I recently discovered a feature of Ruby that surprised me. Really, I was surprised that I hadn't heard of it before (for as long as I have been a fan of the language).
module_function
can be used to make one or more Module methods accessible as type-scoped methods (in the same way that declaring them as self
methods would). For example:
module Foo | |
def self.bar | |
'heynow' | |
end | |
end | |
# is equivalent to | |
module Foo | |
def bar | |
'heynow' | |
end | |
module_function :bar | |
end |
In this form, the methods of the module must be declared before the line containing module_function
. You can pass one or more method names (as symbols) in the call. In fact, you can even re-write this as follows:
module Foo | |
module_function | |
def bar | |
'heynow' | |
end | |
end |
This form makes all methods declared after module_function
behave as type-scoped functions (callable in the form of: Foo.bar
or Foo::bar
). You can "turn-off" the behavior of what is given type-scoped calling access by declaring a visibility modifier after the last method you want to expose in this way.
module Foo | |
module_function | |
def foo | |
'hey' | |
end | |
def bar | |
'now' | |
end | |
public | |
def baz | |
'hooba' | |
end | |
end |
Now the Foo functions can be called either as type-scoped functions or Foo can be included in a class or added to an object.
class Something | |
include Foo | |
def heynow | |
'foo' + bar + baz | |
end | |
end | |
puts Something.new.foo # "hey" | |
puts Something.new.bar # "now" | |
puts Something.new.baz # "hooba" | |
puts Something.new.heynow # "foonowhooba" |
One thing you now can't do, though, is refer to the module_function
scoped methods as instance methods of classes or objects into which the Foo
module is included. IOW, trying to call: Something.new.foo
in the above sample code blows up with a warning about trying to access a 'private' scoped variable.