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 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 thanoptions.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 toextend
any modules that I want to make parametric?