ホーム ブログ ページ 39

ローカル開発環境でGoogleアナリティクスを動作確認する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ローカル開発環境でGoogleアナリティクスの動作確認をしたいが、

Googleアナリティクスのプロパティを作成する際、ウェブサイトのURLが必須となっていたので、どう設定すればいいのか色々試してみました。

【環境】

Vagrant + VirtualBox

CentOS 7

Ruby on Rails 4.2

ホストOS windows10

 前提

Googleアカウントを作成済みであること

 操作手順

Google Analyticsのページを開き、

https://www.google.com/intl/ja_jp/analytics/

・アカウントの作成を選択

・アカウント名に適当な名前を入力する

・ウェブサイトの名前に開発中のシステム名等を入力する

この後、ウェブサイトのURL入力が必須なのですが、ドメインは発行していないし、何を入力すればよいのだろう、ということで

①localhost

②VagrantのプライベートIP

③hostsに設定したドメイン名(test.v1.dev)

hosts側の設定:(VagrantのプライベートIP) test.v1.dev

をそれぞれ試してみました。

 検証

①「URL の最後のトップレベル ドメイン名が無効です」エラーとなり、登録不可

②登録OKとなり、下記のようなトラッキングコードが払い出されるので、サイトに埋め込みます。

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXXXXX-Y', 'auto');
  ga('send', 'pageview');

</script>

http://(VagrantのプライベートIP)のサイトにアクセスした後、Googleアナリティクスのレポートを開き、リアルタイム>サマリーを確認します。

アクティブユーザー数が1になっています。データの計測に成功したようです。

③②と同様に登録OKとなるのでトラッキングコードを埋め込んだ後、http://test.v1.devにアクセスします。

レポートを確認すると、アクティブユーザー数が増えています。こちらも成功したようです。

 さらに検証

ウェブサイトのURLって結局何でも良いのでは?と思ったので、

④適当なドメイン名(hoge.com)

も試してみました。

トラッキングコードを埋め込んだ後、http://(VagrantのプライベートIP)にアクセスし、レポートを確認すると、アクティブユーザー数が増えています。

つまり、計測に使用されるのはトラッキングコードのみで、ウェブサイトのURLは結局何でも良いようです。

 追記

Googleのドキュメントにこのような記述がありましたが、設定しなくてもアクセスされていること自体は確認できました。(細かい分析のためには必要なのかもしれません)

ローカルホストでのテスト

https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced?hl=ja#localhost

apxsのオプション

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

OpenSSLをソースから入れ直した時に
Apacheのmod_ssl.soを更新しても
ライブラリ参照先が変わらない事象があったので
オプションなどをメモ。

環境

  • CentOS 5系
  • Apache 2系
  • OpenSSL 1.0.1系

前提

  • yumで入っていたOpenSSL0.9.8系を、
    ソースから入れたOpenSSL1.0.1系にバージョンアップする
  • Apache自体は再コンパイルせず、
    apxsでモジュールのみ再コンパイルする

OpenSSLをソースからインストールしましたが、
Apacheはyumで入れたOpenSSLを参照したままなので
手動で入れた方を参照するよう更新する必要があります。

今回はApache自体はそのままで、モジュールだけapxsでコンパイルし直します。

apxsとは

「APache eXtenSion tool」
Apacheの拡張モジュールをビルドしてインストールするためのツールです。
後から拡張モジュールを組み込んだり、
モジュールだけ再コンパイルして入れ直したりすることができます。
DSOサポートが有効になっている必要があります。

有効になっているかの確認方法↓

# httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c

→core.c、mod_so.cがあればOK

有効になっていない場合はApacheをオプションつけて再コンパイル。
yumの場合はhttpd-develパッケージに入ってます。

mod_ssl更新

今回はmod_sslを再コンパイルしたいので、
mod_ssl.cファイルを探して、apxsコマンドを実行します。

# locate mod_ssl.c

mod_ssl.cのあるディレクトリに移動後、

# apxs -c -i *.c -lssl -lcrypto -ldl -lz

-c オプション: コンパイルする
-i オプション: インストールする
-l オプション: 共有ライブラリを指定

共有ライブラリの参照先を確認。

# ldd mod_ssl.so

libssl.so、libcrypto.soが手動で入れたOpenSSLの場所を参照していればOKなのですが、
結果はyumで入れたOpenSSLが参照されたままです。

その場合は-Lオプションでライブラリパスを指定できます。

※OpenSSLが/opt/opensslにインストールされている場合

# apxs -c -i *.c -lssl -lcrypto -ldl -lz -L/opt/openssl/lib

-L オプション: ライブラリパスを指定

これで手動で入れたOpenSSLの方にリンクしてくれるようになりました。

apxsコマンドのオプション

共通オプション
-n modnameモジュール名を明示的に指定。-i, -gオプションと共にに使用。
-gオプションを指定する場合は必須。
-iオプション指定時にこのオプションの指定がない場合はファイル名から推測される。
クエリオプション
-q設定(構成)情報を取得する。パラメータで取得情報を指定できる。
設定オプション
-S name=value設定を変更する
テンプレート生成オプション
-gモジュールのテンプレート(雛形)を生成する。
-nオプションの指定によってmod_○○.cというソースファイル、Mikefile等が生成される。
DSOコンパイルオプション
-cコンパイルする。
-oオプションがない場合は、通常ファイル名から推測されたmod_○○.soというモジュールが出力される。
-o dsofile作成されるモジュールのファイル名を明示的に指定
-D name=value設定オプションをコンパイル時に直接指定
-I incdirコンパイル時に直接指定したいインクルードディレクトリがあれば指定
-L libdirコンパイル時に直接指定したいライブラリパスがあれば指定
-l libnameコンパイル時に直接指定したいライブラリがあれば指定
-Wc, compiler-flagsコンパイラフラグを指定
-Wl, linker-flagsリンカフラグを指定
DSOのインストールと設定オプション
-iインストールする
-ahttpd.confにLoadModule行を追加して有効化する
-A-aオプション同様、httpd.confにLoadModule行を追加するが
有効化はしない(コメントアウトした状態で追加される)
-eモジュールはインストールせず、httpd.confのみ編集する

-aオプションは、
対象モジュールのLoadModule行が既にある場合に指定すると、
重複してしまい、apachectl configtestは通っても
エラーでApacheが起動しないので注意が必要です。

かなりざっくり略したので、詳細はman apsxで確認を。

Google APIの使い方について

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

GoogleのAPIを使用する方法について

 Projectの作成

Project作成

Google Developers Console(https://code.google.com/apis/console/)で新しいプロジェクトを作成します。

APIの有効化

API一覧から使用するAPIを選択し有効化(statusをEnable)します。

 トークンの取得

メールアドレス登録

Credentials(サイドメニュー) → OAuth consent screen(メイン画面タブ) から、Eメールアドレス(Email address)とProduct name shown to users(適当な文字列を入力)を登録します。

クライアントIDの発行

Credentials(サイドメニュー) → Credentials(メイン画面タブ)の

Create credentialsから「OAuth Client ID」を選択後、アプリケーションの種類を選択(Other)してクライアントIDを発行します。

登録が完了すると、画面にClient ID, Client Secretが表示されます(2016/07現在、Redirect URIsは表示されなくなった: http://localhost)

Authorization Codeを取得

ブラウザ上で以下のURLを入力します。リダイレクトURIとクライアントIDは上記で取得したものを入力します。

https://accounts.google.com/o/oauth2/auth?
scope=https://www.googleapis.com/auth/androidpublisher
&response_type=code
&access_type=offline
&redirect_uri=<redirect uri>
&client_id=<client id>

「<product name shown to usersで入力した文字列>が次の許可をリクエストしています」

と画面に表示されるので、「許可」ボタン(以前は承認するだったので名前は変わる可能性あり)を押下します。

ボタンを押した後リダイレクト先で、ブラウザのアドレスバーを確認します。

code=以降にAuthorization Code が入っています。

http://localhost/?code=<authorizationcode>

アクセストークンの取得

アクセストークンを取得するために、Authorization Code, Client ID, Client Secret, Redirect URI をPOST でリクエストを送ります。

curl -v -X POST 'https://accounts.google.com/o/oauth2/token' 
-d 'grant_type=authorization_code
&code=< Authorization Code >
&client_id=< Client ID >
&client_secret=< Client Secret >
&redirect_uri=< Redirect URI >'

レスポンスとして、アクセストークンとリフレッシュトークンが帰ってきます。

{
"access_token" : " アクセストークン",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "リフレッシュトークン"
}

 サーバ側設定

Gem

google API Client のGemを使用

https://github.com/google/google-api-ruby-client

使い方

require 'google/api_client'

# 初期化
client = Google::APIClient.new(
  auto_refresh_token:  true,
  application_name:    xxx,   # アプリケーション名やバージョン名を
  application_version: xxx    # 指定する場合は初期化時に入力
)

# 認証情報設定
client.authorization.client_id      = <取得したクライアントID>
client.authorization.client_secret  = <取得したクライアントシークレット>
# リフレッシュトークンにより, アクセストークンは都度取得する
client.authorization.refresh_token  = <取得したリフレッシュトークン>

# 使用するAPIとバージョンを指定
api_publisher = client.discovered_api("hogeAPI", "v1.1")

# API呼び出し
client.authorization.fetch_access_token!

response = client.execute(
  api_method: <api のメソッドを指定>,
  # パラメータを渡す場合はhashで指定
  parameters: {
    "xxx" => xxx,
    "yyy" => xxx,
    "zzz" => xxx
  }
)

responseにAPIのレスポンスが格納されます。

実行すると自分の内容を出力するシェルスクリプト

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

bash 上で自分自身の内容を出力するスクリプトの作成です。 cat コマンドの応用が面白いと思ったので紹介します。

 動機

パスワードのヒントやそこそこ頻繁に使う長めのコマンドをメモしておいてターミナル上で簡単に表示できるようにしておきたい。

echo "Qu'est-ce que c'est?"

 cat (基本)

テキストファイルの出力には cat コマンドを使用します。

echo "Je suis japonais." > sample.txt
	cat sample.txt

試しに自分を出力するシェルスクリプト

cat << EOF > sample.sh
	#!/bin/bash
	
	cat \$0
	
	# Nach dem Sinn von Sein soll die Frage gestellt werden.
	EOF
	chmod u+x sample.sh
	./sample.sh

 cat (応用)

# を不要にしたり、短くしたりできないか

例えば shebang に cat を使うとか。

cat << EOF > .1
	#!/bin/cat
	
	Veni, vidi, vici.
	
	γνῶθι σεαυτόν
	
	北 冥 有 魚 其 名 為 鯤
	
	EOF
	chmod u+x .1
	./.1

できた。PATHを追加すればファイル名だけで表示可能。名付けて猫スクリプト

curl でファイルを送る

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

http アクセスを行うコマンドラインツールは telnet, wget, lynx, w3m などあるがリクエスト結果をそのまま標準出力したい場合は curl コマンドが便利かと思っている。ファイルを POST するのも簡単だったので備忘の為、記載する。

 通常の使い方(bash上)

curl http://host/path/file.ext

※ ポストパラメータを渡すときは -F オプションを使う

e.g.
 のようなフォームで送るパラメータ。 
curl -F "param_name=param_value" curl http://host/path/file.ext

 ファイルを送るとき

e.g.
 のようなフォームで送るパラメータ。
curl -F "param_file=@file_path" curl http://host/path/file.ext

簡単でした。@マークをつけてファイルパスを指定するだけ。

 Appendix

get パラメータを送るときの注意

? や & は bash 上で特殊文字として処理されてしまうので URL ごと引用符で囲んでしまいましょう。

curl "http://host/path/file.ext?a=1&b=2&c=3"

よく使うオプション

  • -H ヘッダーを設定する。下記では名前解決できないけれど名前バーチャルホストを使用しているサーバへアクセスするときの確認に便利
  • -b 送信するクッキーファイルを指定
  • -c 受信するキッキーを保存するファイルを指定
  • -A ユーザエージェントの書き換え:iphoneやandroidやその他で出力が異なる場合の確認に便利
  • -v リクエストヘッダやレスポンスヘッダを表示
curl -v -H Host:virtual_host_name http://127.0.0.1/ -b ck0.txt -c ck1.txt -A "oreore_ua"

datetimepickerでの、あり得ない日付の入力制御の覚え書き

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

railsのビューで、フォームを使って日付を入力させたい時、

datetimepickerを使っていました。

datetimepickerはJSでテキストフィールドに付加する事で、カレンダー表示で日付・時間を選択させる事のできる便利なプラグインです。

ただ、テキストエリアに追加するので、ユーザーがテキストフィールドに直接日付を入力する事も出来てしまいます。

それ自体は別に問題ない事ですが、日付じゃないテキストや、あり得ない日付を入力されてしまう場合もあります。

日付じゃないテキストについては、datetimepickerが勝手に判断してテキストフィールドの中を空に置き換えてくれるのですが、

あり得ない日付に関しては、

「2000-04-31」-> 「2000-05-01」に変換してくれる

「2000-05-32」-> 変換してくれない!

となるので、フォームでもらった値を、

モデルインスタンスのDateTime型のカラムに代入しようとするとエラーを吐きます。

@model = Model.new(date: param[:model][:date])
 -> ArgumentError

どうやら31日までは,datetimepicker側で勝手に判断して変換してくれるようですが、

32日を超えると「ありえない日付」となり、変換はしてくれないようです。

これでは困るので、色々と解消しようとした顛末です。

 1. validationで弾けないか?

モデルにvalidateを設置して、フォームを送ったら「不正な値です」などのアラートを表示させたいと思いましたが、

よくよく考えると、validate発火前の、インスタンスへの代入時点でエラーになっているので、ちょっと厳しそうです。

コントローラの方でチェックするのも考えましたが、フォームを使うコントローラ全てにチェックを入れないといけなかったりするので、

あまり良くなさそうです。

 2. JSで弾く(onBlur編)

そもそもそのような入力が出来なければ良い話なので、JSで入力制御を入れる事にしました。

ちなみに、datetimepicker導入部のJSはこんな感じ。

$('.date_text_field').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
});

今回は日付だけ取りたいので、時間までは取らないようにしています。

このままだと入力制御がかかってないので、onBlurのイベントハンドラを使ってみます。

$('.date_text_field').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
});

$('.date_text_field').onBlur = function(){
  if ($(this).val() != '') {
	  var inputDate = new Date($(this).val());
	  if (isNaN(inputDate.getTime())) {
	    $(this).val('');
	  }
  }	
}

「isNaN(inputDate.getTime())」でテキストフィールドに入力された値が日付として正当か判断しています。

これでテキストフィールドに「2000-03-34」のようなおかしい日付を入力して、フォーム送信ボタンを押すと・・・・

テキストフィールドの中身が空になりました!

・・・しかし、onBlurを使っているので、テキストフィールドからフォーカスが外れれば空になってくれるのですが、

テキストフィールドに入力した状態で、エンターキーを押してそのままフォーム送信したりすると、、

フォーカスは外れないので、そのまま値が送られてしまい、やはりArgumentErrorになってしまいました。

 3. JSで弾く(onsubmit編)

ならば、フォーム全体がsubmitされたタイミングで入力判定すれば良いじゃないか!

という訳で、フォーム全体のイベント監視をさせるようにしてみます。

$('.date_text_field').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
});

$('form').on('submit', function(){
  picker();
 });

function picker(){
  $('.date_text_field').each(function(){
    if ($(this).val() != '') {
      var inputDate = new Date($(this).val());
      if (isNaN(inputDate.getTime())) {
        $(this).val('');
      }
    }
  });
}

formタグを監視するようにしてみました。

フォームがsubmitされると、date_text_fieldクラスを探し出し、日付として不正の場合値を空にします。

これで再度日付入力用のテキストフィールドに「2000-03-34」を入力してフォーム送信・・・

-> 送信直前にフォームの内容が空になりました!

 4. JSで弾く(解決編)

上記の方法で良いかと思ったのですが、

一画面に複数formタグがあったときは、そもそもformにJS監視させたくないときは?などの疑問が残ります。

そんな中、とてもスマートな解決法を教えて頂きました。

$('.picker_date').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
}).on('dp.error', function(e) {
  $(e.target).val('');
});

これだけです。formに対してのイベントリスナーもいりません。

dp.errorイベントを拾うことで、入力された値に不整合があると、値を空にすることが出来ます。

フォーム送信時だけでなく、テキストフィールドからフォーカスが移ったときにも評価が走ります。

ということで無事、datetimepickerへの入力制御を入れる事が出来ました!

便利なBootstrapデザイン

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

rickNo40です。
管理画面デザインをデザイナーが作ることはあまりないので、各ブラウザの調整など苦労したりします。
そこで、簡単に綺麗な管理画面が作成できるのがBootstrapです。
少々触る機会があったのでよく使ったデザインを少しだけ紹介下記全てクラス名

「col-md-?」
?部分は1~12の数字になります。
これは、1つのブロックを12分割し指定した分割分の領域を使用します。
入力フォームの幅を調整したり、
1行に幾つか要素を置くときに2,4,2,4で分割したりと便利です。

「text-left,text-center,text-right」
左寄せ・中央寄せ・右寄せですね。
使いたい時に、あぁまたcss設定しなきゃなんてならず、class名指定するだけなので楽です。

「table」
テーブルの基本デザイン
管理画面の大抵の画面がこれを使用して作ればいいです。

「table-striped」
テーブルで1行毎に色を変えてくれます。
縦結合する場合はだめですが、一覧表示するときは良い感じです。

「table-bordered」
テーブルの枠を表示します。
線があると無いとではやっぱり引き締まり具合が違います。
提供する管理画面なんかだったらborderはつけたが方がいいかと自分は思います。

「table-condensed」
テーブルの余白を縮めます
bootstarp基本的に余白多いんですよね。
1画面に収める量を増やしたい場合は、つけたほうがいいです。

「form-group,form-control」
入力フォーム系にはとりあえず付けておけばいいかと

「input-groupで囲んでinput-group-addon」
入力フォームの前や後ろに単位などをつけたりできます。
普通に書くと入力フォームと高さが微妙に違ってたりなんてことがあるので結構便利です。

と、こんな感じでルールが決まっているとそれを設定するだけなのでとても楽です。
Bootstrapでつくったからといって必ず綺麗になるわけでもありませんが、
少し試してみるのもいいかと思います。

AtomをEclipse風にカスタマイズ【パッケージ編】

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

無料のWeb開発向けテキストエディタ「Atom」を、Eclipse風にカスタマイズする方法をご紹介します。

今回はパッケージ編です。

※「設定・使い方編」と「パッケージ編」の2部構成

※注)以下はMacの設定となります。

 キーバインドをEclipse風にする

eclipse-keybindings

このパッケージはその名の通り、AtomのキーバインドをEclipseに近づけてくれます。

私はEclipseでよく以下のショートカットを使用しますが、もちろんこれらもそのまま使えます。

・全文検索:control + H

・ファイル検索:command + shift + R

 ファイルツリーに拡張子毎のアイコンを表示

file-icons

Eclipseだとデフォルトでファイルツリー上のファイル名の横に拡張子毎のアイコンが表示されていて、見栄えがよいです。

これを実現するのがこちらのパッケージ。

 メソッドツリーを表示

symbols-tree-view

サイドバーにメソッドの一覧を表示してくれるパッケージです。

コードが長いクラスを読む際に便利です。

 日本語化

japanese-menu

好みの問題ですが、Eclipse使ってる方はPleiadesで日本語化されている方が多いと思うので、こちらも入れておくとEclipseに一歩近づく(?)

 ツールバー

tool-bar

tool-bar-main

ツールバーが表示されるようにするパッケージです。

tool-barが本体ですが、本体だけだと自分でツールバーの内容を設定しないといけません。

tool-bar-mainを入れるとよく使いそうなツールバーを自動で設定してくれます。

こちらのパッケージもEclipseに近づけることがメインで実用性は低め・・。

また、デフォルトだとツールバーのアイコンが大きすぎるので、パッケージ側の設定で小さくします。

Atom->環境設定->パッケージ->tool-bar->設定(※設定が表示されていない場合はリスト自体をクリックすると表示されます)->Settings->

 icon Size:16px

 ダブルクリックした単語をハイライト

highlight-selected

Eclipseでも地味に便利なこの機能。単語をダブルクリックすると同じ名前の単語をハイライト表示してくれます。

ただ、背景が白のテーマにしている場合、どこがハイライトされているか分かり辛いため、こちらも設定を変更します。

Atom->環境設定->パッケージ->tool-bar->設定->Settings->

 ■Highlight Background

 ■Light Theme

設定・使い方編へ

http://doruby.kbmj.com/oneafter999_on_rails/20160516/Atom_Eclipse_

Docker を試してみる(2.5)〜Sentryを試す

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

今回はちょっと脱線して SentryというサービスをDocker上で実行してみます。

なお、Sentryはアプリケーションのログを収集して見やすくしてくれるサービスです。

https://getsentry.com/welcome/

SaaS型とオンプレ型が無償で提供されています。

sentry のオフィシャルイメージが用意されていますので、そちらを使います。

https://hub.docker.com/_/sentry/

基本的にこの手順に従っていくだけです。

事前準備: redisとPostgreSQLを起動

これもコンテナで起動します。

$ docker run -d --name sentry-redis redis
$ docker run -d --name sentry-postgres -e POSTGRES_PASSWORD=sentry -e POSTGRES_USER=sentry postgres

シークレットキーの作成

シークレットキーを出力します。

コンテナの起動時に使いますので覚えておいてください。

$ docker run --rm sentry generate-secret-key
hogehogesecretkey

データベースの作成

$ docker run -it --rm -e SENTRY_SECRET_KEY='hogehogesecretkey' --link sentry-postgres:postgres --link sentry-redis:redis sentry upgrade

途中で「ユーザを作るか?」ときかれますので、作っておきましょ。

linkオプションについて

docker run コマンドで –link というオプションが使われています。

これはコンテナ同士を通信させる簡単な方法です。

リンクしたコンテナの情報(IPなど)を共有して参照できるようにします。 –link コンテナ名(:エイリアス) で指定します。

sentryのコンテナ中でエイリアス(postresやredis)を使って参照(REDIS_PORT_6379_TCP_ADDRなど) しているので、上記の通りに指定しないと動きません。

サーバの起動

$ docker run -d -p 9000:9000 --name my-sentry -e SENTRY_SECRET_KEY='hogehogesecretkey' --link sentry-redis:redis --link sentry-postgres:postgres sentry

ホストの9000版アドレスにポートフォワードしてるので、http://localhost:9000 や http://192.168.33.11:9000 のようにしてブラウザから確認できます。

ワーカーの起動

デフォルトの設定で、workerのコンテナも必要なようなので起動しておきます。

$ docker run -d –name sentry-celery-beat -e SENTRY_SECRET_KEY=’hogehogesecretkey’ –link sentry-postgres:postgres –link sentry-redis:redis sentry celery beat $ docker run -d –name sentry-celery1 -e SENTRY_SECRET_KEY=’hogehogesecretkey’ –link sentry-postgres:postgres –link sentry-redis:redis sentry celery worker

Docker を試してみる(2)

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Docker を試してみる(1) の続きです。

超基本ですが重要な run & exec コマンドの説明です。

 runコマンド

dockerの中で一番大事なコマンドです。コンテナを起動しコマンドを実行します。

オプションが非常にたくさんありますがリソースの設定が多いので覚えるのは少しだけ。

–nameコンテナの名前を指定する
-it標準入力を開き仮想端末を割り当てる。シェルを使うときに使う
-dバックグラウンドでコンテナを実行する。サーバとして使うときなど
-e環境変数を指定する
-pポートフォワーディングする。ホスト->コンテナ
–rm実行が終わったら コンテナを削除する
-vボリュームを割り当てる。ホストのディスクをコンテナで使いたいときに使う

実行例)

コンテナ上でシェルを実行する

対話型シェルを起動します。# のプロンプトはシェルに接続した状態です。

exitでコンテナと切断し、コンテナは終了します。終了後コンテナは削除されます。

$ docker run -it --rm ubuntu bash
root@92e455bcb613:/# 

なお、ubuntuコンテナは、コマンド省略時はbashを起動するようになっているので、

bashをつけなくても結果は同じです。

$ docker run -it --rm ubuntu
root@92e455bcb613:/# 

コマンドのみ実行する

プロセスを表示させてみます。psコマンドが実行されコンテナは終了します。終了後コンテナは削除されます。

$ docker run --rm ubuntu ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  25968  1236 ?        Rs   09:27   0:00 ps aux

サーバとして実行する

memcachedサーバとして起動します。DockerHubのmemcachedイメージを使います。

次のコマンドでは memcached というコンテナ名でサーバを起動します。

16進数のIDを出力するのみでコマンドは終了します。

$ docker run -d --name memcached memcached
b40a0f915d7ade1b6ad91c7cc9b2257da1013c21ff61821cc1a59d597b9f734b

docker ps コマンドで実行状況を確認すると実行されていることが確認できます。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
a40a0f915d7a        memcached           "/entrypoint.sh memca"   About a minute ago   Up 59 seconds       11211/tcp           memcached

コンテナを停止するには stop コマンドを使います。さらにコンテナを削除する場合は rmコマンドを使います。

$ docker stop memcached
$ docker rm memcached 

ポートフォワーディングする

ホストのアプリからmemcachedを使いたい、別のホストから接続したいときはポートフォワーディングを行います。

次のコマンドは ホストの11212ポートからコンテナの11211(memcachedのポート)に転送します。

$ docker run -d --name memcached -p 11212:11211 memcached
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
ec0da0dc6aba        memcached           "/entrypoint.sh memca"   5 seconds ago       Up 4 seconds        0.0.0.0:11212->11211/tcp   memcached

上記の出力の、

0.0.0.0:11212->11211/tcp 

任意の接続元からホストの11212ポートへのアクセスを許可し、コンテナの11211ポートへの転送を許可します。

ホストから memcached に接続してみます。

$ telnet localhost 11212
set foo 0 60 3
bar
STORED
get foo
VALUE foo 0 3
bar
END

 execコマンド

runコマンドと同様にコンテナ上でコマンドを実行しますが、

こちらは起動中のコンテナに対してのみ実行可能です。

$ docker exec memcached ps axu
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
memcache     1  0.0  0.2 313740  2228 ?        Ssl  09:43   0:00 memcached
memcache    14  0.0  0.1  17492  1136 ?        Rs+  09:54   0:00 ps axu

migrationファイルの記法メモ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Ruby on Rails でDBのテーブル作成・カラム編集などに使う

migrationファイル。ファイルを作っておけば「rake db:migrate」 のコマンドで色々な対応が出来ますが、

それぞれ書き方があり、今までにすこし引っかかったものを中心にまとめてみました。

 change と up/down

changeとup/downはどちらもmigration実行時・ロールバック時の処理を記述するメソッドです。

changeの場合

class AddNameToPlayers < ActiveRecord::Migration
  def change
    add_column :players, :name, :string
  end
end  

up/downの場合

class AddNameToPlayers < ActiveRecord::Migration
  def up
    add_column :players, :name, :string
  end

  def down
    remove_column :players, :name
  end
end  

up/downはそれぞれ実行時・ロールバック時の操作をかく必要がありますが、

changeは実行時だけの操作を書くと、ロールバック時に処理を反転させて実施してくれます。とっても便利です。

なので、全部changeで書いていた所、ある時エラーになりました。

class RemoveNameToPlayers < ActiveRecord::Migration
  def change
    remove_column :players, :name    <- ロールバックできない
  end
end  

カラムのremove処理などは、changeだけだと、カラムの型情報等が含まれないため、反転出来ないのが原因でした。

removeのmigrationの時はup/downを使うようにしましょう。

 定型外の型

マイグレーションで使えるデータ型には以下のようなものが用意されています。

integer
float
string
text
date
time
boolean
...  

ただある時、integer型のカラムをBIGINT型に変更したい、となったとき、

bigintはそのままmigrationファイルに記述してもダメでした。

  def change
  	change_column :bank, :money, "BIGINT UNSIGNED"
  end 

 カラム位置指定

普通にmigrationファイルでカラムを増やすと、どんどん最後尾にカラムが足されて行きます。

その際、「このカラムは、カラムAとカラムBの間に入れたい!」となった時。

afterを使いました。

  def change
    add_column :test_table, :insert_column, :string, after: "column_a"
  end

このようなmigrationファイルにすると、column_aの後にinsert_columnが追加されます。

おまけ コメント

DBが増えてくると、このカラムは何のカラムだったか、と分からなくなってきます。

migrationファイルから、コメントを付けておく事が出来ます。

  def change
    add_column :test_table, :encrypted_password, :string, comment:"パスワード"
    add_column :test_table, :name, :string, comment:"ログインアカウントネーム"
  end

このようなmigrationファイルを作り、DB構造を見てみると、

各カラムにコメントが入ります。

MySQL DATETIME型のミリ秒の扱いについて

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

MySQL DATETIME型のミリ秒の扱いについて

MySQLのDATETIME型のカラムに対して、ミリ秒付きデータを書き込む際の動作について、

バージョンによって挙動が異なるので注意が必要です。

MySQL 5.5 までは、強制的に切り捨てされて格納、MySQL 5.6 以降は四捨五入されて格納されるという動作になっています。

実行例

 [MySQL 5.5]

テーブル

mysql> show columns from hoges;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| data  | varchar(255) | YES  |     | NULL    |                |
| time  | datetime     | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+

書き込むデータ

mysql> SET @time1 = "2016-04-28 12:00:00.100";
mysql> SET @time2 = "2016-04-28 12:00:00.499";
mysql> SET @time3 = "2016-04-28 12:00:00.500";

mysql> SELECT @time1, @time2, @time3;
+-------------------------+-------------------------+-------------------------+
| @time1                  | @time2                  | @time3                  |
+-------------------------+-------------------------+-------------------------+
| 2016-04-28 12:00:00.100 | 2016-04-28 12:00:00.499 | 2016-04-28 12:00:00.500 |
+-------------------------+-------------------------+-------------------------+
1 row in set (0.00 sec)

データ格納結果

mysql> INSERT INTO hoges (data, time) VALUES (@time1, @time1);
mysql> INSERT INTO hoges (data, time) VALUES (@time2, @time2);
mysql> INSERT INTO hoges (data, time) VALUES (@time3, @time3);

mysql> select * from hoges;
+----+-------------------------+---------------------+
| id | data                    | time                |
+----+-------------------------+---------------------+
|  3 | 2016-04-28 12:00:00.100 | 2016-04-28 12:00:00 |
|  4 | 2016-04-28 12:00:00.499 | 2016-04-28 12:00:00 |
|  5 | 2016-04-28 12:00:00.500 | 2016-04-28 12:00:00 |
+----+-------------------------+---------------------+

 [MySQL 5.7]

テーブル

mysql> show columns from hoge;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | MUL | NULL    | auto_increment |
| data  | varchar(255) | YES  |     | NULL    |                |
| time  | datetime     | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

書き込むデータ

mysql> SET @time1 = "2016-04-28 12:00:00.100";
mysql> SET @time2 = "2016-04-28 12:00:00.499";
mysql> SET @time3 = "2016-04-28 12:00:00.500";

mysql> SELECT @time1, @time2, @time3;
+-------------------------+-------------------------+-------------------------+
| @time1                  | @time2                  | @time3                  |
+-------------------------+-------------------------+-------------------------+
| 2016-04-28 12:00:00.100 | 2016-04-28 12:00:00.499 | 2016-04-28 12:00:00.500 |
+-------------------------+-------------------------+-------------------------+
1 row in set (0.00 sec)

データ格納結果

mysql> INSERT INTO hoge (data, time) VALUES (@time1, @time1);
mysql> INSERT INTO hoge (data, time) VALUES (@time2, @time2);
mysql> INSERT INTO hoge (data, time) VALUES (@time3, @time3);

mysql> select * from hoge;
+----+-------------------------+---------------------+
| id | data                    | time                |
+----+-------------------------+---------------------+
|  1 | 2016-04-28 12:00:00.100 | 2016-04-28 12:00:00 |
|  2 | 2016-04-28 12:00:00.499 | 2016-04-28 12:00:00 |
|  3 | 2016-04-28 12:00:00.500 | 2016-04-28 12:00:01 |
+----+-------------------------+---------------------+
3 rows in set (0.00 sec)

上記のように、同じデータを書き込んだ場合でも、結果が異なったものになっている。

 おまけ

Railsでの動作について

RailsのActiveRecord経由で記録した場合、

Rails ~4.1だと、ミリ秒は切り捨てされて、

Rails 4.2~ だと、ミリ秒も含めてSQL文が作られる。

VirtualBox のHDDサイズ変更

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

VirtualBox のHDDサイズを変更する方法を備忘の為に記載

 環境

ホストOS: Windows 7

ゲストOS: CentOS 6

 手順

仮想マシンが起動している場合はシャットダウンする。
管理者としてコマンドプロンプトを開く。
対象のHDDのUUIDを確認しておく。
cd "c:\Program Files\Oracle\VirtualBox"
VBoxManage -nologo list hdds
サイズを変更する
VBoxManage modifyhd (UUID) --resize (サイズ(MB))

以下は50GBに変更する場合の例

VBoxManage modifyhd f7689c77-bccd-44fa-9304-3f1637aa00c2 --resize 51200

tortoiseSVNで、あるリビジョンとあるリビジョンの差分ファイルをエクスポートする

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

たまごです。

SVN上のあるリビジョンとあるリビジョンの差分ファイルを抽出したい時って、たまにありますよね。その際、自分がよく使う方法を解説したいと思います。

 tortoiseSVNでリビジョン間の差分ファイルを抽出する方法

使うのは、tortoiseSVNです。

  1. 対象ディレクトリで、show logする
  2. 任意のリビジョンを二つ選択し、Compare revisionsする
  3. ファイルを全選択し、右クリックでExport selections to…する

これでOKです。

削除ファイルがいらない場合は、手順の3で全選択せず、Actionでソートしたうえで、Deleted以外を選択するようにしましょう。

 上記方法で失敗する場合

SVNが貧弱だと、3のExport selections to…した際にエラーが出たりします。

そういう時は、仕方ないので、ファイルを選択した状態でCtr+cします。

これで表示されているパスがコピーされるので、後はコマンドプロンプト等使って、地道にコピーします。

(パスは表示されているとおりにコピーされるので、長いパスが省略されないように、なるべくFileカラムの横幅を広くして、コピーしてあげるとよいかんじです)

【JMeter】HTTPリクエストでPATCHメソッドを使用する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Apache JMeterでPATCHメソッドを使用する方法

 概要

Apache JMeterでPATCHメソッドを使用したときに、色々うまくいかなかったので、試したことを記録しておきます。

JMeterの基本的な使い方については割愛します。

【Version】

Apache JMeter Version 2.13

 はじめに

JMeterでは、HTTPプロキシサーバを使用すると、ブラウザの操作を記録することができます。

その際、PATCHメソッドを使用している画面の操作で、エラーが発生しました。

記録されたJMeterのHTTPリクエストサンプラーを見てみると、メソッドがPATCHになっており、Parametersにリクエストで送るパラメータが表示されています。

 解析

一見問題なさそうですが、このHTTPリクエストを実行して、リスナー -> 結果をツリーで表示の「リクエスト」タブを見てみると、

PATCH data:

Content-Length: 0

となっており、リクエストボディが送信されていないようです。

ちなみに、メソッドをPOSTに変更して実行すると、リクエストで送るパラメータに設定した値が送信されていることが確認できます。

 解決方法

Parametersタブの隣にあるBody Dataタブを押すと、Warningメッセージが出ます。ここで、リクエストで送るパラメータをすべて削除するとBody Dataタブに切り替えることができます。

ここに、リクエストボディの値をそのまま貼り付けます。

(筆者はChromeの検証ツールからForm Dataをコピーしました。エンコードされた値を貼り付ける必要があるので、view sourceからコピー。)

 実行

再度実行してみます。

リスナー -> 結果をツリーで表示の「リクエスト」タブを見てみると、

PATCH data:

XXXXXXX%5AAAAAAAAAAAAAA%5D=true

Content-Length: 31

リクエストボディが正常に送信できました。

結果も正常終了になっています。

 余談

本題とは直接関係ありませんが、このとき動かしていたWebアプリはRailsアプリで、Ajaxでフォームの内容を送信していたので、「X-CSRF-Token」をリクエストヘッダーに設定する必要もありました。

以上です。

PUTメソッドも同様の動きをするようなので、同じ方法で解決できます。

CVE-2016-0800のOpenSSL脆弱性「DROWN」について、SSLv2が無効かどうかすぐに確認する方法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。アピリッツの本多です。

2016年03月01日にOpenSSLの新たな脆弱性が発表されました。

SSLv2が有効な環境ではTLSセッションの暗号化が破られる攻撃を受ける可能性があるというものです。

詳しくは以下の資料を参照ください。

DROWN: Breaking TLS using SSLv2

https://drownattack.com/drown-attack-paper.pdf

その他重要度の低い修正も適用されているため、opensslの更新は行ったほうが良いと思いますが、取り急ぎ、SSLv2が現在有効なのかを確かめたいと思います。

今回の脆弱性の情報と合わせて、各ドメインの脆弱性をチェックするためのサイトも公開されました。

DROWN Attack

しかしながら、サブドメインごとにシステム(ないしSSL証明書)が異なる場合にチェックが上手く出来なかったため、centos上でコマンドを叩いて確認を取りたいと思います。

コンソール上で以下のコマンドを入力します

$ openssl s_client -connect (ドメイン名):443 -quiet # プロトコルを指定せずに接続確認

$ openssl s_client -ssl2 -connect (ドメイン名):443 -quiet # SSLv2で接続確認

試しに、グーグルにアクセスしてみたところ、以下の様な応答が返って来ました。

$ openssl s_client -connect www.google.com:443 -quiet

depth=3 C = US, O = Equifax, OU = Equifax Secure Certificate Authority

verify return:1

depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA

verify return:1

depth=1 C = US, O = Google Inc, CN = Google Internet Authority G2

verify return:1

depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = www.google.com

verify return:1

$ openssl s_client -ssl2 -connect www.google.com:443 -quiet

139632633231176:error:1407F0E5:SSL routines:SSL2_WRITE:ssl handshake failure:s2_pkt.c:429:

SSLv2を指定した場合、接続エラーが返って来ました。

このように、グーグルでは「httpsで通信できるが、SSLv2は無効にしている」という事がわかります。

このコマンドはサブドメイン別にサーバーが分かれている場合でも確認が取れますので、もし同じ状況で上記サイトでの確認が取れない場合、今回紹介したコマンドを使って確認してみてはいかがでしょうか。

そしてSSLv2が有効になっている場合は各自対応しましょう。

もちろん、SSLv2が無効になっている場合でもopensslの更新は行ったほうが良いと思います。

Amazon RDS for MySQL でフルアクセス権限を持つユーザーを作成する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

データベースにアクセスするユーザーを作成する場合、本来であればアクセス可能なデータベースや権限を細かく設定すべきですが、稀にフルアクセス権限を持つユーザーを作成したい場合もあると思います。

MySQLであれば

GRANT ALL ON *.* TO user@'localhost' IDENTIFIED BY 'パスワード';

とすることでフルアクセス可能なユーザーを作成することができますが、同コマンドをAmazon RDS for MySQLで実行すると

ERROR 1045 (28000): Access denied for user 'root_account'@'%' (using password: YES)

というような権限エラーが発生します。

このような場合は

GRANT ALL ON `%`.* TO user@'localhost' IDENTIFIED BY 'パスワード';

というように、 `%` で対象となるデータベースを指定することでフルアクセス可能なユーザーを作成することができます。

CVE-2015-7547のglibcライブラリの脆弱性について、CentOS系での修正済みバージョンの確認と適用方法について

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。アピリッツの本多です。

本日2016年02月17日、glibcライブラリの脆弱性の記事が掲載されました。

脆弱性の詳細につきましては以下の記事をご確認頂くとして、本ページでは修正後のglibcのバージョンと、適用方法に情報を絞ってご紹介したいと思います。

Google Online Security Blog: CVE-2015-7547: glibc getaddrinfo stack-based buffer overflow

https://googleonlinesecurity.blogspot.jp/2016/02/cve-2015-7547-glibc-getaddrinfo-stack.html

各CentOSでの修正後のglibcのバージョン情報

OS対応の有無修正後のバージョン
CentOS5系不要
CentOS6系必要2.12-1.166.el6_7.7
CentOS7系必要2.17-106.el7_2.4

情報元:

CVE-2015-7547 – Red Hat Customer Portal

Red Hat Customer Portal

Red Hat Customer Portal

glibcのアップデート手順

rootユーザーにて以下のコマンドを実行します。

# yum clean all

# yum update glibc

アップデート完了後はシステムの再起動を行ってください。

CentOS7系では、以下のコマンドを叩く事で、再起動せずとも更新されたglibcを適用する事が出来るそうです。

# systemctl daemon-reexec

情報元:

Critical glibc buffer overflow vulnerability in getaddrinfo() on Linux (CVE-2015-7547 & CVE-2015-5229)

おまけですが、Amazon Linuxの場合のglibcの情報も記載しておきます。

修正後のバージョン
2.17-106.166.amzn1

更新方法は上のやり方と同じですので、早急の対応を行いましょう。

情報元:

https://alas.aws.amazon.com/ALAS-2016-653.html (SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: sslv3 alert handshake failure)

rubyistのためのscala (3) クラスとオブジェクト指向

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。


Rubyで書くあれはScalaだとどう書くの?シリーズ。 今回はクラスとオブジェクト指向について。

クラス

クラスの宣言と継承

Ruby

class Foo < Bar
end

Scala

class Foo extends Bar {
}

コンストラクタ

Rubyではinitializeという名前のメソッドを定義する。

class Foo
  def def initialize(bar)
    # new した時点でここが実行される
  end
end

Scalaにはコンストラクタを複数定義できるが、ここではデフォルトのコンストラクタについて説明する。

デフォルトのコンストラクタはクラス定義のブラケット内にそのまま記述できる。
引数はクラス名の後ろのカッコ内に書く。

class Foo(bar: Int) {
  // new した時点でここが実行される
}

モジュール

Ruby

module Foo
  def bar
  end
end

Scala

trait Foo {
  def bar: Unit = {
  }
}

barというメソッドを持つtrait Fooを定義することができる。

Mixin

Scalaではtraitを継承することでmixinを行う。

Ruby

module Bar
end

class Foo
  include Bar
end

Scala

trait Bar {
}

class Foo extends Bar {
}

ひとつのクラスが複数のtraitをmixinする場合、二つ目以降は with というキーワードを使う。

Scala

class Foo extends Bar with Baz with Hoge {
}

TODO: prependusingについても調べて書く

名前空間

Rubyではモジュールを名前空間として使うことができる。

Ruby

module Foo
  module Bar
    class Baz
    end
  end
end

baz = Foo::Bar::Baz.new

Scalaではパッケージのほか、シングルトンオブジェクトも名前空間として使うことができる。

Scala

package foo
object Bar {
  class Baz {
  }
}

val baz = new foo.Bar.Baz()

TODO: import について書く

メソッド

キーワードは同じ def
引数と返り値の型を指定する。

Ruby

class Foo
  def bar(a, b)
    a + b
  end
end

Scala

class Foo {
  def bar(a: Int, b: Int): Int = {
    a + b
  }
}

プロパティとアクセサ

デフォルトのゲッター、セッター

Ruby

class Foo
  attr_accessor :bar, :baz
  def initialize(bar, baz)
    @bar = bar
    @baz = baz
  end
end

foo = Foo.new(1, "abc")
foo.bar  # => 1
foo.baz  # => "abc"

Scala

class Foo(var bar: Int, var baz: String) {
}

val foo = new Foo(1, "abc")
foo.bar  // => 1
foo.baz  // => "abc"

セッターの実装

Ruby

class Foo
  attr_reader :bar
  def bar=(i)
    @bar = i
  end
end

foo = Foo.new
foo.bar = 1
foo.bar  # => 1

Scala

class Foo {
  private var _bar: Int = _
  def bar = _bar
  def bar_=(i: Int): Unit = this._bar = i
}

val foo = new Foo()
foo.bar = 1
foo.bar  // => 1

Scalaのセッターメソッドは def 変数名_=(引数): Unit = ??? という形で定義する。

演算子メソッド

Rubyでメソッドとして再定義可能な演算子

|  ^  &  <=>  ==  ===  =~  >   >=  <   <=   <<  >>
 +  -  *  /    %   **   ~   +@  -@  []  []=  ` ! != !~

Scalaで再定義できない予約語、キーワード
FAQ How do I find what some symbol means or does?より引用)
(これ以外の記号、英数字は使えるらしい)

// Keywords
<-  // Used on for-comprehensions, to separate pattern from generator
=>  // Used for function types, function literals and import renaming
// Reserved
( )        // Delimit expressions and parameters
[ ]        // Delimit type parameters
{ }        // Delimit blocks
.          // Method call and path separator
// /* */   // Comments
#          // Used in type notations
:          // Type ascription or context bounds
<: >: <%   // Upper, lower and view bounds
" """      // Strings
'          // Indicate symbols and characters
@          // Annotations and variable binding on pattern matching
`          // Denote constant or enable arbitrary identifiers
,          // Parameter separator
;          // Statement separator
_*         // vararg expansion
_          // Many different meanings

どちらも記号を名前としたメソッドを定義することで演算子を定義できる。

class Foo
  def +(other)
    "add method"
  end
end

foo1 = Foo.new
foo2 = Foo.new
foo1 + foo2  # "add method"
class Foo {
  def +(other: Foo): String = "add method"
}

val foo1 = new Foo
val foo2 = new Foo
foo1 + foo2  // "add method"

引数のデフォルト値

Ruby

class Foo
  def bar(baz = 1)
    baz
  end
end

foo = Foo.new
foo.bar()  # => 1
foo.bar(2)  # => 2

Scala

class Foo {
  def bar(baz: Int = 1): Int = {
    baz
  }
}

val foo = new Foo()
foo.bar()  // => 1
foo.bar(2)  // => 2

可変長引数

Rubyでは定義するときも呼び出すときも * という記号をまえにつける。

class Foo
  def bar(baz, *hoge)
    # 2つめ以降の引数はhogeに配列として入る
  end
end

foo = Foo.new
baz = 1
hoge = ["foo", "bar"]
foo.bar(baz, *hoge)

Scalaでは定義するときは *をうしろにつけ、呼び出すときは :_* という記号をうしろにつける。

class Foo {
  def bar(baz: Int, bar: String*): Unit = {
    // 2つめ以降の引数は bar にSeqとして入る
  }
}

val foo = new Foo
val baz = 1
val hoge = Seq("foo", "bar")
foo.bar(baz, hoge:_*)

※読みやすいレイアウトでまとめましたサイトを作りましたので、こちらもご参照ください。
http://kkismd.github.io/rb2scala/

rubyistのためのscala (1) 値と式

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。


Rubyで書くあれはScalaだとどう書くの?シリーズ。 今回は値や式についてまとめてみました。

数値

種類RubyScala備考
整数123123 2147483647L整数は32bit(Int),64bit(Long)の2種類がある
実数123.45123.45 123. 123.45d 123.45f実数はDoubleとFloat
浮動小数1.2e-31.2e-3
16進整数0xffff0xffff
8進数0377ゼロから始める8進数表記はScala 2.11から非推奨
2進整数0b10112進数のリテラルなし
桁区切り文字1_000_000_000桁区切り文字はなし

文字列

種類RubyScala備考
ダブルクォート"this is a string expression\n""this is a string expression\n"
シングルクォート'this is a string expression''a'シングルクォートはChar型を表すため文字列には使えない
シンボル:aaa'aaa
ヒアドキュメント<"""foo bar baz """改行を含む文字列はダブルクォートを3つ重ねる(Raw String)。バックスラッシュによるエスケープが効かない。
式埋め込み"foo #{1 + 2} baz"s"foo ${1 + 2} baz"ダブルクォートの前に小文字のs (interpolator) を置く
フォーマットsprintf("foo %d baz", 123) "foo %d baz" % [123]"foo %d baz".format(123)

変数

種類RubyScala備考
変数a = 123var a = 123
定数A = 123val a = 123変数をvalで宣言すると再代入がコンパイルエラーになる(Rubyの定数より厳格)

演算子

ScalaもRubyと同じように演算子の一部がメソッドのシンタックスシュガーとして定義されている。

1 + 2 は 1.+(2) のシンタックスシュガー

種類RubyScala備考
代入foo = barfoo = bar再代入が必要な時はvarで宣言する
配列参照array[1]array(1)カッコによる配列参照はメソッド呼び出し .apply(n) のシンタックスシュガー
属性参照foo.barfoo.bar引数なしのメソッドをカッコ省略できる
自己代入foo += 1foo += 1再代入があるのでvar変数として宣言が必要
多重代入foo, bar, baz = 1, 2, 3 foo, bar, baz = [1, 2, 3](foo, bar, baz) = (1, 2, 3) Array(foo, bar, baz) = Array(1, 2, 3)多重代入はパターンマッチのシンタックスシュガー
範囲式1 .. 201 to 20 1.to(20)整数クラスの .to() メソッドを使う。引数が1つしかないメソッドはドットやカッコを省略できる。
アンド条件foo && bar foo and barfoo && bar演算子 and は使えない
オア条件foo || bar foo or barfoo || bar演算子 or は使えない
否定!foo not foo!foo演算子notは使えない
3項演算子obj == 1 ? foo : barif (obj == 1) foo else bar3項演算子がないのでif式を使う

※読みやすいレイアウトでまとめましたサイトを作りましたので、こちらもご参照ください。
http://kkismd.github.io/rb2scala/

rubyistのためのscala (2) 制御構造

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。


Rubyで書くあれはScalaだとどう書くの?シリーズ。 今回は制御構造です。

if-then-else

Ruby

if a = b
  "equal!"
else
  "not equal!"
end

Scala

if (a == b) {
  "equal!"
}
else {
  "not equal!"
}

Scalaでもifは式であり、値を返すことができる。 後置式はない。

unless

Ruby

unless foo?
  "not foo"
else
  "foo"
end

Scala

if (!isFoo)
  "not foo"
else
  "foo"

Scalaにunlessはない。

case

Ruby

case hoge
when 1
  "one"
when 2, 3
  "two or three"
end

Scala

hoge match {
  case 1 =>
    "foo"
  case 2|3 =>
    "two or three"
}

Rubyのcase式もScalaのmatch式もどちらも強力だがここでは最も基本的な形を挙げている。

繰り返し

whileループ

Ruby

while true
  puts("Hello")
end

Scala

while (true) {
  println("Hello")
}

untilループ

Ruby

until f.eof?
  print f.gets
end

Scala

while (!f.isEof) {
  println(f.getLine)
}

untilはない。

forループ

Ruby

for i in [1,2,3]
  print i * 2, "\n"
end

Scala

for (i <- Seq(1,2,3)) {
  println(i * 2)
}

Scalaのfor式はもっと多機能だがここでは基本的な形を挙げている。

break

Ruby

i = 0
while true
  puts i
  i += 1
  if i > 10
    break
  end
end

Scala

import scala.util.control.Breaks
val breaks = new Breaks
var i = 0
breaks.breakable {
 while (true) {
   println(i)
   i += 1
   if (i > 10) breaks.break()
 }
}

ループのブレイクが構文として用意されていないので、標準ライブラリの Breaks を使う必要がある。

next, redo, retry

Ruby

lines.each do |line|
  next if line.blank?
  puts line
end

Scala

lines.foreach { line =>
  if (!line.isEmpty) {
    println(line)
  }
}

next, redo, retryなどの構文はないのでifなどを使って実装する必要がある。

例外処理

例外の送出

Ruby

raise StandardError.new("例外が起きました")

Scala

throw new RuntimeException("例外が起きました")

例外の捕捉

Ruby

begin
  do_something
rescue ZeroDivisionError => e
  recover(e)
ensure
  must_to_do
end

Scala

try {
  doSomething
}
catch {
  case e: ArithmeticException =>
    recover(e)
}
finally {
  mustToDo
}

return

Ruby

return 1

Scala

return 1

returnはほぼ同じ。 関数やメソッド、ブロックの最後のretrunを省略すると、Rubyと同じように最後に評価された値を返す。

※読みやすいレイアウトでまとめましたサイトを作りましたので、こちらもご参照ください。
http://kkismd.github.io/rb2scala/

最近人気な記事