ようへいの日々精進XP

よかろうもん

2018 年 07 月 02 日 (月)

ジョギング

日課

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

体調不良

  • 終日眠気と体のだるさで辛かった

今日のるびぃ ~ だいぶん古いけど, 「Ruby 2.0 最速入門」という記事を写経する (1) ~

だいぶん古い WEB+DB Press Vol.73 の「一歩先ゆく Ruby」というコーナーで「Ruby 2.0 最速入門」という記事が試験にあたって参考になりそうだったので写経する. 尚, irb に動作確認環境は以下の通り.

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

include と prepend

メソッド探索の基本

以下のようなコードがあったとする.

class Mammal
  def have_backbone?
    true
  end

  def live_in_water?
    false
  end
end

class Dog < Mammal
end

上記の場合, Dog インスタンスを作成すると, Mammal を継承している為,

  • have_backbone? は true
  • live_in_water? は false

となる. 以下, irb にて確認した例.

irb(main):014:0> class Mammal
irb(main):015:1>   def have_backbone?
irb(main):016:2>     true
irb(main):017:2>   end
irb(main):018:1> 
irb(main):019:1*   def live_in_water?
irb(main):020:2>     false
irb(main):021:2>   end
irb(main):022:1> end
=> :live_in_water?
irb(main):023:0> 
irb(main):024:0* class Dog < Mammal
irb(main):025:1> end
=> nil
irb(main):030:0> Dog.new.have_backbone?
=> true
irb(main):031:0> Dog.new.live_in_water?
=> false

include

Dolphin というクラスの場合, live_in_water? では true を返したいので Mammal クラスの実装では問題がある為, Swimmable モジュールを利用する.

module Swimmable
  def live_in_water?
    true
  end
end

class Dolphin < Mammal
  def live_in_water?
    super
  end
  include Swimmable
end

以下, irb にて確認.

irb(main):032:0> module Swimmable
irb(main):033:1>   def live_in_water?
irb(main):034:2>     true
irb(main):035:2>   end
irb(main):036:1> end
=> :live_in_water?
irb(main):037:0> 
irb(main):038:0* class Dolphin < Mammal
irb(main):039:1>   include Swimmable
irb(main):040:1> end
=> Dolphin
irb(main):041:0> Dolphin.new.have_backbone?
=> true
irb(main):042:0> Dolphin.new.live_in_water?
=> true

メソッドは以下のような順番で探索される.

  1. Dolphin クラスのインスタンスメソッド
  2. Swimmable モジュールのメソッド
  3. Mammal クラスのインスタンスメソッド

prepend

colors というメソッドを定義した場合.

class Dolphin < Mammal
  def colors
    ['Gray']
  end
end

以下, irb にて確認.

irb(main):067:0> class Dolphin < Mammal
irb(main):068:1>   def colors
irb(main):069:2>     ['Gray']
irb(main):070:2>   end
irb(main):071:1> end
=> :colors
irb(main):072:0> Dolphin.new.colors
=> ["Gray"]

白いイルカが発見された場合, 以下のようにモンキーパッチを適用することで対応出来る.

class Dolphin < Mammal
  def colors
    ['White', 'Gray']
  end
end

以下, irb にて確認.

irb(main):073:0> class Dolphin < Mammal
irb(main):074:1>   def colors
irb(main):075:2>     ['White', 'Gray']
irb(main):076:2>   end
irb(main):077:1> end
=> :colors
irb(main):078:0> Dolphin.new.colors
=> ["White", "Gray"]

モンキーパッチではなく, 別途モジュールを用意して prepend を利用して解決する.

module WithColorWhite
  def colors
    ['White'] + super
  end
end

class Dolphin < Mammal
  prepend WithColorWhite
end

以下, irb にて確認.

irb(main):079:0> class Dolphin < Mammal
irb(main):080:1>   def colors
irb(main):081:2>     ['Gray']
irb(main):082:2>   end
irb(main):083:1> end
=> :colors
irb(main):084:0> Dolphin.new.colors
=> ["Gray"]
irb(main):085:0> module WithColorWhite
irb(main):086:1>   def colors
irb(main):087:2>     ['White'] + super
irb(main):088:2>   end
irb(main):089:1> end
=> :colors
irb(main):090:0> class Dolphin < Mammal
irb(main):091:1>   prepend WithColorWhite
irb(main):092:1> end
=> Dolphin
irb(main):093:0> Dolphin.new.colors
=> ["White", "Gray"]

prepend を利用した場合, メソッドは以下のような順番で探索され, Dolphin クラスで定義されている colors メソッドを super で参照出来る.

  1. WithColorWhite モジュールのメソッド
  2. Dolphin クラスのインスタンスメソッド
  3. Swimmable モジュールのメソッド
  4. Mammal クラスのインスタンスメソッド

フムフム.

2018 年 07 月 01 日 (日)

ジョギング

日課

  • おやすみ

博多デート

  • お中元やら炊飯器, トースター, バリカン等電化製品を買い揃えたりした

今日のるびぃ ~ だいぶん古いけど, 「Ruby 2.0 最速入門」という記事を写経する (1) ~

だいぶん古い WEB+DB Press Vol.73 の「一歩先ゆく Ruby」というコーナーで「Ruby 2.0 最速入門」という記事が試験にあたって参考になりそうだったので写経する. 尚, irb に動作確認環境は以下の通り.

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

Enumerator::Lazy

Enumerator::Lazy とは, 遅延リストを手軽に導入し, 操作する為の仕組み.

irb(main):001:0> require 'date'
=> true
irb(main):002:0> def each_fridays
irb(main):003:1>   friday = Date.new(2018, 6, 29)
irb(main):004:1>   loop do 
irb(main):005:2*     yield friday
irb(main):006:2>     friday += 7
irb(main):007:2>   end
irb(main):008:1> end
=> :each_fridays
irb(main):009:0> fridays = enum_for(:each_fridays)
=> #<Enumerator: main:each_fridays>

上記のように enum_for を利用することで, each_fridays から Enumerator オブジェクトを生成することが出来る. 以下のように Enumerable#first を使うことで, 最初の 5 つの要素だけを取り出すことが出来る.

irb(main):013:0> puts fridays.first(5)
2018-06-29
2018-07-06
2018-07-13
2018-07-20
2018-07-27
=> nil

Enumerable#mapEnumerable#select を使って絞り込み等を行う場合, Object#each_friday ではいつまで経っても処理が終わらないことになる. これは mapselect 等のメソッドが, 配列全ての要素に対して処理を行う前提となっている為である.

irb(main):014:0> fridays.select {|d| d.day == 13 }.first(5)




... ループ ...

この状態を解決する為, Enumerator::Lazy を利用する.

irb(main):016:0> puts fridays.lazy.select {|d| d.day == 13 }.first(5)
2018-07-13
2019-09-13
2019-12-13
2020-03-13
2020-11-13
=> nil

Enumerator::Lazy を利用することで, その各要素を実際に計算する前に mapselect 等の配列に対する操作をメソッドチェインで書き連ねていくことが出来る. 尚, 操作した結果は Enumerator::Lazy となる為, 要素を取り出す為には force メソッドを呼び出す必要がある.

irb(main):020:0> puts fridays.lazy.select {|d| d.day == 13 }.take(5).force
2018-07-13
2019-09-13
2019-12-13
2020-03-13
2020-11-13
=> nil

もしくは, 先述のように firstinject 等の, 要素を利用せざる得ないメソッドを呼び出すことで自動的に各要素が計算される.

irb(main):021:0> puts fridays.lazy.select {|d| d.day == 13 }.first(5)
2018-07-13
2019-09-13
2019-12-13
2020-03-13
2020-11-13
=> nil

巨大なログファイルの中から一部の文字列を検索したい場合にも lazy を利用することで, 巨大な中間ファイルを用意することなく検索結果を取り出すことが出来る.

file = open('/path/to/large.log').each_line.lazy
file.select {|line|
  line ~= /FooBar/
}.each {|line|
  print line
}

Refinements

  • ある特定の状況下でのみ, 特定のクラスメソッド定義の変更を適用した状態出来る
  • モンキーパッチによるメソッドの再定義は, 影響がグローバルに及んでしまう可能性がある

以下のような単位変換のメソッドがあった場合.

class Numeric
  def inch
    self * 2.54
  end
end

以下のように利用可能.

irb(main):022:0> class Numeric
irb(main):023:1>   def inch
irb(main):024:2>     self * 2.54
irb(main):025:2>   end
irb(main):026:1> end
=> :inch
irb(main):027:0> 1.inch
=> 2.54
irb(main):028:0> 2.inch
=> 5.08

但し, この inch メソッドが他の同名メソッドに影響を与える可能性があるので, 局所的にこの inch メソッドを利用出来るようにする.

module InchAvailable
  refine Numeric do
    def inch
      self * 2.54
    end
    alias inches inch
  end
end

irb で実行してみる.

irb(main):001:0> module InchAvailable
irb(main):002:1>   refine Numeric do
irb(main):003:2*     def inch
irb(main):004:3>       self * 2.54
irb(main):005:3>     end
irb(main):006:2>     alias inches inch
irb(main):007:2>   end
irb(main):008:1> end
=> #<refinement:Numeric@InchAvailable>
# using メソッドで InchAvailable を有効化
irb(main):009:0> using InchAvailable; 1.inch
=> 2.54
# using メソッドで InchAvailable を有効化
irb(main):010:0> using InchAvailable; 2.inch
=> 5.08
# using していない場合には undefined method になる
irb(main):011:0> 1.inch
NoMethodError: undefined method `inch' for 1:Fixnum
... 略 ...

フムフム.

2018 年 06 月 30 日 (土)

ジョギング

  • お休み

日課

  • おやすみ

PyCon Kyushu 2018 Fukuoka

pycon-kyushu.connpass.com

に終日参加した.

slideship.com

この発表が一番印象に残ったというか, あー, 自分は Python 2 系と 3 系の書き方がごっちゃになってて, しかもググったコードをコピペしているだけなんだなと切なくなったのでもっと Python を勉強せねばと思った次第.

懇親会の二次会まで参加したけど, 懇親会のほとんどはデンマーク人やコロンビア人, スイス人の Pythonista 達と日本語で他愛もない話に花を咲かせた.

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

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)

Enumerator

以下のプログラムを実行すると, apple が一文字ずつ表示される. each_char を置き換えても同じ結果になるメソッドを選択肢から選ぶ.

enum = "apple".each_char

p enum.next
p enum.next
p enum.next
p enum.next
p enum.next

以下, 解答.

# 解答 1
enum = "apple".enum_for(:each_char)
# 解答 2
enum = "apple".to_enum(:each_char)

以下, irb による確認.

# 解答 1
irb(main):001:0> enum = "apple".enum_for(:each_char)
=> #<Enumerator: "apple":each_char>
irb(main):002:0> enum.next
=> "a"
irb(main):003:0> enum.next
=> "p"
irb(main):004:0> enum.next
=> "p"
irb(main):005:0> enum.next
=> "l"
irb(main):006:0> enum.next
=> "e"
irb(main):007:0> enum.next

# 解答 2
irb(main):008:0> enum = "apple".to_enum(:each_char)
=> #<Enumerator: "apple":each_char>
irb(main):009:0> enum.next
=> "a"
irb(main):010:0> enum.next
=> "p"
irb(main):011:0> enum.next
=> "p"
irb(main):012:0> enum.next
=> "l"
irb(main):013:0> enum.next
=> "e"
  • each_char にブロックを渡さない場合は, Enumerator オブジェクトが作成される
  • Enumerator オブジェクトを作成するには, Object#enum_for または Object#to_enum を利用する
  • 引数にはレシーバーに送信したいメッセージ(メソッドの呼び出し)を設定する
  • 引数を指定しない場合は, each がデフォルト値となる

String#each_char について

レシーバー文字列の各文字列に対して, 繰り返し処理を行う.

irb(main):002:0> 'hello'.each_char {|s| p s.upcase }
"H"
"E"
"L"
"L"
"O"
=> "hello"

これを enum_forto_enum で表現する.

# enum_for
irb(main):004:0> enum = 'hello'.to_enum(:each_char)
=> #<Enumerator: "hello":each_char>
irb(main):006:0> enum.each do |s|
irb(main):007:1*   p s.upcase
irb(main):008:1> end
"H"
"E"
"L"
"L"
"O"
=> "hello"

# to_enum
irb(main):009:0> enum = 'hello'.enum_for(:each_char)
=> #<Enumerator: "hello":each_char>
irb(main):010:0> enum.each do |s|
irb(main):011:1*   p s.upcase
irb(main):012:1> end
"H"
"E"
"L"
"L"
"O"
=> "hello"

例外

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

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

以下, 解説より抜粋.

  • String#+ の引数には String クラスのオブジェクトを期待する
  • 設問では引数に Symbol を渡している為, TypeError 例外が発生する
  • また, ensure は例外発生に関わらず評価される

フムフム.

2018 年 06 月 29 日 (金)

ジョギング

  • 香椎浜 x 2 周 30 分くらい
  • お昼休みに

日課

  • おやすみ

ソフトウェアテスト勉強会

fusic.connpass.com

に参加した. ワークショップを絡めて体系的にソフトウェアテストの基礎を学ぶことができた.

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

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_eval

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

module A
  B = 42

  def f
    21
  end
end

A.module_eval do
  def self.f
    p B
  end
end

B = 15

A.f

以下, 解答.

15 が表示される.

以下, irb にて確認.

irb(main):001:0> module A
irb(main):002:1>   B = 42
irb(main):003:1> 
irb(main):004:1*   def f
irb(main):005:2>     21
irb(main):006:2>   end
irb(main):007:1> end
=> :f
irb(main):008:0> 
irb(main):009:0* A.module_eval do
irb(main):010:1*   def self.f
irb(main):011:2>     p B
irb(main):012:2>   end
irb(main):013:1> end
=> :f
irb(main):014:0> 
irb(main):015:0* B = 15
=> 15
irb(main):016:0> 
irb(main):017:0* A.f
15
=> 15

以下, 解説より抜粋.

  • module_eval にブロックを渡した場合のネストの状態を確認
irb(main):018:0> A.module_eval do
irb(main):019:1*   Module.nesting
irb(main):020:1> end
=> []

ブロックで渡した場合には, トップレベルで定義されたことになっている. ちなみに, 文字列として渡した場合のネストの状態は以下の通り.

irb(main):021:0> A.module_eval <<-EOT
irb(main):022:0"   Module.nesting
irb(main):023:0" EOT
=> [A]

文字列として渡された場合には, 定義したモジュール内に定義されている.

  • トップレベルで定数を定義した場合には, Object クラスの定数となる
irb(main):001:0> B = "foo"
=> "foo"
irb(main):002:0> Object.const_get(:B)
=> "foo"

設問では, トップレベルで定義された定数を探索する為, 15 となる. ちなみに, 以下のようなコードだった場合にどうなるか.

module A
  B = 42

  def f
    21
  end
end

A.module_eval <<-EOT
  def self.f
    p B
  end
EOT

B = 15

A.f

以下, 解答.

42 が表示される.

以下, irb による確認.

irb(main):001:0> module A
irb(main):002:1>   B = 42
irb(main):003:1> 
irb(main):004:1*   def f
irb(main):005:2>     21
irb(main):006:2>   end
irb(main):007:1> end
=> :f
irb(main):008:0> 
irb(main):009:0* A.module_eval <<-EOT
irb(main):010:0"   def self.f
irb(main):011:0"     p B
irb(main):012:0"   end
irb(main):013:0" EOT
=> :f
irb(main):014:0> 
irb(main):015:0* B = 15
=> 15
irb(main):016:0> 
irb(main):017:0* A.f
42
=> 42

フムフム.

2018 年 06 月 28 日 (木)

ジョギング

  • 香椎浜 x 2 周 29 分くらい
  • ペースが速かったかな...

日課

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

風が通り抜ける場所で

  • 終日仕事をしていた
  • だいぶん涼しかった

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

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.nesting

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

module SuperMod
end

module SuperMod::BaseMod
  p Module.nesting
end

以下, 解答.

[SuperMod::BaseMod]

以下, irb にて確認.

irb(main):001:0> module SuperMod
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module SuperMod::BaseMod
irb(main):005:1>   p Module.nesting
irb(main):006:1> end
[SuperMod::BaseMod]
=> [SuperMod::BaseMod]

以下, 解説より抜粋.

  • Module.nesting はモジュールやクラスのネストの状態を表示する
  • モジュールがネストされている場合, ネストの全ての状態を表示する
  • インデントして別々に書いた場合 (module SuperMod;module BaseMod; p Module.nesting; end ;end) に比べて, プレフィックス (SuperMod::BaseMod) がある場合は内側にあるモジュールしかネストの状態は表示されない
irb(main):001:0> module SuperMod
irb(main):002:1>   p Module.nesting
irb(main):003:1> end
[SuperMod]
=> [SuperMod]
irb(main):004:0> 
irb(main):005:0* module SuperMod
irb(main):006:1>   module BaseMod
irb(main):007:2>     p Module.nesting
irb(main):008:2>   end
irb(main):009:1> end
[SuperMod::BaseMod, SuperMod]
=> [SuperMod::BaseMod, SuperMod]
irb(main):010:0> 
irb(main):011:0* module SuperMod::BaseMod
irb(main):012:1>   p Module.nesting
irb(main):013:1> end
[SuperMod::BaseMod]
=> [SuperMod::BaseMod]

変態的な定数参照

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

class Ca
  CONST = "001"
end

class Cb
  CONST = "010"
end

class Cc
  CONST = "011"
end

class Cd
  CONST = "100"
end

module M1
  class C0 < Ca
    class C1 < Cc
      class C2 < Cd
        p CONST

        class C2 < Cb
        end
      end
    end
  end
end

以下, 解答.

100 が表示される

以下, irb による確認.

... 略
irb(main):017:0* module M1
irb(main):018:1>   class C0 < Ca
irb(main):019:2>     class C1 < Cc
irb(main):020:3>       class C2 < Cd
irb(main):021:4>         p CONST
irb(main):022:4> 
irb(main):023:4*         class C2 < Cb
irb(main):024:5>         end
irb(main):025:4>       end
irb(main):026:3>     end
irb(main):027:2>   end
irb(main):028:1> end
"100"
=> nil

以下, 解説より抜粋.

  • Rubyは定数の参照はレキシカルに決定されるが, 設問ではレキシカルスコープに定数は存在しない
  • レキシカルスコープに定数が存在しない場合, スーパークラスの探索を行う

レキシカルスコープとは...

  • 変数を参照する仕様の一つ (ダイナミックスコープというのもある)
  • 他の関数のローカル変数は参照することが出来ない
  • 設問でのレキシカルスコープとは, module M1 ~ end までになるんだと思う

以下, 設問を利用して実験.

class Ca
  CONST = '001'
end

class Cb
  CONST = '002'
end

module M1
  class C0 < Ca
    class C1 < Cb
      p CONST
    end
  end
end

これを実行すると, 以下のように 002 が出力される.

... 略 ...
irb(main):008:0> 
irb(main):009:0* module M1
irb(main):010:1>   class C0 < Ca
irb(main):011:2>     class C1 < Cb
irb(main):012:3>       p CONST
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
"002"
=> "002"

では, 以下のように定数 CONST を定義した場合にどうなるか.

... 略 ...
module M1
  class C0 < Ca
    CONST = 'aaaaaaaaaaaaaa'
    class C1 < Cb
      p CONST
    end
  end
end

以下のように aaaaaaaaaaaaaa と出力される.

irb(main):016:0> module M1
irb(main):017:1>   class C0 < Ca
irb(main):018:2>     CONST = 'aaaaaaaaaaaaaa'
irb(main):019:2>     class C1 < Cb
irb(main):020:3>       p CONST
irb(main):021:3>     end
irb(main):022:2>   end
irb(main):023:1> end
"aaaaaaaaaaaaaa"
=> "aaaaaaaaaaaaaa"

これは, レキシカルスコープ内に定数が定義されていると言える. 対して, 以下のように定義した場合にどうなるか.

... 略 ...
CONST = 'aaaaaaaaaaaaaa'
module M1
  class C0 < Ca
    class C1 < Cb
      p CONST
    end
  end
end

以下のように 002 と表示される.

... 略 ...
irb(main):008:0> CONST = 'aaaaaaaaaaaaaa'
=> "aaaaaaaaaaaaaa"
irb(main):009:0> module M1
irb(main):010:1>   class C0 < Ca
irb(main):011:2>     class C1 < Cb
irb(main):012:3>       p CONST
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
"002"
=> "002"

これは, 定数がレキシカルスコープに無い為, スーパークラスを探索して定数を参照している.

フムフム.

2018 年 06 月 27 日 (水)

ジョギング

  • 自宅→香椎宮香椎浜で 35 分くらい
  • 左足足底筋の痛み
  • 右足膝周り痛い
  • 蒸し暑い

日課

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

体調

  • 昨日よりはマシ

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

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.nesting

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

module SuperMod
end

module SuperMod::BaseMod
  p Module.nesting
end

以下, 解答.

[SuperMod::BaseMod]

以下, irb にて確認.

irb(main):001:0> module SuperMod
irb(main):002:1> end
=> nil
irb(main):003:0> 
irb(main):004:0* module SuperMod::BaseMod
irb(main):005:1>   p Module.nesting
irb(main):006:1> end
[SuperMod::BaseMod]
=> [SuperMod::BaseMod]

以下, 解説より抜粋.

  • Module.nesting はモジュールやクラスのネストの状態を表示する
  • モジュールがネストされている場合, ネストの全ての状態を表示する
  • インデントして別々に書いた場合 (module SuperMod;module BaseMod; p Module.nesting; end ;end) に比べて, プレフィックス (SuperMod::BaseMod) がある場合は内側にあるモジュールしかネストの状態は表示されない
irb(main):001:0> module SuperMod
irb(main):002:1>   p Module.nesting
irb(main):003:1> end
[SuperMod]
=> [SuperMod]
irb(main):004:0> 
irb(main):005:0* module SuperMod
irb(main):006:1>   module BaseMod
irb(main):007:2>     p Module.nesting
irb(main):008:2>   end
irb(main):009:1> end
[SuperMod::BaseMod, SuperMod]
=> [SuperMod::BaseMod, SuperMod]
irb(main):010:0> 
irb(main):011:0* module SuperMod::BaseMod
irb(main):012:1>   p Module.nesting
irb(main):013:1> end
[SuperMod::BaseMod]
=> [SuperMod::BaseMod]

変態的な定数参照

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

class Ca
  CONST = "001"
end

class Cb
  CONST = "010"
end

class Cc
  CONST = "011"
end

class Cd
  CONST = "100"
end

module M1
  class C0 < Ca
    class C1 < Cc
      class C2 < Cd
        p CONST

        class C2 < Cb
        end
      end
    end
  end
end

以下, 解答.

100 が表示される

以下, irb による確認.

... 略
irb(main):017:0* module M1
irb(main):018:1>   class C0 < Ca
irb(main):019:2>     class C1 < Cc
irb(main):020:3>       class C2 < Cd
irb(main):021:4>         p CONST
irb(main):022:4> 
irb(main):023:4*         class C2 < Cb
irb(main):024:5>         end
irb(main):025:4>       end
irb(main):026:3>     end
irb(main):027:2>   end
irb(main):028:1> end
"100"
=> nil

以下, 解説より抜粋.

  • Rubyは定数の参照はレキシカルに決定されるが, 設問ではレキシカルスコープに定数は存在しない
  • レキシカルスコープに定数が存在しない場合, スーパークラスの探索を行う

レキシカルスコープとは...

  • 変数を参照する仕様の一つ (ダイナミックスコープというのもある)
  • 他の関数のローカル変数は参照することが出来ない
  • 設問でのレキシカルスコープとは, module M1 ~ end までになるんだと思う

以下, 設問を利用して実験.

class Ca
  CONST = '001'
end

class Cb
  CONST = '002'
end

module M1
  class C0 < Ca
    class C1 < Cb
      p CONST
    end
  end
end

これを実行すると, 以下のように 002 が出力される.

... 略 ...
irb(main):008:0> 
irb(main):009:0* module M1
irb(main):010:1>   class C0 < Ca
irb(main):011:2>     class C1 < Cb
irb(main):012:3>       p CONST
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
"002"
=> "002"

では, 以下のように定数 CONST を定義した場合にどうなるか.

... 略 ...
module M1
  class C0 < Ca
    CONST = 'aaaaaaaaaaaaaa'
    class C1 < Cb
      p CONST
    end
  end
end

以下のように aaaaaaaaaaaaaa と出力される.

irb(main):016:0> module M1
irb(main):017:1>   class C0 < Ca
irb(main):018:2>     CONST = 'aaaaaaaaaaaaaa'
irb(main):019:2>     class C1 < Cb
irb(main):020:3>       p CONST
irb(main):021:3>     end
irb(main):022:2>   end
irb(main):023:1> end
"aaaaaaaaaaaaaa"
=> "aaaaaaaaaaaaaa"

これは, レキシカルスコープ内に定数が定義されていると言える. 対して, 以下のように定義した場合にどうなるか.

... 略 ...
CONST = 'aaaaaaaaaaaaaa'
module M1
  class C0 < Ca
    class C1 < Cb
      p CONST
    end
  end
end

以下のように 002 と表示される.

... 略 ...
irb(main):008:0> CONST = 'aaaaaaaaaaaaaa'
=> "aaaaaaaaaaaaaa"
irb(main):009:0> module M1
irb(main):010:1>   class C0 < Ca
irb(main):011:2>     class C1 < Cb
irb(main):012:3>       p CONST
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
"002"
=> "002"

これは, 定数がレキシカルスコープに無い為, スーパークラスを探索して定数を参照している.

フムフム.

2018 年 06 月 26 日 (火)

ジョギング

  • 自宅→香椎宮香椎浜で 35 分くらい
  • 左足足底筋の痛み
  • 蒸し暑い
  • 明日は休もうかな...

日課

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

体調

  • 悪し
  • 暑さにやられた感がある

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

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)

正規表現

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

p "This is a aPPle"[/[a-z][A-Z].*/]

以下, 解答.

aPPle が表示される

以下, irb にて確認.

irb(main):017:0> p "This is a aPPle"[/[a-z][A-Z].*/]
"aPPle"
=> "aPPle"

以下, 解説より抜粋.

  • スラッシュ / で囲まれた文字列は正規表現と扱われる
  • 設問では, 文字列から String#[]正規表現を用いて部分文字列を抜き取る
  • 設問の正規表現 /[a-z][A-Z].*/ を分解すると以下のような意味となる
    • [a-z]: 1文字目が小文字英字
    • [A-Z]: 2文字目が大文字英字
    • .*: 任意の1文字が0回以上繰り返す

Regexp#match

Regexp#match を試す.

指定された文字列 str に対して位置 pos から自身が表す正規表現によるマッ チングを行います。マッチした場合には結果を MatchData オブジェクトで返し ます。 マッチしなかった場合 nil を返します。

irb(main):022:0> p "This is a aPPle".match(/[a-z][A-Z].*/)
#<MatchData "aPPle">
=> #<MatchData "aPPle">

正規表現にマッチした部分文字列だけが必要な場合, 以下のように書くことで取得出来る.

irb(main):023:0> bar = /foo(.*)baz/.match("foobarbaz")
=> #<MatchData "foobarbaz" 1:"bar">
irb(main):024:0> bar = /foo(.*)baz/.match("foobarbaz").to_a[0]
=> "foobarbaz"
irb(main):025:0> bar = /foo(.*)baz/.match("foobarbaz").to_a[1]
=> "bar"
irb(main):027:0> /(foo)(bar)(baz)/.match("foobarbaz").to_a.values_at(1,2,3)
=> ["foo", "bar", "baz"]

String#[]

String#[] を試す.

nth 番目の文字を返します。 nth が負の場合は文字列の末尾から数えます。 つまり、 self.size + nth 番目の文字を返します。 nth が範囲外を指す場合は nil を返します。

irb(main):029:0> 'bar'[-1]
=> "r"
irb(main):030:0> 'bar'[0]
=> "b"
irb(main):031:0> 'bar'[1]
=> "a"
irb(main):032:0> 'bar'[2]
=> "r"

正規表現 regexp の nth 番目の括弧にマッチする最初の部分文字列を返します。 nth を省略したときや 0 の場合は正規表現がマッチした部分文字列全体を返します。 正規表現が self にマッチしなかった場合や nth に対応する括弧がないときは nil を返します。

このメソッドを実行すると、 マッチ結果に関する情報が組み込み変数 $~ に設定されます。

irb(main):037:0> 'foo bar baz'[/f.o/]
=> "foo"
irb(main):038:0> $~
=> #<MatchData "foo">
irb(main):039:0> $~.to_a
=> ["foo"]

Object クラス

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

class Object
  CONST = "1"
  def const_succ
    CONST.next!
  end
end

class Child1
  const_succ
  class << self
    const_succ
  end
end

class Child2
  const_succ
  def initialize
    const_succ
  end
end

Child1.new
Child2.new

p Object::CONST

以下, 解答.

5 が表示される

以下, irb による確認.

irb(main):001:0> class Object
irb(main):002:1>   CONST = "1"
irb(main):003:1>   def const_succ
irb(main):004:2>     CONST.next!
irb(main):005:2>   end
irb(main):006:1> end
=> :const_succ
irb(main):007:0> 
irb(main):008:0* class Child1
irb(main):009:1>   const_succ
irb(main):010:1>   class << self
irb(main):011:2>     const_succ
irb(main):012:2>   end
irb(main):013:1> end
=> "3"
irb(main):014:0> 
irb(main):015:0* class Child2
irb(main):016:1>   const_succ
irb(main):017:1>   def initialize
irb(main):018:2>     const_succ
irb(main):019:2>   end
irb(main):020:1> end
=> :initialize
irb(main):021:0> 
irb(main):022:0* Child1.new
=> #<Child1:0x0056408aab6190>
irb(main):023:0> Child2.new
=> #<Child2:0x0056408aaae990>
irb(main):024:0> 
irb(main):025:0* p Object::CONST
"5"
=> "5"

以下, 解説より抜粋.

  • Object クラスにメソッドを定義すると特異クラスでもそのメソッドを利用することが出来る
  • Object#const_succ について, 内部で String#next! を実行している為, レシーバーの文字列を次の文字列へ進める

以下, クラス定義毎に Object::CONST の値を確認.

irb(main):001:0> class Object
irb(main):002:1>   CONST = "1"
irb(main):003:1>   def const_succ
irb(main):004:2>     CONST.succ!
irb(main):005:2>   end
irb(main):006:1> end
=> :const_succ
irb(main):007:0> p Object::CONST
"1"
=> "1"
irb(main):008:0> class Child1
irb(main):009:1>   const_succ
irb(main):010:1>   class << self
irb(main):011:2>     const_succ
irb(main):012:2>   end
irb(main):013:1> end
=> "3"
irb(main):014:0> p Object::CONST          
"3"
=> "3"
irb(main):015:0> class Child2
irb(main):016:1>   const_succ
irb(main):017:1>   def initialize
irb(main):018:2>     const_succ
irb(main):019:2>   end
irb(main):020:1> end
=> :initialize
irb(main):021:0> p Object::CONS                       
"4"
=> "4"
irb(main):022:0> Child1.new
=> #<Child1:0x0056352f061778>
irb(main):023:0> p Object::CONST
"4"
=> "4"
irb(main):026:0> Child2.new                        
=> #<Child2:0x0056352ef600b8>
irb(main):027:0> p Object::CONST
"5"
=> "5"

また, Object クラスではなく, 任意のクラス (Foo) を定義した場合の挙動を確認.

irb(main):001:0> class Foo
irb(main):002:1>   CONST = "1"
irb(main):003:1>   def const_succ
irb(main):004:2>     CONST.next!
irb(main):005:2>   end
irb(main):006:1> end
=> :const_succ
irb(main):010:0> class Bar
irb(main):011:1>   class << self
irb(main):012:2>     const_succ
irb(main):013:2>   end
irb(main):014:1> end
NameError: undefined local variable or method `const_succ' for #<Class:Bar>
...

上記のように, 特異メソッドを定義しようとしても例外となる.

フムフム.

2018 年 06 月 25 日 (月)

ジョギング

  • 自宅→香椎宮香椎浜で 30 分くらい
  • 左足足底筋に違和感というか痛み
  • 蒸し暑い
  • そろそろ T シャツで走ってもいいかもしれない

日課

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

Github (Github Enterprise) のカンバン機能を使い始めた

  • 今日中にやらんといかん事, 進行中の作業, ペンディングにしている作業等をうまーく纏めたかったので Github のカンバン機能 (Projects) を使い始めた
  • ポストイットでペタペタ貼る感じでとりあえず使ってみようと思う
  • Backlog の課題と連携出来る方法ないのかなー
    • 課題が丸っと 1 つのカラムに 1 つのカードとして追加される感じ
    • Github の issue では出来ているんだけど, issue は Backlog 課題との二重管理になるので利用していないしな...

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

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)

% 記法

実行結果にある結果を得るように __(1)__ に適したコードを選ぶ.

# コード
arr = __(1)__
arr.each do |i|
  p i
end

# 実行結果
apple
banana
orange

以下, 解答.

%w/apple banana orange/

以下, irb にて確認.

irb(main):001:0> arr = %w/apple banana orange/
=> ["apple", "banana", "orange"]
irb(main):002:0> arr.each do |i|
irb(main):003:1*   p i
irb(main):004:1> end
"apple"
"banana"
"orange"
=> ["apple", "banana", "orange"]
irb(main):005:0> 

以下, その他の選択肢について.

  • %a/ /: このような記法はありません
irb(main):005:0> %a/apple banana orange/
SyntaxError: (irb):5: unknown type of %string
  • %/ /: ダブルクォート文字列 (%Q/ /)
irb(main):001:0> %/apple banana orange/
=> "apple banana orange"
irb(main):032:0> %Q/apple banana orange/
=> "apple banana orange"
irb(main):002:0> %r/apple banana orange/
=> /apple banana orange/
irb(main):011:0> %/apple banana orange/.match(%r/apple/)
=> #<MatchData "apple">
irb(main):012:0> %/apple banana orange/.match(%r/banana/)
=> #<MatchData "banana">
irb(main):013:0> %/apple banana orange/.match(%r/orange/)
=> #<MatchData "orange">
  • %w/ /: 要素が文字列の配列
irb(main):031:0> %w/apple banana orange/
=> ["apple", "banana", "orange"]
irb(main):014:0> %w/apple banana \orange/
=> ["apple", "banana", "\\orange"]

その他の % 記法.

  • %W/ /: 要素が文字列の配列, 式展開, バックスラッシュ記法が有効
irb(main):031:0> %w/apple banana orange/
=> ["apple", "banana", "orange"]
irb(main):013:0> %W/apple banana \orange/
=> ["apple", "banana", "orange"]
  • %q/ /: シングルクォート文字列
irb(main):001:0> %q/apple banana orange/
=> "apple banana orange"

シングルクォートって書かれているけど, シングルクォートの出力を確認出来なかった...

  • %x/ /: コマンド出力 (コマンドを実行出来る)
irb(main):002:0> %x/date/
=> "2018年  6月 20日 水曜日 08:48:35 JST\n"
irb(main):003:0> %x/ruby --version/
=> "ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]\n"
irb(main):004:0> `ruby --version`
=> "ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]\n"
irb(main):005:0> `date`
=> "2018年  6月 20日 水曜日 08:49:44 JST\n"
  • %s/ /: シンボル
irb(main):006:0> %s/apple banana orange/
=> :"apple banana orange"
  • %i/ /: 要素がシンボルの配列 (空白区切り)
irb(main):008:0> %i/apple banana orange/
=> [:apple, :banana, :orange]
irb(main):014:0> %w/apple banana \orange/
=> ["apple", "banana", "\\orange"]
  • %I/ /: 要素がシンボルの配列 (空白区切り), 式展開, バックスラッシュ記法が有効
irb(main):009:0> %I/apple banana orange/
=> [:apple, :banana, :orange]
=> ["apple", "banana", "\\orange"]

フムフム.

2018 年 06 月 24 日 (日)

ジョギング

  • 嬉野の街を 45 分くらい
  • 宿泊していたホテルから椎葉山荘 に登って, お茶畑を周りに見ながら走った
  • 気持ち良かった

日課

  • お休み

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

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)

Enumerator クラス

以下のプログラムの __(1)__ に適切な内容を選択して実行すると, [97, 112, 112, 108, 101] と表示される. 期待した結果を得られるように正しい選択肢を選ぶ.

enum_char = Enumerator.new do |yielder|
  "apple".each_char do |chr|
    __(1)__
  end
end

array = enum_char.map do |chr|
  chr.ord
end

p array

以下, irb にて確認.

irb(main):001:0> enum_char = Enumerator.new do |yielder|
irb(main):002:1*   "apple".each_char do |chr|
irb(main):003:2*     yielder << chr
irb(main):004:2>   end
irb(main):005:1> end
=> #<Enumerator: #<Enumerator::Generator:0x00558ba63f9468>:each>
irb(main):006:0> 
irb(main):007:0* array = enum_char.map do |chr|
irb(main):008:1*   chr.ord
irb(main):009:1> end
=> [97, 112, 112, 108, 101]
irb(main):010:0> 
irb(main):011:0* p array
[97, 112, 112, 108, 101]
=> [97, 112, 112, 108, 101]

以下, 解説より抜粋.

  • map メソッドのブロックは Enumerator オブジェクトをレシーバーとした場合 Enumerator::Yielder オブジェクトとなり, 設問では変数 yielder を指す
  • Enumerator::Yielder を評価するには, << を呼び出す

Enumerator クラスをも少し突っ込んで (ドキュメントを参考に)

Enumerator クラスとは

  • each 以外のメソッドにも Enumerable の機能を提供するためのラッパークラス
  • Enumerator を生成するには Enumerator.new あるいは Object#to_enum, Object#enum_for を利用する

そもそも Enumerable クラスとは

  • 繰り返しを行なうクラスのための Mix-in
  • このモジュールのメソッドは全て each を用いて定義されているので, インクルードするクラスには each が定義されている必要がある

Enumerator.new について

new(obj, method = :each, *args) -> Enumerator

  • オブジェクト obj について, each の代わりに method という 名前のメソッドを使って繰り返すオブジェクトを生成して返す
  • args を指定すると, method の呼び出し時に渡される
irb(main):001:0> str = "xyz"
irb(main):003:0* enum = Enumerator.new(str, :each_byte)
(irb):3: warning: Enumerator.new without a block is deprecated; use Object#to_enum
=> #<Enumerator: "xyz":each_byte>
irb(main):004:0> enum.class
=> Enumerator
irb(main):007:0> enum.map {|b| '%02x' % b }
=> ["78", "79", "7a"]

new(size=nil) {|y| ... } -> Enumerator

  • Enumerator オブジェクトを生成して返す
  • 与えられたブロックは Enumerator::Yielder オブジェクトを引数 (以下の例では y が該当する) として実行される
  • 生成された Enumerator オブジェクトに対して each を呼ぶと, この生成時に指定されたブロック ((1..10).each{|i|...) を実行し, Yielder オブジェクトに対して << メソッドが呼ばれるたびに, each に渡されたブロックが繰り返される
  • new に渡されたブロックが終了した時点で each の繰り返しが終了し, このときのブロックの返り値が each の返り値となる
irb(main):001:0> enum = Enumerator.new{|y|
irb(main):002:1*   (1..10).each{|i|
irb(main):003:2*     y << i if i % 5 == 0
irb(main):004:2>   }
irb(main):005:1> }
=> #<Enumerator: #<Enumerator::Generator:0x0055620e1400f8>:each>
irb(main):006:0> enum.each{|i| p i }
5
10
=> 1..10
irb(main):007:0> fib = Enumerator.new { |y|
irb(main):008:1*   a = b = 1
irb(main):009:1>   loop {
irb(main):010:2*     y << a
irb(main):011:2>     a, b = b, a + b
irb(main):012:2>   }
irb(main):013:1> }
=> #<Enumerator: #<Enumerator::Generator:0x0055620e0dbec8>:each>
irb(main):014:0> p fib.take(10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

以下, Object#enum_forObject#to_enum について.

Object#enum_forObject#to_enum についても, Enumerator.new と同様に Enumerator オブジェクトを返す. 以下, ドキュメントより引用.

irb(main):011:0* enum = str.enum_for(:each_byte)
=> #<Enumerator: "xyz":each_byte>
irb(main):012:0> p(a = enum.map{|b| '%02x' % b })
["78", "79", "7a"]
=> ["78", "79", "7a"]
irb(main):013:0> enum = str.to_enum(:each_byte)
=> #<Enumerator: "xyz":each_byte>
irb(main):014:0> p(a = enum.map{|b| '%02x' % b })
["78", "79", "7a"]
=> ["78", "79", "7a"]

以下, ブロックを指定する場合.

irb(main):001:0> module Enumerable
irb(main):002:1>   def repeat(n)
irb(main):003:2>     raise ArgumentError, "#{n} is negative!" if n < 0
irb(main):004:2>     unless block_given?
irb(main):005:3>       # __method__ はここでは :repeat
irb(main):006:3*       return enum_for(__method__, n) do # return to_enum(__method__, n) でも同義
irb(main):007:4*         # size メソッドが nil でなければ size * n を返す。
irb(main):008:4*         sz = size
irb(main):009:4>         sz * n if sz
irb(main):010:4>       end
irb(main):011:3>     end
irb(main):012:2>     each do |*val|
irb(main):013:3*       n.times { yield *val }
irb(main):014:3>     end
irb(main):015:2>   end
irb(main):016:1> end
=> :repeat
irb(main):017:0> %i[hello world].repeat(2) { |w| puts w }
hello
hello
world
world
=> [:hello, :world]
irb(main):018:0> enum = (1..14).repeat(3)
=> #<Enumerator: 1..14:repeat(3)>
irb(main):019:0> enum.first(4)
=> [1, 1, 1, 2]
irb(main):020:0> enum.first(10)
=> [1, 1, 1, 2, 2, 2, 3, 3, 3, 4]
irb(main):021:0> enum.size
=> 42

フムフム.

2018 年 06 月 23 日 (土)

ジョギング

日課

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

結婚式 6 周年

ちょっと早いけど, 結婚から 6 年半ということで, 嬉野温泉に一泊で.

美肌の湯で奥さんにはいつまでも元気でいてほしい.

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

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)

Object クラス

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

p [1, 2, 3, 4].map(&self.method(:*))

以下, irb にて動作確認.

irb(main):001:0> p [1, 2, 3, 4].map(&self.method(:*))
NameError: undefined method `*' for class `Object'

以下, 解説より抜粋.

  • 設問の self は Object クラスのインスタンスとなる
  • Object クラスには * メソッドは定義されていないので, undefined method の例外となる

以下のように Object クラスに * メソッドを追加すれば利用出来る.

irb(main):001:0> class Object
irb(main):002:1>   def *(arg)
irb(main):003:2>     '*' + arg.to_s + '*'
irb(main):004:2>   end
irb(main):005:1> end
=> :*
irb(main):007:0> [1, 2, 3, 4].map(&self.method(:*))
=> ["*1*", "*2*", "*3*", "*4*"]

ちなみに, Object#method についてドキュメントより引用.

オブジェクトのメソッド name をオブジェクト化した Method オブジェクトを返します。

irb(main):006:0> me = -365.method(:abs)
=> #<Method: Fixnum#abs>
irb(main):007:0> me
=> #<Method: Fixnum#abs>
irb(main):008:0> me.call
=> 365
# 以下と同義
irb(main):009:0> -365.abs
=> 365

キーワード引数

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

def foo(arg:)
  puts arg
end

foo 100

以下, irb にて動作確認.

irb(main):001:0> def foo(arg:)
irb(main):002:1>   puts arg
irb(main):003:1> end
=> :foo
irb(main):004:0> 
irb(main):005:0* foo 100
ArgumentError: missing keyword: arg

以下, 解説より抜粋.

  • キーワード引数は省略することが出来ない
  • シンボル: 値 の形式で引数を指定する

設問では, 以下のように修正する.

irb(main):001:0> def foo(arg:)
irb(main):002:1>   puts arg
irb(main):003:1> end
=> :foo
irb(main):004:0> 
irb(main):005:0* foo(arg: 100)
100
=> nil

フムフム.