Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby::Boxでできること、Refinementsでできること

 Ruby::Boxでできること、Refinementsでできること

松江Ruby会議12 登壇資料

Avatar for Tomohiro Hashidate

Tomohiro Hashidate

June 06, 2026

More Decks by Tomohiro Hashidate

Other Decks in Technology

Transcript

  1. 動作の仕組み (再掲) Boxで読み込むためのモジュールを二つ用意する。 module BoxA def foo puts "BoxA" +

    Ruby::Box.current.inspect super end end module BoxB def foo = puts "BoxB" + Ruby::Box.current.inspect end 11
  2. # Box で定義されたモジュールをinclude/prepend する A = Ruby::Box.new; A.require_relative "box_a" B

    = Ruby::Box.new; A.require_relative "box_a" class Foo prepend A::BoxA include B::BoxB def foo puts "Main" + Ruby::Box.current.inspect super end end Foo.new.foo # => returns: BoxA#<Ruby::Box:3,user,optional> Main#<Ruby::Box:2,user,main> BoxB#<Ruby::Box:4,user,optional> 12
  3. 14

  4. 使ったことない人のための例 module StringRefinement refine String do def foo "#foo: "

    + self end end end using StringRefinement puts "hoge".foo # => "#foo: hoge" 17
  5. Refinementsにおける組込みクラス module RefineA refine String do def |(other) self +

    other end end end require_relative "./refine_a" using RefineA puts "Hello, " | "world!" "Hello, world!" 19
  6. Boxにおける組込みクラス class String def |(other) self + other end end

    BoxA = Ruby::Box.new BoxA.require_relative "./box_a" a = BoxA::String.new a << "Hello, " puts a | "world!" どうなるでしょうか? 20
  7. Boxにおける組込みクラス(正解) class String def |(other) self + other end end

    BoxA = Ruby::Box.new BoxA.require_relative "./box_a" a = BoxA::String.new a << "Hello, " puts a | "world!" NoMethodError 21
  8. これなら大丈夫 # ... さっきのString の定義... class Foo def foo "Hello,

    " | "foo!" end end BoxA = Ruby::Box.new BoxA.require_relative "./box_a" a = BoxA::Foo.new puts a.foo "Hello, foo!" 23
  9. Refinementsの影響範囲 # refine_b.rb require_relative './bar' module RefineB refine String do

    def |(other) self + other end end refine Foo do def foo(other) "foo_refine: " | other end def foo2 Bar.new.bar(self) end end end 24
  10. # main.rb class Foo end require_relative './refine_b' using RefineB p

    Foo.new.foo("refine_b") p Foo.new.foo2 "foo_refine: refine_b" /home/joker/ghq/github.com/joker1007/slides/matsue_rubykaigi/bar.rb:3:in 'Bar#bar': undefined method 'foo' for an instance of Foo (NoMethodError) foo.foo("bar") ^^^^ from /home/joker/ghq/github.com/joker1007/slides/matsue_rubykaigi/refine_b.rb:16:in 'foo2' from main_refine_b.rb:8:in '<main>' 26
  11. 一方Ruby::Boxは require_relative './bar' class String def |(other) self + other

    end end class Foo < Ruby::Box.main::Foo def foo(other) "foo_box:" + other end def foo2 Bar.new.bar(self) end end 28
  12. 普通に呼べる class Foo end BoxB = Ruby::Box.new BoxB.require_relative './box_b' p

    BoxB::Foo.new.foo("box_b") p BoxB::Foo.new.foo2 "foo_box:box_b" "foo_box:bar" 29
  13. これはいける module RefineC refine String do def |(other) self +

    other end end end class A using RefineC def fuga p "fuga" | "piyo" end end A.new.fuga # => "fugapiyo" p "hoge" | "bar" # => NoMethodError 31
  14. これはダメ module RefineC refine String do def |(other) self +

    other end end end def fuga using RefineC p "fuga" | "piyo" end fuga # => main.using is permitted only at toplevel 32
  15. Refinementsが良いケース rspec-parameterizedの例 describe "plus" do using RSpec::Parameterized::TableSyntax where(:a, :b, :answer)

    do 1 | 2 | 3 5 | 8 | 13 0 | 0 | 0 end with_them do it "should do additions" do expect(a + b).to eq answer end end end 35
  16. 47