Created
July 29, 2011 12:50
-
-
Save tomstuart/1113745 to your computer and use it in GitHub Desktop.
Parametric modules in Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Printable < Module | |
def initialize(string) | |
super() | |
define_method :print do | |
puts string | |
end | |
end | |
end | |
>> class A; include Printable.new('Hello'); end | |
>> class B; include Printable.new('Goodbye'); end | |
>> A.new.print | |
Hello | |
>> B.new.print | |
Goodbye | |
--- | |
# @tomafro suggested something better: | |
module TimeoutThing | |
def do_something | |
puts timeout | |
end | |
def self.with(options = {}) | |
Module.new do |m| | |
include TimeoutThing | |
options.each do |k, v| | |
define_method k do | |
v | |
end | |
end | |
end | |
end | |
end | |
TimeoutThing.with(:timeout => 20) | |
class A | |
include TimeoutThing.with(:timeout => 20) | |
end | |
class B | |
include TimeoutThing.with(:timeout => 40) | |
end | |
A.new.do_something | |
B.new.do_something | |
--- | |
# I think I like this best: | |
module Parametric | |
def with(options) | |
base = self | |
Module.new do | |
include base | |
options.each do |k, v| | |
define_method(k) { v } | |
end | |
end | |
end | |
end | |
module Printable | |
extend Parametric | |
def print | |
puts string | |
end | |
end | |
>> class A; include Printable.with(:string => 'Hello'); end | |
>> class B; include Printable.with(:string => 'Goodbye'); end | |
>> A.new.print | |
Hello | |
>> B.new.print | |
Goodbye |
To clarify: it's not a module, it's a class which subclasses Module
and therefore produces a module when instantiated. Mmm, contrived.
I like @tomafro's solution because it gives you a nice place to put (static) method definitions. I'll probably go with slightly less magic, i.e. define_method :options { options }
rather than options.each do … end
, but otherwise it's what I'm going to use for now. I think you're right that there's no beautiful way. Maybe I'll put the definition of #with
in its own module and use it to extend
any modules that I want to make parametric?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I didn't realise that a module which contained an
initialize
method would gain a correspondingnew
- interesting. Regardless, I think any solution is going to have the same key characteristics that both yours and @tomafro's has - the creation of a newModule
, with method(s) defined usingdefine_method
to get closure-like behaviour to bind the 'class'-level argument to the instance method implementation.