ようへいの日々精進XP

よかろうもん

2018 年 06 月 22 日 (金)

ジョギング

  • 自宅→香椎神宮香椎浜 で 31 分くらい
  • 引き続き, 右腰, 右臀部の強い張り (ストレッチでなんとかしている)
  • 引き続き, 左足足底筋にも違和感あり
  • 暑くなってキタ━━━━(゚∀゚)━━━━!!

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (34) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

Module#refine

以下のコードを実行するとどうなるか.

class Cls1
  def method1(value)
    100 + value
  end
end

module Mod1
  refine Cls1 do
    def method1
      super 50
    end
  end
end

module Mod2
  refine Cls1 do
    def method1
      super 100
    end
  end
end

using Mod1
using Mod2

puts Cls1.new.method1

以下, 解答.

200 が出力される

以下, 確認. refine を含むコードは irb で実行する場合にはコツが必要

irb(main):001:0> class Cls1
irb(main):002:1>   def method1(value)
irb(main):003:2>     100 + value
irb(main):004:2>   end
irb(main):005:1> end
=> :method1
irb(main):006:0> 
irb(main):007:0* module Mod1
irb(main):008:1>   refine Cls1 do
irb(main):009:2*     def method1
irb(main):010:3>       super 50
irb(main):011:3>     end
irb(main):012:2>   end
irb(main):013:1> end
=> #<refinement:Cls1@Mod1>
irb(main):014:0> 
irb(main):015:0* module Mod2
irb(main):016:1>   refine Cls1 do
irb(main):017:2*     def method1
irb(main):018:3>       super 100
irb(main):019:3>     end
irb(main):020:2>   end
irb(main):021:1> end
=> #<refinement:Cls1@Mod2>
# Refinement でメソッドを追加した場合, 以下のように実行する必要がある
irb(main):022:0> using Mod1; using Mod2; puts Cls1.new.method1
200
=> nil
# もしくは, Refinement でメソッドを追加した場合, 以下のように実行する必要がある
irb(main):023:0> begin
irb(main):024:1*   using Mod1
irb(main):025:1>   using Mod2
irb(main):026:1>   puts Cls1.new.method1
irb(main):027:1> end
200
=> nil

以下, 解説より抜粋.

  • 設問では, 同じメソッドに対して Refinement で再定義を2つのモジュールで行っている
  • using を 2 行書いても, 1 つのメソッドで有効になる再定義は1つだけとなる為, 最後に書いた using から優先される
  • 有効になる再定義は 1 つなので, モジュール Mod2 にある super はクラス Cls1 の method1 を呼び出す為, super + 100100 + 100 となり 200 となる

尚, using Mod1 の内容はすべて無効になったわけではなく, 以下のようなサンプルコードの場合, Mod2 にメソッド method2 が定義されていなくても呼び出すことが出来る.

class Cls1
  def method1(value)
    100 + value
  end

  def method2(value)
    value + ", world"
  end
end

module Mod1
  refine Cls1 do
    def method1
      super 50
    end

    def method2
      super "Hello"
    end
  end
end

module Mod2
  refine Cls1 do
    def method1
      super 100
    end
  end
end

begin # irb で実行する為
  using Mod1
  using Mod2
  puts Cls1.new.method1
  puts Cls1.new.method2
end # irb で実行する為

以下, irb にて確認.

irb(main):001:0> class Cls1
irb(main):002:1>   def method1(value)
irb(main):003:2>     100 + value
irb(main):004:2>   end
irb(main):005:1> 
irb(main):006:1*   def method2(value)
irb(main):007:2>     value + ", world"
irb(main):008:2>   end
irb(main):009:1> end
=> :method2
irb(main):010:0> 
irb(main):011:0* module Mod1
irb(main):012:1>   refine Cls1 do
irb(main):013:2*     def method1
irb(main):014:3>       super 50
irb(main):015:3>     end
irb(main):016:2> 
irb(main):017:2*     def method2
irb(main):018:3>       super "Hello"
irb(main):019:3>     end
irb(main):020:2>   end
irb(main):021:1> end
=> #<refinement:Cls1@Mod1>
irb(main):022:0> 
irb(main):023:0* module Mod2
irb(main):024:1>   refine Cls1 do
irb(main):025:2*     def method1
irb(main):026:3>       super 100
irb(main):027:3>     end
irb(main):028:2>   end
irb(main):029:1> end
=> #<refinement:Cls1@Mod2>
irb(main):030:0> 
irb(main):031:0* begin # irb で実行する為
irb(main):032:1*   using Mod1
irb(main):033:1>   using Mod2
irb(main):034:1>   puts Cls1.new.method1
irb(main):035:1>   puts Cls1.new.method2
irb(main):036:1> end # irb で実行する為
200
Hello, world
=> nil

確かに. Mod2 には method2 は定義されていないけど, method2 を呼び出すことが出来ている.

フムフム.

2018 年 06 月 21 日 (木)

ジョギング

  • 自宅→香椎神宮香椎浜 で 35 分くらい
  • 引き続き, 右腰, 右臀部の強い張り (ストレッチでなんとかしている)
  • 引き続き, 左足足底筋にも違和感あり

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (33) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

クラス変数

以下のコードを実行するどどうなるか.

class S
  @@val = 0
  def initialize
    @@val += 10
  end
end

class C < S
  class << C
    @@val += 10
  end

  def initialize
    @@val += 10
    super
  end
end

C.new
C.new
S.new
S.new

p C.class_variable_get(:@@val)

以下, 解答.

70

以下, irb にて確認.

... 略 ...
irb(main):023:0> 
irb(main):024:0* p C.class_variable_get(:@@val)
70
=> 70

以下のタイミングにて @@val に加算される.

  • クラスメソッドが定義された
  • C.new が呼び出された
  • super により, S クラスの initialize が呼びだされた
  • S.new が呼び出された

ブレイクダウンして irb で確認してみる.

# クラスメソッドを定義した時点で @@val に 10 が代入されている
irb(main):042:0> p C.class_variable_get(:@@val)
10
=> 10
# C.new すると, 10 + 10 = 20, クラスメソッドの 10 を足して 30 になる
irb(main):043:0> C.new
=> #<C:0x0055c197ed57c0>
irb(main):044:0> p C.class_variable_get(:@@val)
30
=> 30
# さらに C.new して, 10 + 10 = 20, 30 + 20 = 50 になる
irb(main):045:0> C.new
=> #<C:0x0055c197ec3de0>
irb(main):046:0> p C.class_variable_get(:@@val)
50
=> 50
# S.new すると 10 となって, 50 + 10 = 60 になる
irb(main):047:0> S.new
=> #<S:0x0055c197eab920>
irb(main):048:0> p C.class_variable_get(:@@val)
60
=> 60
# さらに S.new すると 10 となって, 60 + 10 = 70 になる
irb(main):049:0> S.new
=> #<S:0x0055c197e8a090>
irb(main):050:0> p C.class_variable_get(:@@val)
70
=> 70

クラス変数怖い.

ブロック

以下のコードを実行するとどうなるか.

def foo(*args, &block)
  block.call(*args)
end

foo(1, 2, 3, 4) do |*args|
  p args.length > 0 ? "hello" : args
end

以下, 解答.

hello が出力される

以下, irb による確認.

irb(main):001:0> def foo(*args, &block)
irb(main):002:1>   block.call(*args)
irb(main):003:1> end
=> :foo
irb(main):004:0> 
irb(main):005:0* foo(1, 2, 3, 4) do |*args|
irb(main):006:1*   p args.length > 0 ? "hello" : args
irb(main):007:1> end
"hello"
=> "hello"

以下, 解説より抜粋.

  • 1 行目で引数の値を配列として受け取り, ブロックに配列を渡している
  • 2 行目で * を付けて引数を渡しているので, 配列が展開される (1, 2, 3, 4)
  • 5 行目でブロック変数を渡しているが, *args と宣言されている為, [1, 2, 3, 4] が渡される
  • 6 行目で args.length > 0 の結果は真となり, hello が出力される

フムフム.

2018 年 06 月 20 日 (水)

ジョギング

  • お昼休みに自宅→香椎神宮香椎浜 で 35 分くらい
  • 引き続き, 右腰, 右臀部の強い張り (ストレッチでなんとかしている)
  • 引き続き, 左足足底筋にも違和感あり

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (32) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

Enumerable#partition

以下のコードを実行するとどうなるか.

a = (1..5).partition(&:odd?)
p a

以下, 解答.

[[1, 3, 5], [2, 4]] が出力される

以下, irb による確認.

irb(main):024:0> (1..5).partition(&:odd?)
=> [[1, 3, 5], [2, 4]]

以下, 解説より抜粋.

  • Enumerable#partition はブロックの条件を満たす配列と条件を満たさない配列に分割して, 結合した2次元配列を返す
  • 条件を満たす配列は最初の要素に入る
  • Integer#odd? は self が奇数の場合に true を返すメソッド

Enumerable#partition をドキュメントより引用.

各要素を、ブロックの条件を満たす要素と満たさない要素に分割します。 各要素に対してブロックを評価して、その値が真であった要素の配列と、 偽であった要素の配列の 2 つを配列に入れて返します。 ブロックを省略した場合は、各要素に対しブロックを評価し、 上のようにその値が真であった要素の配列と、 偽であった要素の配列のペアを返すような Enumerator を 返します。

irb(main):001:0> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0].partition {|i| i % 3 == 0 }
=> [[9, 6, 3, 0], [10, 8, 7, 5, 4, 2, 1]]

大文字, 小文字をざっくりと判別するメソッドを追加して, Enumerable#partition してみる.

# 大文字小文字を判別するメソッドを String クラスに追加する
class String
  def islower?
    self =~ /[a-z]$/ ? true : false
  end
  
  def isupper?
    self =~ /[A-Z]$/ ? true : false
  end
end
['A', 'Az', 'Za', 'Bq', 'GG'].partition(&:islower?)
['A', 'Az', 'Za', 'Bq', 'GG'].partition(&:isupper?)
['aA', 'az', 'Za', 'Bq', 'GG'].partition(&:islower?)
['aA', 'az', 'Za', 'Bq', 'GG'].partition(&:isupper?)

以下, irb での実行例.

irb(main):015:0> ['A', 'Az', 'Za', 'Bq', 'GG'].partition(&:islower?)
=> [["Az", "Za", "Bq"], ["A", "GG"]]
irb(main):016:0> ['A', 'Az', 'Za', 'Bq', 'GG'].partition(&:isupper?)
=> [["A", "GG"], ["Az", "Za", "Bq"]]
irb(main):010:0> ['aA', 'az', 'Za', 'Bq', 'GG'].partition(&:islower?)
=> [["az", "Za", "Bq"], ["aA", "GG"]]
irb(main):011:0> ['aA', 'az', 'Za', 'Bq', 'GG'].partition(&:isupper?)
=> [["aA", "GG"], ["az", "Za", "Bq"]]

Enumerable#partition と関係無いけど, 小文字と大文字が混在している場合には, 最後の文字が評価される.

Integer#odd? をドキュメントより引用.

自身が奇数であれば真を返します。 そうでない場合は偽を返します。

irb(main):002:0> 1.odd?
=> true
irb(main):003:0> 2.odd?
=> false

ちなみに, Integer#odd? に対して, Integer#even? も利用可能.

自身が偶数であれば真を返します。 そうでない場合は偽を返します。

irb(main):004:0> 2.even?
=> true
irb(main):005:0> 1.even?
=> false

例外

以下のコードを実行するとどうなるか.

begin
  print "liberty" + :fish
rescue TypeError
  print "TypeError."
rescue
  print "Error."
else
  print "Else."
ensure
  print "Ensure."
end

以下, 解答.

TypeError.Ensure. が表示される

以下, irb による実行例.

irb(main):001:0> begin
irb(main):002:1*   print "liberty" + :fish
irb(main):003:1> rescue TypeError
irb(main):004:1>   print "TypeError."
irb(main):005:1> rescue
irb(main):006:1>   print "Error."
irb(main):007:1> else
irb(main):008:1*   print "Else."
irb(main):009:1> ensure
irb(main):010:1*   print "Ensure."
irb(main):011:1> end
TypeError.Ensure.=> nil

以下, 解説より抜粋.

  • :fish は Symbol クラスのオブジェクト
  • String#+ の引数は String クラスを期待する為, String クラス以外のオブジェクトが渡された場合は, TypeError が発生する
  • 例外を捕捉する為に rescue で, 例外を受け取った際の処理を記述する
  • エラーが発生しなかった場合の処理を行うには else を用いる
  • エラー発生有無に関わらず, 必ず実行する処理を行わせる為には ensure を用いる

フムフム.

2018 年 06 月 19 日 (火)

ジョギング

  • お昼休みに自宅→香椎神宮香椎浜 で 35 分くらい
  • 引き続き, 臀部の強い張り (ストレッチでなんとかしている)
  • 左足足底筋にも違和感あり

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

ワールドカップ

  • 日本がコロンビアに 2 - 1 で勝った
  • 長友選手の運動量が半端ないなーと思った, あの持久力には驚き...

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (31) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

クラス, メソッドの優先順位

以下のコードを実行するとどうなるか.

module Mod1
end

module Mod2
end

class Cls
  include Mod1, Mod2
end

p Cls.ancestors

[Cls, Mod1, Mod2, Object, Kernel, BasicObject]

以下, irb による確認.

irb(main):001:0> module Mod1
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module Mod2
irb(main):005:1> end
=> nil
irb(main):006:0> 
irb(main):007:0* class Cls
irb(main):008:1>   include Mod1, Mod2
irb(main):009:1> end
=> Cls
irb(main):010:0> 
irb(main):011:0* p Cls.ancestors
[Cls, Mod1, Mod2, Object, Kernel, BasicObject]
=> [Cls, Mod1, Mod2, Object, Kernel, BasicObject
  • includeprepend はモジュールのメソッドをインスタンスメソッドとして追加する
  • include では, メソッド探索順は self の後に追加され, prepend では, self の前に追加される
  • 複数モジュールを指定した場合は, 左側が先にメソッド探索される

ちなみに, prepend した場合には, 以下のように出力される.

irb(main):015:0> Cls2.ancestors
=> [Mod1, Mod2, Cls2, Object, Kernel, BasicObject]

定数探索

以下のコードを実行するとどうなるか.

module Mod1
  def refer_const
    CONST
  end
end

module Mod2
  CONST = '010'
end

class Cls1
  CONST = "001"
end

class Cls2 < Cls1
  include Mod2
  include Mod1
  CONST = '100'
end

c = Cls2.new
p c.refer_const

例外が発生する

以下, irb にて確認.

irb(main):001:0> module Mod1
irb(main):002:1>   def refer_const
irb(main):003:2>     CONST
irb(main):004:2>   end
irb(main):005:1> end
=> :refer_const
irb(main):006:0> 
irb(main):007:0* module Mod2
irb(main):008:1>   CONST = '010'
irb(main):009:1> end
=> "010"
irb(main):010:0> 
irb(main):011:0* class Cls1
irb(main):012:1>   CONST = "001"
irb(main):013:1> end
=> "001"
irb(main):014:0> 
irb(main):015:0* class Cls2 < Cls1
irb(main):016:1>   include Mod2
irb(main):017:1>   include Mod1
irb(main):018:1>   CONST = '100'
irb(main):019:1> end
=> "100"
irb(main):020:0> 
irb(main):021:0* c = Cls2.new
=> #<Cls2:0x0055a24afb1b10>
irb(main):022:0> p c.refer_const
NameError: uninitialized constant Mod1::CONST

以下, 解説より抜粋.

  • refer_const メソッドは, モジュール Mod1 にあるが, CONST はレキシカルに決定されるためモジュール Mod1 のスコープを探索する
  • 設問では Mod1 内に CONST が見つからないため例外が発生する

例えば, 以下のように書くことで Mod1::CONST を参照することが出来る.

irb(main):001:0> module Mod1
irb(main):002:1>   CONST = '100'
irb(main):003:1>   def refer_const
irb(main):004:2>     CONST
irb(main):005:2>   end
irb(main):006:1> end
=> :refer_const
irb(main):007:0> 
irb(main):008:0* module Mod2
irb(main):009:1>   CONST = '010'
irb(main):010:1> end
=> "010"
irb(main):011:0> 
irb(main):012:0* class Cls1
irb(main):013:1>   CONST = "001"
irb(main):014:1> end
=> "001"
irb(main):015:0> 
irb(main):016:0* class Cls2 < Cls1
irb(main):017:1>   include Mod2
irb(main):018:1>   include Mod1
irb(main):019:1> end
=> Cls2
irb(main):020:0> 
irb(main):021:0* c = Cls2.new
=> #<Cls2:0x00556bfc9497e8>
irb(main):022:0> p c.refer_const
"100"
=> "100"

フムフム.

2018 年 06 月 18 日 (月)

ジョギング

  • 自宅→香椎神宮香椎浜 で 35 分くらい
  • 臀部の強い張り (ストレッチでなんとかしている)

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

関西地方で大きな地震

  • 大きな被害が出ていた
  • 親戚や友人の皆さんは特にケガもなくということで一安心
  • これから天気も悪くなるとのことなので, 引き続き気をつけてくださいmm

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (30) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

定数探索

以下のコードを実行するとどうなるか.

class Foo
  NAME = "foo"

  def self.name
    const_get(:NAME)
  end
end

class Bar < Foo
  NAME = "bar"
end

puts Bar.name

bar が表示される

以下, irb にて確認.

irb(main):001:0> class Foo
irb(main):002:1>   NAME = "foo"
irb(main):003:1> 
irb(main):004:1*   def self.name
irb(main):005:2>     const_get(:NAME)
irb(main):006:2>   end
irb(main):007:1> end
=> :name
irb(main):008:0> 
irb(main):009:0* class Bar < Foo
irb(main):010:1>   NAME = "bar"
irb(main):011:1> end
=> "bar"
irb(main):012:0> 
irb(main):013:0* puts Bar.name
bar
=> nil

以下, 解説より抜粋.

  • Class#name はクラス名を文字列で返す
  • Foo#name クラスは Class#name をオーバーライドしているので, const_get が呼ばれることになる
  • const_get は, self に定義された定数を探索し, 自クラスに定義がない場合は, メソッドと同様に探索を行う

ドキュメントを見てみると, Class#name というメソッドが無いんだが...きっと, Module#name のことなんだろうなあということで, Module#name 前提でちょっと掘り下げる.

irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> Foo.name
=> "Foo"
irb(main):003:0> Foo.inspect
=> "Foo"
irb(main):004:0> Foo.to_s
=> "Foo"

Module#nameModule#inspecModule#to_s と同義である. このメソッドが返す「クラス/モジュール名」とは, 正確には「クラスパス」を指す.

irb(main):005:0> class Foo
irb(main):006:1>   class Bar
irb(main):007:2>   end
irb(main):008:1>   Bar.name
irb(main):009:1> end
=> "Foo::Bar"
irb(main):010:0> Foo.name
=> "Foo"
irb(main):012:0> Foo::Bar.name
=> "Foo::Bar"
irb(main):013:0> class Foo
irb(main):014:1>   class Baz; end
irb(main):015:1> end
=> nil
irb(main):016:0> Foo::Baz.name
=> "Foo::Baz"

引き続き, const_get について.

irb(main):001:0> module Bar
irb(main):002:1>   BAR = 1
irb(main):003:1> end
=> 1
irb(main):004:0> class Object
irb(main):005:1>   include Bar
irb(main):006:1> end
=> Object
# Object では include されたモジュールの定義を探索する
irb(main):007:0> Object.const_get(:BAR)
=> 1
# 存在しない定数にアクセスしようとすると例外 (NameError) が発生する
irb(main):008:0> Object.const_get(:FOO)
NameError: uninitialized constant FOO
... 略 ...
# トップレベルに定数を定義して, その定数を参照する場合
irb(main):009:0> BAR = 10
=> 10
irb(main):011:0> Object.const_get(:BAR)
=> 10
# 完全修飾名で定数を指定した場合には, モジュールに定義されている定数を参照する
irb(main):013:0> Object.const_get('Bar::BAR')
=> 1
irb(main):007:0> class Baz
irb(main):008:1>   include Bar
irb(main):009:1> end
=> Baz
irb(main):010:0> Baz.const_get(:BAR)
=> 1
# 第二引数に false を付けると, 自身に定義された定数から探す
irb(main):011:0> Baz.const_get(:BAR, false)
NameError: uninitialized constant Baz::BAR
... 略 ...
irb(main):012:0> class Baz
irb(main):013:1>   BAR = 2
irb(main):014:1> end
=> 2
irb(main):015:0> Baz.const_get(:BAR)
=> 2
irb(main):016:0> Baz.const_get(:BAR, false)
=> 2
irb(main):017:0> Baz.const_get('Bar:BAR')
NameError: wrong constant name Bar:BAR
... 略 ...
irb(main):018:0> Baz.const_get('Bar::BAR')
=> 1

const_get は, 引数 (String か Symbol で指定) で指定された定数を取り出す. 存在していない定数を参照すると NameError の例外が発生する. 第二引数に false を指定すると, 自身に定義された定数から探す.

フムフム.

2018 年 06 月 17 日 (日)

ジョギング

  • 自宅→香椎神宮香椎浜 で 35 分くらい
  • 臀部の強い張り (ストレッチでなんとかしている)

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

引き続き

  • 仕事をしつつ, 昨日よりは少しのんびり過ごすことが出来た
  • どこにも連れて行ってあげられなかったので, 奥さんには申し訳ないと思っている

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (29) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

method_missing

以下のコードを実行するとどうなるか.

module Mod
  def method_missing(id, *args)
    puts "Mod#method_missing"
  end
end
class Cls1
  include Mod
  def method_missing(id, *args)
    puts "Cls1#method_missing"
  end
end
class Cls2 < Cls1
  class << self
    def method_missing(id, *args)
      puts "Cls2.method_missing"
    end
  end
end

Cls2.new.dummy_method

Cls1#method_missing

以下, irb にて確認.

irb(main):001:0> module Mod
irb(main):002:1>   def method_missing(id, *args)
irb(main):003:2>     puts "Mod#method_missing"
irb(main):004:2>   end
irb(main):005:1> end
=> :method_missing
irb(main):006:0> class Cls1
irb(main):007:1>   include Mod
irb(main):008:1>   def method_missing(id, *args)
irb(main):009:2>     puts "Cls1#method_missing"
irb(main):010:2>   end
irb(main):011:1> end
=> :method_missing
irb(main):012:0> class Cls2 < Cls1
irb(main):013:1>   class << self
irb(main):014:2>     def method_missing(id, *args)
irb(main):015:3>       puts "Cls2.method_missing"
irb(main):016:3>     end
irb(main):017:2>   end
irb(main):018:1> end
=> :method_missing
irb(main):019:0> 
irb(main):020:0* Cls2.new.dummy_method
Cls1#method_missing
=> nil

以下, 解説より抜粋.

  • method_missing は, 継承チェーンを辿った末にメソッドが見つからなかった時に呼び出される
  • method_missing も継承チェーンを辿る
  • class << self; end で定義されたメソッドは, 特異クラスのインスタンスメソッドになる為, 設問コードでは呼び出すことが出来ない

以下のように呼び出すことで, Cls2 特異メソッドの method_missing を呼び出すことが出来る.

irb(main):021:0> Cls2.dummy_method
Cls2.method_missing
=> nil

メソッドの可視性

以下のコードを実行するとどうなるか.

class Cls
private
  def initialize
  end
end

p Cls.new.public_methods.include? :initialize

false が出力される.

以下, irb にて確認.

irb(main):001:0> class Cls
irb(main):002:1> private
irb(main):003:1>   def initialize
irb(main):004:2>   end
irb(main):005:1> end
=> :initialize
irb(main):006:0> 
irb(main):007:0* p Cls.new.public_methods.include? :initialize
false
=> false

以下, 解説より抜粋.

  • initialize の可視性はprivateに設定されている
  • initialize の可視性を public に設定したとしても, 必ず private となる

Object#private_methods というメソッドも用意されている.

irb(main):001:0> class Cls
irb(main):002:1>   def initialize
irb(main):003:2>   end
irb(main):004:1> end
=> :initialize
irb(main):005:0> Cls.new.private_methods(false)
=> [:initialize]
irb(main):006:0> Cls.new.private_methods(false).include?(:initialize)
=> true

Object#private_methods の引数に false を渡すと, スーパークラスに定義されているメソッドを除いて出力される.

フムフム.

2018 年 06 月 16 日 (土)

ジョギング

  • 自宅→香椎神宮香椎浜 x 1 周で 42 分くらい
  • 臀部の強い張り (ストレッチでなんとかしている)

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

やらかした...

  • ギョームで障害発生...うーん...ごめんなさい
  • ということで, 終日, 調査や検証等...

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (28) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

クラスやモジュールの優先順位

以下のコードを実行するとどうなるか.

module Mod1
end

module Mod2
end

class Cls
  include Mod1
  include Mod2
end

p Cls.ancestors

[Cls, Mod2, Mod1, Object, Kernel, BasicObject]

以下, irb による確認.

irb(main):001:0> module Mod1
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module Mod2
irb(main):005:1> end
=> nil
irb(main):006:0> 
irb(main):007:0* class Cls
irb(main):008:1>   include Mod1
irb(main):009:1>   include Mod2
irb(main):010:1> end
=> Cls
irb(main):011:0> 
irb(main):012:0* p Cls.ancestors
[Cls, Mod2, Mod1, Object, Kernel, BasicObject]
=> [Cls, Mod2, Mod1, Object, Kernel, BasicObjec

以下, 解説より抜粋.

  • include はモジュールのメソッドをインスタンスメソッドとして追加する
  • メソッドの探索順は self の後に追加される
  • 複数回 include された場合には, 後から宣言されたモジュールのメソッドが優先される (設問では Mod2 のメソッドが優先される)

Module#ancestors について, ドキュメントより抜粋.

クラス、モジュールのスーパークラスとインクルードしているモジュールを優先順位順に配列に格納して返します。

以下, irb による実行例.

irb(main):001:0> module Foo
irb(main):002:1> end
=> nil
irb(main):003:0> class Bar
irb(main):004:1>   include Foo
irb(main):005:1> end
=> Bar
irb(main):006:0> class Baz < Bar
irb(main):007:1>   p ancestors        # スーパークラスとインクルードしているモジュールの優先順位を返す
irb(main):008:1>   p included_modules # インクルードしているモジュールを返す
irb(main):009:1>   p superclass       # スーパークラスを返す
irb(main):010:1> end
[Baz, Bar, Foo, Object, Kernel, BasicObject]
[Foo, Kernel]
Bar
=> Bar

ブロック引数の渡し方

以下のコードを実行するとどうなるか.

def foo(&block, *args)
  block.call(*args)
end

foo(1,2,3,4) do |*args|
  p args.length > 0 ? "AAA" : args
end

例外が発生する

以下, irb にて確認.

irb(main):001:0> def foo(&block, *args)
irb(main):002:1>   block.call(*args)
irb(main):003:1> end
SyntaxError: (irb):1: syntax error, unexpected ',', expecting ')'
def foo(&block, *args)
               ^
(irb):3: syntax error, unexpected keyword_end, expecting end-of-input

以下, 解説より抜粋.

  • ブロック引数は仮引数の中で最後に記述する
  • ブロック引数はメソッド定義につき 1 つしか指定出来ない
  • 他の引数がある場合には, ブロック引数は必ず最後に指定する必要がある

以下, 正しく動作するコード.

def foo(*args, &block)
  block.call(*args)
end

foo(1,2,3,4) do |*args|
  p args.length > 0 ? "AAA" : args
end

以下, irb にて確認.

irb(main):001:0> def foo(*args, &block)
irb(main):002:1>   block.call(*args)
irb(main):003:1> end
=> :foo
irb(main):004:0> 
irb(main):005:0* foo(1,2,3,4) do |*args|
irb(main):006:1*   p args.length > 0 ? "AAA" : args
irb(main):007:1> end
"AAA"
=> "AAA"

フムフム.

2018 年 06 月 15 日 (金)

ジョギング

  • 自宅→香椎神宮香椎浜
  • 引き続き, 右足 (右腰から右足全体) にかけて痛み... は, 多少, 今日は良かった

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

香椎ミートアップ

  • ということで, 香椎駅の中に出来た竹の家に行ってきた
  • 色々ワイワイ喋って楽しかったけど呑み過ぎた感

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (27) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

Ruby コマンドラインオプション

Ruby で使用可能なオプションではないものを選択する.

  • -t
  • -l
  • -p
  • -f

以下, 利用可能ではないオプション.

  • -t
  • -f

以下, 利用可能なオプション (解説より抜粋)

  • -l
    • 各行の最後に String#chop! を実行する (ドキュメントより引用: 行末の自動処理を行います。まず、$\ を $/ と同じ値に設定し, printでの出力 時に改行を付加するようにします。)
  • -p
    • -n オプションと同様に $_ を出力する
    • $_ とは, 最後に Kernel.#gets または Kernel.#readline で読み込んだ文字列です。 (ドキュメントより引用)

以下, 実行例.

# 通常は print を利用する場合, 改行は付加されない
$ ruby -e 'print "01234567890"'
01234567890$
# -l オプションを付けると, print を利用した際に改行を付加する
$ ruby -l -e 'print "01234567890"'
01234567890
# -p オプションのサンプル
$ echo foo | ruby -p -e '$_.tr! "a-z", "A-Z"'
FOO
# ちなみに, -n オプションは以下のような挙動となる
$ echo 'foo' | ruby -n -e 'print'
foo

Enumerator::Lazy

以下のコードは Enumerator::Lazy を利用している. 先頭から 5 つの値を取り出す為にはどのメソッドが必要か.

(1..100).each.lazy.chunk(&:even?)

以下, 解答.

take(5).force first(5)

以下, irb による実行例.

irb(main):001:0> (1..100).each.lazy.chunk(&:even?)
=> #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x0055758c2a6dc0>:each>>
irb(main):002:0> (1..100).each.lazy.chunk(&:even?).first(5)
=> [[false, [1]], [true, [2]], [false, [3]], [true, [4]], [false, [5]]]
irb(main):003:0> (1..100).each.lazy.chunk(&:even?).take(5)
=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x0055758c24f048>:each>>:take(5)>
irb(main):004:0> (1..100).each.lazy.chunk(&:even?).take(5).force
=> [[false, [1]], [true, [2]], [false, [3]], [true, [4]], [false, [5]]]
irb(main):006:0> (1..100).each.lazy.chunk(&:even?).force.take(5)
=> [[false, [1]], [true, [2]], [false, [3]], [true, [4]], [false, [5]]]
irb(main):007:0> (1..100).each.lazy.chunk(&:even?).first
=> [false, [1]]
irb(main):008:0> (1..100).each.lazy.chunk(&:even?).force.first(5)
=> [[false, [1]], [true, [2]], [false, [3]], [true, [4]], [false, [5]]]

以下, 解説より抜粋.

  • 単純に値を取り出すには, Enumerator::Lazy#force 又は Enumerator::Lazy#first を利用する
  • 設問では, 「先頭から 5 つの値」とあるので, first(5) を利用する
  • Enumerator::Lazy#force は全ての値を取り出す (全ての要素を含む配列を返す) が, 5 つの値を取り出す為には Enumerator::Lazy#take 又は Enumerator::Lazy#first を利用する
  • Enumerator::Lazy#takeEnumerable#take と異なり, Enumerator::Lazyインスタンスを戻り値となる為, Enumerator::Lazy#force で実際の値を取り出す

フムフム.

2018 年 06 月 14 日 (木)

ジョギング

  • 自宅→香椎神宮香椎浜
  • 引き続き, 右足 (右腰から右足全体) にかけて痛み... は, 多少, 今日は良かった

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

夕飯

  • AJINOMOTO の冷凍餃子, タコ刺し (絶品), 枝豆

ひとやま

  • 奥さん, ギョームにてひとやま越えたらしい
  • おつかれさま

体調

  • 終日イマイチ...
  • ホントに加齢を感じる今日このごろ

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (26) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

Mix-in

以下のコードを実行するとどうなるか.

module M
  def class_m
    "class_m"
  end
end

class C
  include M
end

p C.methods.include? :class_m

false

以下, irb にて確認.

irb(main):001:0> module M
irb(main):002:1>   def class_m
irb(main):003:2>     "class_m"
irb(main):004:2>   end
irb(main):005:1> end
=> :class_m
irb(main):006:0> 
irb(main):007:0* class C
irb(main):008:1>   include M
irb(main):009:1> end
=> C
irb(main):010:0> 
irb(main):011:0* p C.methods.include? :class_m
false
=> false

以下, 解説より抜粋.

  • include は Module のインスタンスメソッドを Mix-in するメソッド
  • C.methods は C の特異メソッドを表示する

従って, C#class_mインスタンスメソッドとなり, C.methods では表示されないが, 以下のようにインスタンス化することで, true インスタンスメソッドとなり true となる.

irb(main):012:0> p C.new.methods.include? :class_m
true
=> true

インスタンスメソッド, 特異メソッド

以下のコードを実行するとどうなるか.

class Cls
  class << Cls
    def foo
      'foo'
    end
  end

  def foo
    'FOO'
  end
end

p Cls.new.foo

FOO

以下, irb による確認.

irb(main):001:0> class Cls
irb(main):002:1>   class << Cls
irb(main):003:2>     def foo
irb(main):004:3>       'foo'
irb(main):005:3>     end
irb(main):006:2>   end
irb(main):007:1> 
irb(main):008:1*   def foo
irb(main):009:2>     'FOO'
irb(main):010:2>   end
irb(main):011:1> end
=> :foo
irb(main):012:0> 
irb(main):013:0* p Cls.new.foo
"FOO"
=> "FOO"

以下, 解説より抜粋.

  • 特異クラス内 class << Cls; end に宣言されたメソッドは特異メソッドとなる
  • 特異メソッドは def Cls.foo: end でも宣言することも出来る
  • 設問コードでは, インスタンスを作成しそのメソッドを呼び出している為, インスタンスメソッドの FOO を返すメソッドが呼ばれる

以下のように書くと foo が出力される.

irb(main):014:0> p Cls.foo
"foo"
=> "foo"

フムフム.

2018 年 06 月 13 日 (水)

ジョギング

  • 自宅→香椎神宮香椎浜
  • 引き続き, 右足 (右腰から右足全体) にかけて痛み... 日に日にひどくなる感じ...
  • ストレッチでごまかす

日課

  • 休み

fukuoka.rb

fukuokarb.connpass.com

に参加した.

以下の 2 つのプルリクエストをこさえた.

github.com

github.com

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (26) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

引き続き, class_eval による定数参照

以下のコードは Hello, world を表示する. 同じ結果となるコードを複数選択する.

module M
  CONST = "Hello, world"

  class C
    def awesome_method
      CONST
    end
  end
end

p M::C.new.awesome_method

以下, 解答.

# 解答(1)
class C
end

module M
  CONST = "Hello, world"

  C.class_eval do
    def awesome_method
      CONST
    end
  end
end

p C.new.awesome_method

# 解答 (2)
class C
  CONST = "Hello, world"
end

module M
  C.class_eval(<<-CODE)
    def awesome_method
      CONST
    end
  CODE
end

p C.new.awesome_method

以下, irb にて確認.

# 設問コード
irb(main):001:0> module M
irb(main):002:1>   CONST = "Hello, world"
irb(main):003:1> 
irb(main):004:1*   class C
irb(main):005:2>     def awesome_method
irb(main):006:3>       CONST
irb(main):007:3>     end
irb(main):008:2>   end
irb(main):009:1> end
=> :awesome_method
irb(main):010:0> 
irb(main):011:0* p M::C.new.awesome_method
"Hello, world"
=> "Hello, world"

# 解答(1)
irb(main):001:0> class C
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module M
irb(main):005:1>   CONST = "Hello, world"
irb(main):006:1> 
irb(main):007:1*   C.class_eval do
irb(main):008:2*     def awesome_method
irb(main):009:3>       CONST
irb(main):010:3>     end
irb(main):011:2>   end
irb(main):012:1> end
=> :awesome_method
irb(main):013:0> 
irb(main):014:0* p C.new.awesome_method
"Hello, world"
=> "Hello, world"


# 解答(2)
irb(main):001:0> class C
irb(main):002:1>   CONST = "Hello, world"
irb(main):003:1> end
=> "Hello, world"
irb(main):004:0> 
irb(main):005:0* module M
irb(main):006:1>   C.class_eval(<<-CODE)
irb(main):007:2"     def awesome_method
irb(main):008:2"       CONST
irb(main):009:2"     end
irb(main):010:2"   CODE
irb(main):011:1> end
=> :awesome_method
irb(main):012:0> 
irb(main):013:0* p C.new.awesome_method
"Hello, world"
=> "Hello, world"

以下, 解説より抜粋.

  • 解答 (1)
    • class_eval にブロックを渡した場合は, ブロック内のネストはモジュール M になる
    • そのコンテキストから定数を探索するので "Hello, world" が表示される
  • 解答 (2)
    • class_eval に文字列を渡した場合のネストの状態はクラス C となる
    • CONST はクラス C にある為, "Hello, world" が表示される

念の為, ブロックで渡した場合と, 文字列で渡した場合のネストの状態を確認してみる.

# class_eval のブロック渡し
irb(main):001:0> class C
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module M
irb(main):005:1>   C.class_eval do
irb(main):006:2*     Module.nesting
irb(main):007:2>   end
irb(main):008:1> end
=> [M]
irb(main):009:0> exit

# class_eval の文字列渡し
irb(main):001:0> class C
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module M
irb(main):005:1>   C.class_eval(<<-CODE)
irb(main):006:2"     Module.nesting
irb(main):007:2"   CODE
irb(main):008:1> end
=> [C, M]

上記のように, ネストの状態が異なる為, 定数を探索するコンテキストも異なることが解る.

フムフム.