Ruby+Rails を始めるのにこの辺をおさえておくといいのでは。 というのを書いていきます。
Ruby
Rails
rbenv+ruby-build でインストールがおすすめ
$ irb
とすると REPL が開くので、試してみるのが早いはず。
配列
array = [ 'this', 'is', 'array', 'object' ]
p array #=> ["this", "is", "array", "object"]
puts array[0] #=> this
array[4] = '!'
p array #=> ["this", "is", "array", "object", "!"]
Ruby の配列は tuple のようにいろいろな型の要素を持つことができます。
[ 'string', 10, :symbol, ['array in array'], { hash: :in_array } ]
ハッシュ
hash = { 'this' => 'is', hash: 'object' }
p hash #=> {"this"=>"is", :hash=>"object"}
puts hash['this'] #=> is
puts hash[:hash] #=> object
hash['!'] = '?'
p hash #=> {"this"=>"is", :hash=>"object", "!"=>"?"}
ハッシュのキーをシンボルにする場合は、以下のような書き方ができ、
call_method(with: params)
これは
call_method({ :with => params })
と等価です (ハッシュのキーがシンボルの場合のハッシュリテラルの記法と、最後のパラメータがハッシュの場合は {} のリテラルの表記を省略可能なことを利用した書き方)。
Ruby でプログラミングする最初の一歩は Array クラスと Hash クラスのメソッドを理解すること。
- http://docs.ruby-lang.org/ja/2.1.0/class/Array.html
- http://docs.ruby-lang.org/ja/2.1.0/class/Hash.html
Array や Hash は Enumerable を mix-in (実装継承) しているため、Enumerable module のメソッドを呼び出すこともできます。 慣れてきたら、Enumerable を使いこなせるようにリファレンスマニュアルを眺めてみましょう。
emails = User.where('age > ?', 20).reject {|user| user.name == 'sunaot' }.map {|user| user.email }
ハッシュや Array に対して期待する操作については大体メソッドが用意されていると思って間違いないと思います。 まずはリファレンスマニュアルを眺めてやりたいことを実現できる抽象化されたメソッドがないか探してみましょう。 とくにイテレータは非常に強力にサポートされており、上記の reject のようにブロックをわたしてやることで reject 条件をクロージャでカスタマイズするような柔軟な呼出しが可能です。
3 / 2 #=> 1
3.0 / 2 #=> 1.5
3 / 2.0 #=> 1.5
任意の位置に桁区切りが入れられます。数値型の中の _ は見た目以上の意味は持ちません。
3 + 1_000 #=> 1003
文字列リテラル
'fixed string'
text = 'quote'
"double #{ text } string" #=> double quote string
`echo executable`
%Q| double quote string |
%| double quote string |
%q| single quote string |
puts <<HEREDOC
hello, world!
HEREDOC
文字列操作も Ruby の得意分野です。やりたいことは大体メソッドがあるはずなので探してみてください。
正規表現リテラル
/this is regexp/
Ruby の M17N
Ruby 2.0 以降、未指定の場合の script encoding がデフォルト UTF-8 になったため、マジックコメント (shebang の下の conding: utf-8) は不要となりました。マジックコメントは指定せず、スクリプトは UTF-8 で保存してください。
UTF-8 ではないエンコーディングを扱う場合、プログラム内に取込む入力の境界と出力の境界で適切に encode/decode します。
force_encoding は「実態はわからないが、そのようにみなす」というものなので、お世話にならないようなつくりのプログラムを書き、出会うことのないようにしましょう。IO から入力されるエンコーディングがわかっているなら、その入力ストリームにたいしてエンコーディング情報を指定することができます。くわしくは、IO のリファレンスマニュアルを読む。
シンボルリテラル
:this_is_symbol
シンボルはインスタンスが一意に特定できる文字列オブジェクトです。通常、Ruby の文字列は同じ値の文字列でも個別にインスタンスが違います。
'hello'.object_id #=> 70365954987520
'hello'.object_id #=> 70365954972240
'hello' == 'hello' #=> true 同値性の検査 String#==
'hello' === 'hello' #=> true 同値性の検査 String#===
'hello'.eql?('hello') #=> true 同値性の検査 String#eql?
'hello'.equal?('hello') #=> false 同一性の検査 Object#equal?
シンボルは同じ値であれば、プログラム中で一つしかインスタンスが生成されないことが保証されています。
:hello.object_id #=> 515368
:hello.object_id #=> 515368
:hello.equal?(:hello) #=> true
メソッド名のような唯一であることを表現したい場合に使いますが、どーしてもシンボルじゃないといけない機会はそれほどなく、実際は表記上の見た目の使い分けがされていることが多いです。
シンボルと文字列は別のものとして扱われるので、パラメータとしてシンボルを期待するのか文字列を期待するのか両方を許容して value.to_s とキャストするのかというあたりは気をつけることが多いです。
# 共存可能
{ 'hello' => 1, :hello => 2 }
'hello' == :hello #=> false
'hello'.to_s == :hello.to_s #=> true
IO class や File class を見てみてください。
open('filename') do |file|
file.readlines.map {|line| line + '!!!' }
end
# ファイルの close はブロックを抜けるときに保証されている
Ruby はいくつかのルールによって最小限の記述でセマンティックを表現しています。
# namespace は module を使ってつくっていきます
# namespace を TopLevel::NextLevel と重ねることもできますが
# 定義済の module ではない場合はエラーとなるので、
# 最初の定義ではひとつずつネストを深くしていきます
module TopLevelName
class ClassName
# 大文字で始まる名前は定数となります。メソッドの中ではリテラルとしては定義できません (裏口はある)
CONSTANT_NAME = 'const'
# @@ を二つつけるとクラス変数です。同一クラスのインスタンス間で共有されます
@@class_variable = 'this is class variable'
# クラスコンテキストの特異変数
@on_class_context = 'class context'
# class のコンストラクタは initialize という名前でつくります。
# ClassName.new(args) されたときに initialize(args) が呼ばれます。
def initialize
# インスタンスコンテキストで宣言された @ 付変数はインスタンス変数となります
# インスタンス内でメソッドをまたいで共有されます
@instance_variable = ':-)'
end
# def とスネークケースの命名でインスタンスメソッドを定義します
# 引数にはデフォルトを指定できます
# 末尾の引数は複数の値を array でまとめて受けることができ、可変長引数に使われます
def method_name(val = 'default', *args)
# メソッドからの復帰は return を使います
return :ok
end
# 呼出しの多くの場合と同様に、メソッド定義の引数の () は省略できます
# デフォルトを指定しない引数は必須の引数としてシグネチャがあわない場合に ArgumentError を起こします
# &付でブロックを受け、another_method(val) {|item| item.succ } のような記法を受け付けるメソッドを定義できます
def another_method val, &block
block.call(val) unless block.nil?
end
# self. とつけることでクラスメソッドを定義できます
# クラスメソッドは、ClassName.class_method と呼び出します
# この中はクラスコンテキストになります
def self.class_method
puts @on_class_context # 見える. 一方、@instance_variable は見えない
end
private
# private 宣言した以降のメソッドはプライベートメソッドとなり、
# 同一インスタンス内からのみ呼出しが可能になります
# 外部からの呼出しは NoMethodError となります
def private_method
end
# デストラクタ
# ないです。GC のタイミングで走る機構など言語レベルではありますが、
# それよりも open のような execute around method pattern などで
# 事後処理を保証するほうがよいでしょう
# 実装は begin ensure の制御構造を使ってかんたんに行えます
end
end
くわしくはリファレンスマニュアルを参照。
ん、グローバル変数?
$global_var
です。まず、見ないので唯一この説明の中でぐぐって調べました。
- 継承
- 継承は単一継承です
- 多重継承できないことの力の弱さは Mix-in が補います
- 結果として、Ruby では概念の親子関係を表現するためだけに継承を使い、実装の共有は Mix-in で実現するという設計ができます
- Mix-in
- Ruby の module は namespace をつくる役割と、Mix-in による実装継承を行うための module を定義する役割のふたつを兼任しています
Matz による Mix-in の解説
- まつもと直伝 プログラミングのオキテ 第3回 多重継承の光と影
Ruby は動的型言語なので、Java のようなポリモーフィズムのための型の継承によるインターフェイスの保証というのが必要ありません。 これも継承の利用を少なくおさえている理由のひとつです。 interface 継承で型としてポリモーフィズムを保証するかわりに、Ruby では DuckTyping といわれるインスタンス重視のアプローチをとっています。 これはそのときに呼ばれたメソッドのシグネチャに対してインスタンスが振る舞えるなら、その型は問わないという呼出しメソッドごとのシグネチャだけを対象とした最小限の契約です。 (Perl もそうですね)
- まつもと直伝 プログラミングのオキテ 第4回 Duck Typingが生まれるまで
その他の、条件分岐や繰り返し、例外についてはリファレンスマニュアルを参照。
注意点としては、Ruby では通常繰り返しの制御構造はほぼ使いません。 90% 以上が Array や Hash に対するメソッド呼出しでのイテレーションでまかなえるからです。 Array, Hash, Enumerable を使ったプログラミングに慣れましょう。
それパーフェクト Ruby に書いてるよ!
Ruby のコードを読んでいると
class Hoge
class << self
def hello
puts 'hello'
end
end
end
って出てきてびびるんだが、これはなんの暗号ですか?
続きはこちら。
- https://gist.github.com/sunaot/8682795
- その後、加筆して Rubyist Magazine へ記事として寄稿しました