Reputation: 14736
I have a base module that has some logic in it and it gets included inside various classes. Now I need a configure
block that sets some configuration how the class should behave.
I tried the following code:
class MyConfig
attr_accessor :foo, :bar
end
module BaseModule
def self.included base
base.include InstanceMethods
base.extend ClassMethods
end
module ClassMethods
attr_reader :config
def configure &block
@config = MyConfig.new
block.call(@config)
end
end
module InstanceMethods
def do_something
puts self.class.config.inspect
end
end
end
class MyClass1
include BaseModule
configure do |config|
config.foo = "foo"
end
end
class MyClass2
include BaseModule
configure do |config|
config.bar = "bar"
end
end
MyClass1.new.do_something
#<MyConfig:0x007fa052877ea0 @foo="foo">
MyClass2.new.do_something
#<MyConfig:0x007fa052877ce8 @bar="bar">
- I'm unsure if an instance variable
@config
for a module / class is the best way to configure a class. Is this the right way, or are there any better solutions?- Is it good to also use
base.extend ClassMethods
when the module only gets included withinclude BaseModule
? A developer could expect that only instance methods get included, but as a side effect there are also class methods extended.
Update
I've added a MyConfig
class, from which a new instance is created. This has the benefit that you can use config.foo = "foo"
.
Upvotes: 4
Views: 1495
Reputation: 2390
I've changed your code a bit to use an approach both me and a lot of popular gems (like devise) use for configuration. Hope you'll like it :)
module BaseModule
def self.included base
base.include InstanceMethods
base.extend ClassMethods
end
module ClassMethods
mattr_accessor :foo
@@foo = 'initial value'
def configure &block
block.call(self)
end
end
module InstanceMethods
def do_something
puts foo
end
end
end
class MyClass1
include BaseModule
configure do |klass|
klass.foo = "foo"
end
end
class MyClass2
include BaseModule
configure do |klass|
klass.foo = "bar"
end
end
MyClass1.new.do_something
# => "foo"
MyClass2.new.do_something
# => "bar"
The changes are:
configure
method return self
, this way you can configure your class in a simple, readable, rails-like wayExample:
Kid.config do |k|
k.be_kind = false
k.munch_loudly = true
k.age = 12
end
Upvotes: 2