その他 > その他 > Ruby Tips

実行環境など

以下のコードは全て Ruby 2.2.2p95 で動作確認をしている。

罫線で区切られたソースコードより下の部分は、 標準出力とエラー出力を合わせた出力である。 なお、 Ruby では標準出力はデフォルトでバッファリングされるが、 バッファリングされない場合の出力を記載している。 したがって、 標準出力とエラー出力が混ざるようなコードに対しては、 実際の出力内容とこのページに書かれた出力内容とで行の順番が異なる可能性がある。 $stdout.sync = true などを前もって実行しておくなどして、 バッファリングを無効化しておくと良い。

スコープ, ブロック

束縛, スコープ

オブジェクトに名前が与えらている状態を 「束縛」 という。 例えば、 variable = 9 というコードを実行すると、 9 というオブジェクトに variable という名前を与えているという束縛ができ上がる。 この束縛が共有される範囲を 「スコープ」 という。

a = 7
b = "abcd"
c = Array.new(3)
p a
p c
class Foo
  p c
end

7 [nil, nil, nil] ****.rb:7:in `<class:Foo>': undefined local variable or method `c' for Foo:Class (NameError) from ****.rb:6:in `<main>'

上の例では、 初めの 3 行で 3 つの束縛が定義される。 4 行目で、 a という名前を束縛するオブジェクトである 7 を表示している。 5 行目では、 c に対して同じことを行っている。 ac の束縛はその前の行で定義されているから、 ここまでは束縛が共有されていることになる。 しかし、 7 行目で c を束縛するオブジェクトを表示しようとするとエラーになる。 これは、 7 行目の実行時点では c に関する束縛が存在しないからで、 最初の 5 行でが存在していたはずの束縛がここでは共有されていないことになる。 すなわち、 スコープが異なるということになる。

スコープが変化するのは、 モジュール定義 (クラス定義を含む) とメソッドである。 このようなスコープが変化する場所を 「スコープゲート」 という。 この言葉を用いて言い換えれば、 Ruby のスコープゲートは module, class, def の 3 つである。

a = 1
class Test
  b = 2
  p [:in_class, local_variables]
  def foo
    c = 3
    p [:in_method, local_variables]
  end
end
test = Test.new
test.foo
p [:in_main, local_variables]

[:in_class, [:b]] [:in_method, [:c]] [:in_main, [:a, :test]]

上のソースコードには、 トップレベルのスコープ, Test クラス内のスコープ, foo メソッド内のスコープの 3 つのスコープが存在する。 スコープが異なるので、 それぞれのスコープで定義された束縛 (ローカル変数の定義) は別のスコープでは共有されない。 上のように、 ローカル変数の束縛の有無は Kernel#local_variables で確認できる。

フラットスコープ

スコープゲートをメソッド呼び出しに置き換えれば、 スコープが新しく作られないので変数を共有できる。 これをうまく使うと、 一部のメソッドのみで共有されるローカル変数を作ることができる。

class Test
  def self.define
    shared = 0
    define_method(:display) do
      p shared
    end
    define_method(:plus_one) do
      shared += 1
    end
  end
  def foo
    p shared
  end
end
Test.define
test = Test.new
test.display
test.plus_one
test.display
test.foo

0 1 ****.rb:12:in `foo': undefined local variable or method `shared' for #<Test:0x00000002a0dc58> (NameError) from ****.rb:20:in `<main>'

ブロック

Ruby のブロックは、 コードと束縛のペアである。 ブロックは、 それが定義された時点での束縛を保持し、 ブロックが実行されるときはその保持した束縛のもとでコードが実行される。

def foo(&block)
  x = 5
  block.call
end
x = 3
foo do
  p x
end

3

上のソースコードでは、 6 行目の do から 8 行目の end までがブロックである。 このブロックが定義された時点では、 3 というオブジェクトに x というローカル変数が束縛されている。 foo メソッドが 6 行目で呼ばれると、 メソッド定義内の 2 行目以降のコードが、 新しいスコープで実行される。 ここでは、 2x というローカル変数が束縛されているが、 block.call でブロックを実行すると、 ブロックが保持している束縛をもとにブロックの内容である p x が実行されるので、 上のような出力が得られるのである。

proc, lambda

ブロックはオブジェクトではないが、 オブジェクトに変換することはできる。 このときにできるのが Proc クラスのインスタンスである。 ブロックから Proc インスタンスを得るには、 Proc.new, Kernel#proc, Kernel#lambda, 矢印演算子の 4 つの方法がある。 Proc.newKernel#proc はどちらを使っても同じインスタンスを返し、 Kernel#lambda と矢印演算子の 2 つも同じだが、 例えば Proc.new を使って生成したものと Kernel#lambda を使って生成したものは微妙に違う。 Proc.newKernel#proc を用いたものを 「proc」 と呼び、 Kernel#lambda や矢印演算子を用いたものを 「lambda」 と呼ぶ。

proc と lambda の違いは全てを説明しようとすると非常に複雑だが、 主に 2 つである。 まず、 return の挙動が異なる。 proc 内で return を呼ぶと proc が定義されているスコープから戻ろうとするが、 lambda で return を呼ぶと単に lambda から戻るだけである。

def proc_test
  block = proc {return 1}
  block.call
  return 0
end
def lambda_test
  block = lambda {return 1}
  block.call
  return 0
end
p proc_test
p lambda_test

1 0

また、 proc より lambda の方が引数の扱いに厳しく、 lambda に対して定義と異なる引数の数で呼びだそうとするとエラーが生じる。 ただし、 これには特殊ケースがいろいろあり、 実際は複雑である。

なお、 proc や lambda はどちらもブロックをオブジェクト化しただけなので、 保持している束縛はブロックと同じように定義時点の束縛である。 同じスコープであっても、 proc や lambda が定義された後で定義された束縛は共有されていない。

lambda = -> {p x}
x = 3
lambda.call

****.rb:1:in `block in <main>': undefined local variable or method `x' for main:Object (NameError) ****.rb:3:in `call' ****.rb:3:in `<main>'

Method, UnboundMethod

メソッドはオブジェクトではないが、 ブロックと同じようにオブジェクトに変換することはできる。 これは Object#method により行われ、 Method インスタンスが得られる。 Method インスタンスはブロックとは異なり、 定義時のスコープではなく、 生成するときにレシーバに指定したオブジェクトのスコープで評価される。

class Test
  def initialize
    @variable = 0
  end
  def foo
    p @variable
  end
end
test = Test.new
foo = test.method(:foo)
foo.call

0

上のようにして得られた Method インスタンスに対して Method#unbind を呼ぶか、 Module#instance_method を用いるかすると、 UnboundMethod インスタンスが得られる。 これは、 束縛をもたないメソッドのようなものである。 そのままでは実行できないが、 UnboundMethod#bind を用いて適当なオブジェクトに束縛すれば実行できるようになる。 このとき当然だが、 束縛するオブジェクトはもとのクラスと同じクラスかそのサブクラスのインスタンスである必要がある。 もともとがモジュールにあったメソッドであれば、 このような制限はない。

class Test
  def initialize
    @variable = 0
  end
  def foo
    p @variable
  end
end
foo = Test.instance_method(:foo)
test = Test.new
test.instance_eval do
  @variable = 5
end
bounded_foo = foo.bind(test)
bounded_foo.call

5

UnboundMethod インスタンスは Module#define_method の第 2 引数に渡すことができる。

module Test
  def foo
    puts("foo")
  end
end
foo = Test.instance_method(:foo)
String.send(:define_method, :foo, foo)
"String".foo

foo

Method インスタンスの呼び出しは、 lambda の呼び出しと同じように引数の個数に厳密である。 引数の数が異なるとエラーになる。

Binding

Ruby ではほとんど全てのものがオブジェクトなので、 束縛もオブジェクトにすることができる。 束縛は Binding インスタンスで管理する。 Kernel#binding により、 このメソッドが呼び出されたスコープ全体の束縛を保持した Binding インスタンスが取得できる。 Binding インスタンスは Kernel#eval の第 2 引数に指定でき、 第 1 引数の文字列をその Binding インスタンスが保持する束縛のもとで評価される。

x = 5
test_binding = binding
y = 3
eval("p x", test_binding)
eval("p y", test_binding)

5 3

上の例からも分かるが、 Binding インスタンスが保持するのはスコープ全体の束縛である。 したがって、 同じスコープ内であればどこで Binding インスタンスを生成しても同じものが得られる。

Binding インスタンスは Proc#binding を用いても生成できる。 これはレシーバが定義されているスコープ全体の束縛を保持した Binding インスタンスを返す。 ブロックが保持する束縛は定義時に存在していたものだけなので、 この違いには注意すること。

block = -> {p x}
x = 3
block_binding = block.binding
eval("p x", block_binding)
block.call

3 ****.rb:1:in `block in <main>': undefined local variable or method `x' for main:Object (NameError) from ****.rb:5:in `call' from ****.rb:5:in `<main>'

組み込み定数である TOPLEVEL_BINDING にはトップレベルのスコープの Binding インスタンスが格納されている。 これを使うと、 ソースコード上のどの位置でもトップレベルにアクセスできる。

class Test
  def foo
    eval("p self", TOPLEVEL_BINDING)
  end
end
Test.new.foo

main

クラス, モジュール, メソッド

基本

Ruby には 「クラスのようなもの」 としてクラスとモジュールがある。 Ruby ではほとんど全てのものがオブジェクトなので、 当然クラスそのものやモジュールそのものもオブジェクトである。 クラスは Class クラスのインスタンスで、 モジュールは Module クラスのインスタンスである。 クラスやモジュールは、 どちらもインスタンスメソッドをもつことができるという点で、 通常のオブジェクトと異なる。

クラスは、 インスタンスの生成とスーパークラスの参照という 2 つの機能をモジュールに追加したものである。 逆に言えば、 モジュールは、 インスタンスの生成ができずスーパークラスをもたないクラスだと考えられる。 実際、 ClassModule のサブクラスで、 Class で新しく定義されているインスタンスメソッドは new, allocate, superclass の 3 つだけである。

特異クラス

オブジェクトは全て特異クラスをもつ。 特異クラスは継承ができず、 オブジェクトの特異メソッドはこの特異クラスに定義される。 特異クラスは Object#singleton_class で取得できる。 普通のオブジェクトの特異クラスのスーパークラスはそのオブジェクトのクラスである。

string = "abc"
p string.class
p string.singleton_class
p string.singleton_class.superclass

String #<Class:#<String:0x00000002a2eae8>> String

クラスの特異クラスのスーパークラスはそのクラスのスーパークラスの特異クラスである。

p String.superclass
p String.singleton_class
p String.singleton_class.superclass
p String.superclass.singleton_class

Object #<Class:String> #<Class:Object> #<Class:Object>

クラスでないモジュールに関しては、 普通のオブジェクト同じような挙動を示す。

p Kernel.class
p Kernel.singleton_class
p Kernel.singleton_class.superclass

Module #<Class:Kernel> Module

Module#include, Module#prepend, Object#extend

Module#include は、 継承チェーンにおいてレシーバとなるモジュールの上に引数のモジュールを追加する。 逆に、 Module#prepend は、 モジュールの下に引数のモジュールを追加する。

module M
end
module N
end
class C
  prepend M
  include N
end
class D < C
end
p D.ancestors

[D, M, C, N, Object, Kernel, BasicObject]

Kernel モジュールのインスタンスメソッドがどこでもレシーバなしで呼び出せるのは、 ObjectKernel をインクルードしているためである。

異なるモジュールを複数インクルードした場合は、 順にモジュールのすぐ上にモジュールが追加されていく。 プリペンドも同様である。

module M
end
module N
end
class C
  include M
  include N
end
p C.ancestors

[C, N, M, Object, Kernel, BasicObject]

モジュールのインクルードやプリペンドの際に、 すでに継承チェーンに属しているモジュールが再び継承チェーンに追加されることはない。

module M
end
module N
  include M
end
class O
  prepend M
  include N
end
p O.ancestors
p N.ancestors

[M, O, N, Object, Kernel, BasicObject] [N, M]

上の例では、 O での継承チェーンは M, O, N, M と続くはずだが、 プログラムの 3 行目で行われるはずの M の継承チェーンへの追加は、 すでに継承チェーンに M があるため行われない。 一方、 N での継承チェーンにおいては、 3 行目での M の追加は 1 回目なので行われる。

Object#extend を用いることで、 レシーバの特異メソッドに引数のモジュールのインスタンスメソッドを追加できる。

module Extension
  def foo
    puts("foo")
  end
end
object = Object.new
object.extend(Extension)
object.foo

foo

クラスメソッドはクラスの特異メソッドだから、 同様にしてクラスメソッドも定義できる。

module Extension
  def foo
    puts("foo")
  end
end
class ExtendedClass
  extend Extension
end
ExtendedClass.foo

foo

クラスの特異メソッドはクラスの特異クラスのインスタンスメソッドであるから、 上のソースコードは以下と等価である。

module Extension
  def foo
    puts("foo")
  end
end
class ExtendedClass
  class << self
    include Extension
  end
end
ExtendedClass.foo

foo

メソッド探索

メソッド探索において注意すべきパターンを挙げておく。 基本は、 まずレシーバの特異クラスを探し、 そこになかったらスーパークラスを順にたどって (継承チェーンを上に向かって) 探していく。 特異クラスにメソッドはないことが多いので、 メソッド探索はレシーバの普通の意味でのクラスから始まると考えることもある。

クラスにモジュールがプリペンドされている場合は、 少し注意が必要である。

module PrependedModule
  def foo
    puts("foo in PrependedModule")
  end
end
class Test
  prepend PrependedModule
  def foo
    puts("foo in Test")
  end
end
Test.new.foo

foo in PrependedModule

Test インスタンスに対して foo メソッドを呼ぼうとすると、 メソッド探索は Test からではなくその下にある PrependedModule から始まる。 どんなときでも継承チェーンの一番下からメソッド探索が行われると考えれば良い。

以下は、 同名のインスタンスメソッドをもつ複数のモジュールをインクルードしている例である。

module ModuleAlpha
  def foo
    puts("foo in ModuleAlpha")
  end
  def bar
    foo
  end
end
module ModuleBeta
  def foo
    puts("foo in ModuleBeta")
  end
end
class Test
  include ModuleAlpha
  include ModuleBeta
end
p Test.ancestors
test = Test.new
test.bar

[Test, ModuleBeta, ModuleAlpha, Object, Kernel, BasicObject] foo in ModuleBeta

Test.new.test が呼ばれた時点で、 selftest に変わり、 メソッド探索が始まる。 まず、 bar メソッドを探索する。 これは test のクラスである Test にないので、 次に ModuleBeta を探すがここにもないので、 ModuleAlpha を探してここで見つかるので、 ModuleAlpha#bar が実行される。 このメソッドの内部では foo メソッドが呼ばれているが、 レシーバがないので self に対するメソッド呼び出しだと解釈されて self.foo と同様の挙動を示す。 すなわち、 ここでは test.foo と書かれているのと同じように動く。 したがって、 再びメソッド探索が開始する。 test のクラスである Test には foo はないので、 ModuleBeta を探しここで見つかるので、 ModuleBeta#foo が実行される。 結果的に、 上で示した出力を得る。 ソースコードだけを見ると、 ModuleAlpha#bar が呼ばれると同じモジュールに定義されている ModuleAlpha#foo が呼ばれそうだが、 実際はそうではない。

カレントオブジェクト

Ruby のコードは全てカレントオブジェクト (self) のもとで実行される。 レシーバを指定せずにメソッドを呼び出すと、 レシーバはカレントオブジェクトであると解釈される。 また、 インスタンス変数への参照は、 その変数がカレントオブジェクトに属していると解釈される。

カレントオブジェクトが変更される場所はいくつかある。 まず、 レシーバを指定してメソッドを呼び出すと、 そのメソッドを実行している間は self がそのレシーバになる。

class Test
  def foo
    @x = 10
    p [:foo, self]
    bar
  end
  def bar
    @x += 1
    p [:bar, self]
  end
end
test = Test.new
test.foo

[:foo, #<Test:0x00000002a2e1d8 @x=10>] [:bar, #<Test:0x00000002a2e1d8 @x=11>]

モジュール定義 (クラス定義を含む) の内部では、 self はそのモジュールそのものになる。 ただし、 メソッド定義の内部では、 上で述べたようにメソッドのレシーバが self である。

class Test
  p [:in_class, self]
  def foo
    p [:in_method, self]
  end
end
Test.new.foo

[:in_class, Test] [:in_method, #<Test:0x000000029de570>]

上で述べたようなものと同じ機能をもつメソッドのブロック内でも self が変化する。 例えば、 クラス定義に相当する Class.new のブロック内ではその返り値が self になるし、 Module#define_method のブロック内ではメソッドのレシーバが self になる。

カレントモジュール

Ruby ではカレントモジュールというものもある。 メソッドを定義すると、 カレントモジュールのインスタンスメソッドになる。

トップレベルでは、 カレントモジュールは Object である。 モジュール定義 (クラス定義を含む) の内部では、 そのモジュールがカレントモジュールになる。 メソッドの内部では、 カレントオブジェクトのクラスがカレントモジュールになる。

BasicObject#instance_eval, Module#class_eval

BasicObject#instance_eval は、 レシーバのコンテキストで与えられたブロックを評価する。 すなわち、 与えたブロック内でのカレントオブジェクトをレシーバ自身にし、 カレントモジュールをレシーバの特異クラスにする。 特に前者の効果により、 レシーバのインスタンス変数や private なメソッドなどにアクセスができる。

class Test
  def initialize
    @variable = 0
  end
  private def foo
    puts("foo")
  end
end
x = 5
test = Test.new
test.instance_eval do
  foo
  p @variable
  @variable = x
end
test.instance_eval do
  p @variable
end

foo 0 5

Module#class_eval は、 レシーバのクラスのコンテキストで与えられたブロックを評価する。 すなわち、 与えられたブロック内でのカレントオブジェクトとカレントモジュールをともにレシーバ自身にする。

なお、 BasicObject#instance_eval, Module#class_eval のそれぞれに対して、 ブロックに引数を与えることができる BasicObject#instance_exec, Module#class_exec というものもある。

アクセス制御

Ruby のメソッドの可視性には、 private, protected, public の 3 種類が存在する。

private なメソッドはレシーバをつけて呼び出すことができなくなる。 すなわち、 そのメソッドが self に対して呼び出されるものであるようなスコープでしか呼び出せなくなる。

class Foo
  private def foo
    puts("foo called")
  end
  def bar
    foo
  end
end
Foo.new.bar
Foo.new.foo

foo called ****.rb:10:in `<main>': private method `foo' called for #<Foo:0x00000002aae838> (NoMethodError)

private メソッドのルールはあくまで 「レシーバをつけて呼び出せない」 であるので、 例えば明示的に self に対して呼び出そうとするとエラーになる。

class Foo
  private def foo
    puts("foo called")
  end
  def bar
    self.foo
  end
end
Foo.new.bar

****.rb:6:in `bar': private method `foo' called for #<Foo:0x00000002a2e8e0> (NoMethodError) from ****.rb:9:in `<main>'

また、 スーパークラスから継承したメソッドはレシーバなしで呼べるので、 そのメソッドが private であってもサブクラスから呼び出せる。

class SuperFoo
  private def foo
    puts("foo called")
  end
end
class Foo < SuperFoo
  def bar
    foo
  end
end
Foo.new.bar

foo called

なお、 アクセサメソッド (def hoge=(value) で定義できるもの) はレシーバとして self だけは許される。 レシーバなしの呼び出しのみ可能にすると、 変数への代入と区別したいときに困るからだろう。

protected なメソッドは、 そのメソッドをもつオブジェクトが self であるような場所でのみ呼び出せる。 private との違いは例えば以下のコードで分かる。

class Foo
  private def private
    puts("private called")
  end
  protected def protected
    puts("protected called")
  end
  def bar
    protected
    private
    Foo.new.protected
    Foo.new.private
  end
end
foo = Foo.new
foo.bar

protected called private called protected called ****.rb:12:in `bar': private method `private' called for #<Foo:0x00000002a2e2a0> (NoMethodError) ****.rb:16:in `<main>'

このコードでは、 foo.bar を実行する段階で、 9 行目から始まる bar メソッドの中身を実行し始めるが、 ここでの selffoo であるから、 foo がもつ protected なメソッドが呼び出せる。 Foo.new.private がエラーになるのはすでに述べた通りである。

Object#send を用いると、 可視性に関係なくメソッドを呼び出せる。

class Foo
  private def private
    puts("private called")
  end
  protected def protected
    puts("protected called")
  end
end
Foo.new.send(:private)
Foo.new.send(:protected)

private called protected called

メソッドの可視性の設定は、 Module#private, Module#protected, Module#public を用いる。 これらを引数なしで呼び出すと、 それ以降で定義されるメソッドがその可視性に設定される。 シンボルか文字列を引数に渡す (複数指定できる) と、 その名前をもつメソッドがその可視性に設定される。 なお、 Ruby 2.1.0 からはメソッド定義式がその名前のシンボルを返すようになったので、 上のように private def foo と書ける。

Enumerable

Enumerable#chunk

Enumerable#chunk は、 要素を初めから順にブロックで評価し、 評価値が同じになる部分をグループ化してできる Enumerator インスタンスを返す。 返される Enumerator インスタンスは、 ブロックの評価値とその評価値になるもとの要素からなる配列のペアを順に回す。

array = [2, 6, 7, 9, 1, 4, 1, 7]
array.chunk{|s| s.even?}.each do |element|
  p element
end

[true, [2, 6]] [false, [7, 9, 1]] [true, [4]] [false, [1, 7]]

ブロックの評価値が nil:_separator である場合は、 その要素は返される Enumerator インスタンスに含まれなくなる。 この前後でブロックは区切られる。 例えば、 ファイルを読み込んで 1 行ずつ分割したいが、 ハイフン 5 つからなる行でさらに分割したい場合に、 以下のように書ける。

separated = DATA.chunk do |line|
  next (line != "-----\n") || nil
end
separated.each do |_, data|
  pp data
end
__END__
AAAAA
AAAAA
AAAAA
-----
-----
BBBBB
BBBBB
BB
-----
CCCCC

["AAAAA\n", "AAAAA\n", "AAAAA\n"] ["BBBBB\n", "BBBBB\n", "BB\n"] ["CCCCC"]

ブロックの評価値が :_alone である場合は、 その要素は単独のブロックをなす。

separated = DATA.chunk do |line|
  next (line != "-----\n") || :_alone
end
separated.each do |_, data|
  pp data
end
__END__
AAAAA
AAAAA
AAAAA
-----
-----
BBBBB
BBBBB
BB
-----
CCCCC

["AAAAA\n", "AAAAA\n", "AAAAA\n"] ["-----\n"] ["-----\n"] ["BBBBB\n", "BBBBB\n", "BB\n"] ["-----\n"] ["CCCCC"]

Enumerable#find の 第 1 引数

Enumerable#find はブロックを評価して最初に真になる要素を返すが、 引数を指定することで真になる要素が見つからなかったときの返り値を指定できる。 このときの引数は、 単なる値ではなく Proc インスタンス (call メソッドをもっていれば他のオブジェクトでも良い) である。 単に call を呼び出すだけで、 引数は与えない。

array = [2, 6, 7, 9, 1, 4, 1, 7]
proc = -> do 
  next :none
end
p array.find(proc){|s| s % 5 == 0}

:none

ブロックなしの Enumerable のメソッド

ブロックなしの Enumerable#mapEnumerator インスタンスを返す。 繰り返しのできるオブジェクト (何でも良い) を Enumerator インスタンスに変換するという認識で良いのだろうか・・・。

DATA.map.with_index do |element, i|
  p [i, element]
end
__END__
foo
hoge
hugahuga
bar

[0, "foo\n"] [1, "hoge\n"] [2, "hugahuga\n"] [3, "bar"]

上のコードの DATA.map.with_indexDATA.with_index にすることはできない。 これは、 DATAFile インスタンス (FileEnumerable を Mix-in している) であるため、 Enumerator クラスで定義される with_index メソッドが呼べないためである。

Enumerable#map に限らず、 ブロックをとる Enumerable のメソッドは、 たいていブロックを指定しないと対応する Enumerator インスタンスを返すようになっている。 例えば、 おもしろくない例だが、 以下のような感じである。

array = [2, 7, 1, 8, 2, 8]
array.find.each_with_index do |element, i|
  p [i, element]
end

[0, 2]

リテラル

% 記法

% 記法は %Q, %q, %s, %r, %W, %w, %x の 7 種類で、 %Q%q は文字列、 %s はシンボル、 %r は正規表現、 %W%w は配列、 %x はコマンド出力を表す。 大文字版と小文字版があるものは、 式展開やバックスラッシュ記法の有無が異なる。 大文字の方は式展開などが行われ (文字列リテラルのダブルクォートに相当)、 小文字の方は式展開などが行われない (文字列リテラルのシングルクォートに相当)。 また、 %r では式展開だけが行われ、 バックスラッシュ記法は無効である。 アルファベットを省略した場合は %Q であると解釈される。

p %|A'B'C/D"E"F\u0061=#{2*2}|
p %Q{A'B'C/D"E"F\u0061=#{2*2}}
p %q[A'B'C/D"E"F\u0061=#{2*2}]
p %s$A'B'C/D"E"F\u0061=#{2*2}$
p %r!A'B'C/D"E"F\u0061=#{2*2}!
p %W$A'B' C/D "E"F \u0061=#{2*2}$
p %w$A'B' C/D "E"F \u0061=#{2*2}$
p %x*echo hello*

"A'B'C/D\"E\"Fa=4" "A'B'C/D\"E\"Fa=4" "A'B'C/D\"E\"F\\u0061=\#{2*2}" :"A'B'C/D\"E\"F\\u0061=\#{2*2}" /A'B'C\/D"E"F\u0061=4/ ["A'B'", "C/D", "\"E\"F", "a=4"] ["A'B'", "C/D", "\"E\"F", "\\u0061=\#{2*2}"] "hello\n"

%W%w はスペースで要素が区切られるが、 %W において式展開が含まれる場合はその評価を行う前に要素に区切られる。

string = "X Y"
p %W(A\ B #{string}C\sD #{3 * 3})

["A B", "X YC D", "9"]

ヒアドキュメント

<< に続けて、 クォートで括られた何らかの識別子を書くと、 それの次の行からその識別子だけの行の直前の行までがリテラルになる。 ダブルクォートを利用した場合は式展開やエスケープが有効になり、 シングルクォートを利用した場合は無効になる。 識別子をクォートで括らなかった場合は、 ダブルクォートで囲った場合と同じになる。

p <<"EOB"
String Line 1
String Line 2
EOB
p <<EOS
String Line 1
String Line 2
EOS
p <<`HELLO`
echo hello
HELLO

"String Line 1\nString Line 2\n" "String Line 1\nString Line 2\n" "hello\n"

ヒアドキュメントの終了を示す行は識別子だけからなる必要がある。 識別子の前後にスペースを入れることはできない上に、 コメントも書くことができない。 << の代わりに <<- にすると、 ヒアドキュメントの終了を表す識別子をインデントすることができるようになるが、 依然としてコメントは書けない。

p <<"EOB"
String Line 1
String Line 2
  EOB  # comment
String Line 3
EOB
p <<-"EOB"
String Line 1
String Line 2
  EOB

"String Line 1\nString Line 2\n EOB # comment\nString Line 3\n" "String Line 1\nString Line 2\n"

文字列リテラルと違い、 ヒアドキュメントの中ではクォートをエスケープする必要がない。 特にシングルクォートによるヒアドキュメントは、 完全にソースコードに書かれているそのままの文字列になる。 以下の例の ", ', \ の挙動について特に注目すること。

p <<"EOB"
"AB" 'CD' \"AB\" \'CD\' #{3 * 5} 
EOB
p <<'EOB'
"AB" 'CD' \"AB\" \'CD\' #{3 * 5} 
EOB

"\"AB\" 'CD' \"AB\" 'CD' 15 \n" "\"AB\" 'CD' \\\"AB\\\" \\'CD\\' \#{3 * 5} \n"

<<"EOB" などの部分が式になるので、 以下のような記述が可能になる。

def method(foo, string, bar)
  p string
end
method(1, <<"EOB", 2)
This is a here document.
line 2
line 3
EOB

"This is a here document.\nline 2\nline 3\n"

1 行に複数のヒアドキュメントを書くことも可能である。

def method(first_string, second_string)
  p first_string
  p second_string
end
method(<<FIRST, <<SECOND)
first line 1
first line 2
FIRST
second line 1
second line 2
SECOND

"first line 1\nfirst line 2\n" "second line 1\nsecond line 2\n"

条件式としての範囲式

範囲式は Ruby ではよく使われるが、 実は if などの条件式を書くところでも範囲式を使うことができ、 このときは Range インスタンスになるのではなく特殊な振る舞いをする。

ドット 2 つの範囲式 (a..b の形式) の挙動は以下の通りである。 まず初期状態として、 1 つ目の式 (上の例では a) が評価され、 これが真を返すまでは範囲式全体は false を返す。 1 つ目の式が真を返すと全体で true を返す。 このとき、 2 つ目の式も真ならば初期状態に戻る。 これ以降は 2 つ目の式のみを評価し、 2 つ目の式が真になるまで全体で true を返す。 2 つ目式が真になったら全体で true を返し、 その後に初期状態に戻る。

(1..20).each do |i|
  if (i % 5 == 0)..(i % 3 == 0)
    puts(i)
  end
end

5 6 10 11 12 15 20

ドット 3 つの範囲式 (a...b の形式) の場合は、 1 つ目の式が真を返したときに 2 つ目の式が真を返しても初期状態に戻らないところが異なる。

(1..20).each do |i|
  if (i % 5 == 0)...(i % 3 == 0)
    puts(i)
  end
end

5 6 10 11 12 15 16 17 18 20

以下は while 文で範囲式を用いた例である。

i = 0
while (i % 3 == 0)...(i % 5 == 0)
  puts(i)
  i += 1
end

0 1 2 3 4 5 6 7 8 9 10

その他

Kernel#require, Kernel#load

Kernel#requireKernel#load は外部ファイルを読み込むためのメソッドである。 これらは、 第 1 引数に指定された名前のファイルをロードパスから探し、 それをトップレベルで実行する。 したがって、 例えば、 読み込んだファイルで定数 (クラス名を含む) が定義されていればトップレベルの定数になる。 ただし、 読み込んだファイルのローカル変数は共有されない。

一方、 この 2 つのメソッドは、 様々な点で異なった挙動を示す。 まず、 Kernel#require はライブラリを読み込むときに用いるもので、 Kernel#load はファイルを読み込むときに用いるとされていて、 意味合いが異なる。 また、 Kernel#require は拡張子を省略できるが、 Kernel#load はできない。 さらに、 Kernel#require は同じファイルは 1 度だけしか実行しないが、 Kernel#load は同じファイルであってもこのメソッドが呼ばれれば何度でも実行する。

なお、 Kernel#load の第 2 引数に true を指定すると、 定数を読み込まなくなる。 より具体的には、 読み込むファイルを実行するときに無名のモジュールが作成され、 ファイル内の定数はこのモジュールのもとに定義され、 ファイルの実行が終わったらこのモジュールは破棄される。

Kernel#require, Kernel#require_relative

Copyright © 2009‐2017 Ziphil, All rights reserved.
inserted by FC2 system