Forum: Ruby Conditionally Including Methods From A Module?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Kenny (Guest)
on 2008-10-25 13:07
(Received via mailing list)
Is there a way to include only certain methods from a module instead
of all the methods?

Given the following:

module ActsAsAnything
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def acts_as_anything(opts = {})
      # Based on the options based in, I would like to selectively
include certain methods from
      # the InstanceMethods module.

      # Something like:
      include ActsAsAnything::InstanceMethods.instance_method(:index)
if opts[:include_index]
      include ActsAsAnything::InstanceMethods.instance_method(:list)
if opts[:include_list]

      # (Note the 'if' condition above is just for example.... )
    end
  end

  module InstanceMethods
    def index
      # .....
    end

   def list
      # ....
   end
  end
end

However, 'include' requires a module and I can't figure out the proper
syntax, or even if this is possible, to just include a certain method
from it. The is for a standard acts_as_.... Rails plug-in.

Any help or guidance is much appreciated.

Sincerely,
Kenny
Mike G. (Guest)
on 2008-10-25 15:00
Kenny wrote:
> Is there a way to include only certain methods from a module instead
> of all the methods?

Not directly.  In general, methods are part of the same module for a
reason.  A given method may call other methods in the module, and a
method may use instance variables defined in other methods.

What you propose could make sense in the case of a "pure utility" module
which has no state and where there little is or no relationship between
the methods.

  def methods_to_lambdas(mod)
    instance = Class.new { include mod }.new
    mod.instance_methods(false).inject(Hash.new) { |hash, meth|
      hash.update(
        meth.to_sym => lambda { |*args, &block|
          instance.send(meth, *args, &block)
        }
      )
    }
  end

  def pull_methods(mod, *names)
    lambdas = methods_to_lambdas(mod)
    names.each { |name|
      define_method(name, &lambdas[name])
    }
  end

  module Misc
    def func_a ; p "Misc#func_a" ; end
    def func_b ; p "Misc#func_b" ; end
    def func_c ; p "Misc#func_c" ; end
  end

  class Fred
    pull_methods(Misc, :func_a, :func_b)
  end

  Fred.new.func_a  #=> Misc#func_a
  Fred.new.func_b  #=> Misc#func_b
  Fred.new.func_c  #=> NoMethodError

ruby-1.8.7 or 1.9 is needed for the lambda syntax (for 1.8.6 you can
eval a string instead).
Kenny (Guest)
on 2008-10-26 02:21
(Received via mailing list)
Thanks so much for the post Mike, very much appreciated and a great
learning lesson for me in some lower level Ruby semantics.

After my post last night, I can up with using define_method as well
and produced something like the following:

module ActsAsAnything
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    # acts_as_anything
    def acts_as_anything(opts = {})

      # index
      define_method(:index) do
        puts 'Index Method'
      end if opts.include?(:index)
    end
  end
end

Since I'm including a Module that I'm the author of, I figure I can
get away with this syntax and just redefine my top level Module as
such.

Any thoughts on this implementation?

Sincerely,
Kenny
Daniel B. (Guest)
on 2008-10-26 03:52
(Received via mailing list)
On Oct 25, 3:04 am, Kenny <removed_email_address@domain.invalid> wrote:
> Is there a way to include only certain methods from a module instead
> of all the methods?

<snip>

Yep.

gem install use

class Foo
   use ModuleA, :include => [:method_x]
end

That will only include 'method_x' from ModuleA. You can also exclude
and alias included methods on the fly.

Regards,

Dan
Daniel B. (Guest)
on 2009-01-08 08:33
(Received via mailing list)
Kenny wrote:
>   module ClassMethods
>
>       # ....
>    end
>   end
> end
>
> However, 'include' requires a module and I can't figure out the proper
> syntax, or even if this is possible, to just include a certain method
> from it. The is for a standard acts_as_.... Rails plug-in.
>
> Any help or guidance is much appreciated.

gem install use

class Foo
    use Bar, :method_a, :method_b
end

See http://rubyforge.org/docman/view.php/735/2472/examples.html for more
examples.

Regards,

Dan
This topic is locked and can not be replied to.