Forum: Ruby How can I use module methods as class methods ?

249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-10-28 15:37
Hi,

Here is a code :

module A
  def self.foo
      1
  end
  def bar
      2
  end
end

## Now if I do extend
class B
    extend A
end

B.bar # 2
B.foo # error
B.new.foo # error

## Now if I do include
class B
    include A
end

B.new.bar # 2
B.foo # error
B.new.foo # error

Any chance to get access or do like `B.foo` ?
14b5582046b4e7b24ab69b7886a35868?d=identicon&s=25 Joel Pearson (virtuoso)
on 2013-10-28 15:47
You should be able to do that by adapting this approach:
http://softwarebyjosh.com/2012/01/21/Pirating-Ruby...
4c0cd4007f109d473c295009a2651f45?d=identicon&s=25 John Moon (Guest)
on 2013-10-28 16:16
(Received via mailing list)
When you want to include Modules into a Class you would typically do

require filename # if you are using two different script

class B
    include A # => includes all methods in the Module
end
249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-10-28 16:25
John Moon wrote in post #1125888:
> When you want to include Modules into a Class you would typically do
>
> require filename # if you are using two different script
>
> class B
>     include A # => includes all methods in the Module
> end

No it wouldn't :

module A
  def self.foo
      1
  end
  def bar
      2
  end
end


## Now if I do include
class B
    include A
end

B.new.foo # undefined method `foo' for #<B:0x17148f0> (NoMethodError)
B.foo # undefined method `foo' for B:Class (NoMethodError)
14b5582046b4e7b24ab69b7886a35868?d=identicon&s=25 Joel Pearson (virtuoso)
on 2013-10-28 16:31
By defining self.foo you're explicitly saying that it belongs to module
A. If you wanted to include or extend a class with it you wouldn't use
"self".

The way to accomplish this is demonstrated with some metaprogramming
that I linked to in my previous response.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (robert_k78)
on 2013-10-29 00:09
(Received via mailing list)
On Mon, Oct 28, 2013 at 4:31 PM, Joel Pearson <lists@ruby-forum.com>
wrote:
> By defining self.foo you're explicitly saying that it belongs to module
> A. If you wanted to include or extend a class with it you wouldn't use
> "self".
>
> The way to accomplish this is demonstrated with some metaprogramming
> that I linked to in my previous response.

The most straightforward approach that satisfies the thread subject
would be to use #extend.

module M
  def bar; 123 end
end

class X
  extend M
end

X.bar # => 123

Cheers

robert
14b5582046b4e7b24ab69b7886a35868?d=identicon&s=25 Joel Pearson (virtuoso)
on 2013-10-29 09:36
Robert Klemme wrote in post #1125970:
> The most straightforward approach that satisfies the thread subject
> would be to use #extend.

This was already covered in the initial post, he's using a module with
"self.foo", which doesn't work with extend since that method remains
with the module rather than transferring to the class.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (robert_k78)
on 2013-10-29 12:57
(Received via mailing list)
On Tue, Oct 29, 2013 at 9:36 AM, Joel Pearson <lists@ruby-forum.com>
wrote:
> Robert Klemme wrote in post #1125970:
>> The most straightforward approach that satisfies the thread subject
>> would be to use #extend.
>
> This was already covered in the initial post, he's using a module with
> "self.foo", which doesn't work with extend since that method remains
> with the module rather than transferring to the class.

Aargh!  Overlooked that.  Posting after midnight... Thank you for the
heads up, Joel!

My 2 Cents: I do not think it is a good idea to do what OP is trying
to do.  After all methods defined on the module itself affect this
exact module's state.  If one wants to provide some kind of
functionality that should be reusable by class instances then defining
a module with instance methods and extending the class would be the
proper way.

If there needs to be related behavior, i.e. instance methods using
class methods then I would use two modules.  You can either act on the
extend event or on the #included event.  I'd probably use the
#included callback as that stresses the fact that I want to provide
instance functionality.

#!/usr/bin/ruby -w

module Foo
  module Foo4Class
    def instance_count
      @instance_count
    end
  end

  def self.included(cl)
    cl.extend Foo4Class

    cl.instance_variable_set '@instance_count', 0

    cl.singleton_class.class_eval do
      def new(*a,&b)
        super.tap { @instance_count += 1 }
      end
    end
  end

  def shout_instance_count
    printf "There have been %d of us created!\n",
self.class.instance_count
  end
end


class Bar
  include Foo
end

Array.new(10) { Bar.new }.each(&:shout_instance_count)

https://gist.github.com/rklemme/7213313

Kind regards

robert
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (robert_k78)
on 2013-10-29 13:52
(Received via mailing list)
On Tue, Oct 29, 2013 at 12:56 PM, Robert Klemme
<shortcutter@googlemail.com> wrote:
> heads up, Joel!
> extend event or on the #included event.  I'd probably use the
> #included callback as that stresses the fact that I want to provide
> instance functionality.

> https://gist.github.com/rklemme/7213313

I have updated the gist with a more appropriate solution that reduces
meta programming in favor of ordinary methods.

Cheers

robert
6cb1b2c58abc2116f910ec9253ee387f?d=identicon&s=25 Aleksandar Kostadinov (aleksandar_k)
on 2015-07-15 00:58
What I did for convenience and easy read is:

module ModIncl
  def whatever
    ...
  end
end
module Mod
  extend ModIncl
end

Now if I want to call a method without messing my class I can use
`Mod.whatever`. If I want to mess the methods into my class to call them
easily, then I do `include ModIncl`.

Not sure how @Robert Klemme's answer made me think about this. I can
hardly comprehend what he does but thanks anyway.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.