views:

143

answers:

2

I have a rails app that loads lots of data from some java services. I'm writing a module that will allow me to populate some select boxes with this data and I'm trying to include these properly so I can reference them in my views. Here's my module

module FilterOptions
  module Select

    def some_select
     return "some information"
    end
  end
end

My idea was to include FilterOptions in my application_helper, and I thought I could then reference my methods using Select::some_select This is not the case. I have to include FilterOptions::Select then I can reference the method some_select on its own. I don't want that though as I think it's a bit confusing to someone that may not know that some_select is coming from my own module.

So, how do I write methods of a module that are like public static methods so I can include my main module, and reference my methods using the sub-module namespace like Select::some_select

+3  A: 

If you define module methods within the context of the module itself, they can be called without import:

module FilterOptions
  module Select
    def self.some_select
     return "some information"
    end
  end
end

puts FilterOptions::Select.some_select
# => "some information"

It is also possible to import one module, and not import the next, refer to it by name instead:

include FilterOptions
puts Select.some_select
# => "some information"
tadman
ok i feel kind of stupid, i do this in classes all the time with self, i don't know why i thought a module would be different. BTW what's the difference between using Select::some_select and Select.some_select?
brad
That's a good question. When it comes to constants, you need to use the :: notation since it's not a method call, but I think you can use either for methods.
tadman
+3  A: 

module_function causes a module function to be callable either as an instance method or as a module function:

#!/usr/bin/ruby1.8

module Foo

  def foo
    puts "foo"
  end
  module_function :foo

end

Foo.foo        # => foo
Foo::foo       # => foo

include Foo
foo            # => foo

Sometimes you want every method in a module to be a "module function," but it can get tedious and repetitive to keep saying "module_function" over and over. In that case, a little meta-programming can save the day:

!/usr/bin/ruby1.8

module Foo

  def self.method_added(name)
    instance_eval do
      module_function(name)
    end
  end

  def foo
    puts "foo"
  end

end

Foo.foo        # => foo
Foo::foo       # => foo

include Foo
foo            # => foo

If you do this a lot, you'll get tired of repeating the "self.method_added" method at the top of each of your modules. So, create a ModuleFunctions module. Any module including ModuleFunctions will cause all of its methods to be module functions.

#!/usr/bin/ruby1.8

module ModuleFunctions

  def self.included(o)
    def o.method_added(name)
      instance_eval do
        module_function(name)
      end
    end
  end

end

module Foo

  include ModuleFunctions

  def foo
    puts "foo"
  end

end

Foo.foo        # => foo
Foo::foo       # => foo

include Foo
foo            # => foo
Wayne Conrad
hey sorry for the late response, thanks for the details, i'm just learning metaprogramming now so I'll add this into my toolbox!
brad
You're welcome. Happy Hacking!
Wayne Conrad