7545


Ruby Silverに向けて勉強しているものです。

特異クラスについて勉強用にサンプルコードを作成していたのですが、  
自身の理解の範疇を越えたので質問させてください。

Module Fooを作成して、Class Barにextendでミックスインしています。  
foo1が特異メソッドで定義されるのは理解しているつもりなんですが、  
foo2、foo3についてBarからどのように呼び出せばよいのか（もしくはできない）を  
おしえていただけないでしょうか

よろしくお願いいたします。

[code]

    module Foo
      def foo1
        puts "foofoo1"
      end
    
      def Foo.foo2
        puts "foofoo2"
      end
    
      class << self
        def foo3
          puts "foofoo3"
        end
      end
    
    end
    
    class Bar
      extend Foo
    end
    
[/code]

結果です。

[code]

    head :030 > Bar.foo2
    NoMethodError: undefined method `foo2' for Bar:Class
        from (irb):30
        from /home/anoguchi/.rvm/rubies/ruby-head/bin/irb:11:in `<main>'
    
    head :031 > Bar.foo3
    NoMethodError: undefined method `foo3' for Bar:Class
        from (irb):31
        from /home/anoguchi/.rvm/rubies/ruby-head/bin/irb:11:in `<main>'
    
[/code]


CC BY-SA 3.0
2015-03-06T09:03:39.573
7544
2015-03-07T06:22:55.333
2015-03-06T09:43:13.883
3639
8722
question
ruby
Mix-inしたモジュールの特異メソッドの呼び出し方


`Object#extend`の機能は以下の説明のとおりです。

> 引数で指定したモジュールのインスタンスメソッドを self の特異 メソッドとして追加します。

<http://docs.ruby-lang.org/ja/2.0.0/method/Object/i/extend.html>

`foo1`は`Foo`のインスタンスメソッドですが、`foo2`・`foo3`は`Foo`の特異メソッドであってインスタンスメソッドでないので`extend`の対象にはなりません。よって、`foo2`・`foo3`は`Bar`には所属していないため、`Bar.foo2`のような呼び出しはできないことになります。


CC BY-SA 3.0
2015-03-06T09:28:55.897
7545
2015-03-06T13:33:30.277
2015-03-06T13:33:30.277
3639
3639
7544
answer


要件に合っているかわかりませんが、やってみました。

[code]

    #!/usr/bin/ruby
    
    module Foo  
      def foo1
        puts "foofoo1"
      end
    
      def Foo.foo2
        puts "foofoo2"
      end
    
      class << self
        def foo3
          puts "foofoo3"
        end
      end
    end
    
    class Bar
      include Foo
    
      def self.method_missing(name, *args)
        self.included_modules.each do | module_obj |
          if (module_obj.respond_to?(name)) 
            module_obj.send(name)
          end
        end
      end
    end
    
    
    $ ruby -v
    ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin13]
    
    irb(main):003:0> Bar.foo2
    foofoo2
    => [Foo, Kernel]
    irb(main):004:0> Bar.foo3
    foofoo3
    => [Foo, Kernel]
    irb(main):005:0> 
    
[/code]

method_missingをこんな使い方していいものなのか。


CC BY-SA 3.0
2015-03-06T18:22:02.850
7565
2015-03-07T06:22:55.333
2015-03-07T06:22:55.333
85
8695
7544
answer


基本的にはBarでFooをextendしてもFooの特異メソッドは呼び出せない、が答えになるんですが、どうしても実現したければこんな方法もあります。

[code]

    module Foo
      def self.extended(klass)
        klass.extend ClassMethods
      end
    
      def foo1
        puts "foofoo1"
      end
    
      module ClassMethods
        def foo2
          puts "foofoo2"
        end
    
        def foo3
          puts "foofoo3"
        end
      end
      extend ClassMethods
    end
    
    class Bar
      extend Foo
    end
    
    Bar.foo1
    Bar.foo2
    Bar.foo3
    puts "*" * 10
    Foo.foo2
    Foo.foo3
    Foo.foo1 # NoMethodError
    
[/code]

上記コードの実行結果

[code]

    foofoo1
    foofoo2
    foofoo3
    **********
    foofoo2
    foofoo3
    test.rb:34:in `<main>': undefined method `foo1' for Foo:Module (NoMethodError)
    
[/code]

以上、ご参考までに。

参考文献

  * [Rubyのモジュールメソッドの作り方](http://qiita.com/ionis_h/items/5f26248ea4e154cce424)


CC BY-SA 3.0
2015-03-07T01:12:30.787
7568
2015-03-07T01:12:30.787
85
7544
answer