Can you explain why the developer is using class << self to add a methods to the base class?
base.rb from the GeoPlanet Gem
module GeoPlanet
class Base
class << self
def build_url(resource_path, options = {})
end
end
end
Because he doesn't know that
def GeoPlanet::Base.build_url(resource_path, options = {}) end
would work just as well?
Well, they aren't 100% equivalent: if GeoPlanet doesn't exist, then the original snippet will create the module, but my version will raise a NameError. To work around that, you'd need to do this:
module GeoPlanet
def Base.build_url(resource_path, options = {}) end
end
Which will of course raise a NameError, if Base doesn't exist. To work around that, you'd do:
module GeoPlanet
class Base
def self.build_url(resource_path, options = {}) end
end
end
However you look at it, there's no need to use the singleton class syntax. Some people just simply prefer it.
I think it is simply a matter of style/taste. I like to use the class << self approach when I have a lot of class methods that I want to group together or provide some sort of visual separation from instance methods.
I would also use this approach if all my methods were class methods as the GeoPlanet author did.
Related
2 main techniques for creating class methods (without the obvious "def self.method") are:
Defining them in "class << self" block
Defining ClassMethod module and extending it later
I personally prefer second way, seems cleaner. Does anyone has any reason to prefer one technique over the other?
There's also "class_method" method, but I never used it, it has quite complex implementation and seem to do a lot more than previous 2.
self.method is the simplest option when you just need to create one method without dependencies or related logic.
class << self allows you to do far more than define methods on the metaclass. This is useful when you're defining methods which need to work with other parts of the metaclass (eg. aliasing existing method names).
For instance:
class Logger
class << self
attr_reader :payload
def log(message)
#payload = message
end
end
end
The module extension method comes in handy for method reuse and to group multiple coherent methods.
For instance:
module QueryMethods
def find
end
def where
end
end
module FactoryMethods
def build
end
def create
end
end
class BusinessModel
extend QueryMethods
extend FactoryMethods
end
First, the class << foo syntax opens up foo's singleton class (eigenclass). This allows you to specialise the behaviour of methods called on that specific object.
a = 'foo'
class << a
def inspect
'"bar"'
end
end
a.inspect # => "bar"
a = 'foo' # new object, new singleton class
a.inspect # => "foo"
class << self opens up self's singleton class, so that methods can be redefined for the current self object (which inside a class or module body is the class or module itself). Usually, this is used to define class/module ("static") methods
class << self is good at keeping all of your class methods in the same block. If methods are being added in def self.method from then there's no guarantee (other than convention and wishful thinking) that there won't be an extra class method tucked away later in the file.
def self.method is good at explicitly stating that a method is a class method, whereas with class << self you have to go and find the container yourself.
Which of these is more important to you is a subjective decision, and also depends on things like how many other people are working on the code and what their preferences are.
Pros of “class << self” style
I'm trying to make a DSL like configuration for classes that include a module but to have the configured variable available to both class and instance methods seems to require littering the module with access methods. Is there a more elegant way to do this?
module DogMixin
class << self
def included(base)
base.extend ClassMethods
end
end
module ClassMethods
def breed(value)
#dog_breed = value
end
def dog_breed
#dog_breed
end
end
end
class Foo
include DogMixin
breed :havanese
end
puts Foo.dog_breed
# not implemented but should be able to do this as well
f = Foo.new
f.dog_breed
Your example is a bit weird I think :)
Anyway, one way to avoid writing the accessors (the assignment - accessor is problematic in my eyes - especially in the given example) is to define constants, as in the example below. If however you need runtime-assignments, please edit your question (and thus render this answer invalid :) except you want to mess with runtime constant assignment, which is possible but messy).
module DogMixin
# **include** DogMixin to get `Class.dog_breed`
class << self
def included(base)
def base.dog_breed
self::DOG_BREED || "pug"
end
end
end
# **extend** DogMixin to get `instance.dog_breed`
def dog_breed
self.class.const_get(:DOG_BREED) || "pug"
end
end
class Foomer
DOG_BREED = 'foomer'
extend DogMixin
include DogMixin
end
f = Foomer.new
puts Foomer.dog_breed
puts f.dog_breed
# If I understand you correctly, this is the most important (?):
f.dog_breed == Foomer.dog_breed #=> true
It took some reading of (In Ruby) allowing mixed-in class methods access to class constants to get the Instance-And-Class Constant lookup from a module, but it works. I am not sure if I really like the solution though. Good question, although you could add a little detail.
I have an app that includes modules into core Classes for adding client customizations.
I'm finding that class_eval is a good way to override methods in the core Class, but sometimes I would like to avoid re-writing the entire method, and just defer to the original method.
For example, if I have a method called account_balance, it would be nice to do something like this in my module (i.e. the module that gets included into the Class):
module CustomClient
def self.included base
base.class_eval do
def account_balance
send_alert_email if balance < min
super # Then this would just defer the rest of the logic defined in the original class
end
end
end
end
But using class_eval seems to take the super method out of the lookup path.
Does anyone know how to work around this?
Thanks!
I think there are several ways to do what you're wanting to do. One is to open the class and alias the old implementation:
class MyClass
def method1
1
end
end
class MyClass
alias_method :old_method1, :method1
def method1
old_method1 + 1
end
end
MyClass.new.method1
=> 2
This is a form of monkey patching, so probably best to make use of the idiom in moderation. Also, sometimes what is wanted is a separate helper method that holds the common functionality.
EDIT: See Jörg W Mittag's answer for a more comprehensive set of options.
I'm finding that instance_eval is a good way to override methods in the core Class,
You are not overriding. You are overwriting aka monkeypatching.
but sometimes I would like to avoid re-writing the entire method, and just defer to the original method.
You can't defer to the original method. There is no original method. You overwrote it.
But using instance_eval seems to take the super method out of the lookup path.
There is no inheritance in your example. super doesn't even come into play.
See this answer for possible solutions and alternatives: When monkey patching a method, can you call the overridden method from the new implementation?
As you say, alias_method must be used carefully. Given this contrived example :
module CustomClient
...
host.class_eval do
alias :old_account_balance :account_balance
def account_balance ...
old_account_balance
end
...
class CoreClass
def old_account_balance ... defined here or in a superclass or
in another included module
def account_balance
# some new stuff ...
old_account_balance # some old stuff ...
end
include CustomClient
end
you end up with an infinite loop because, after alias, old_account_balance is a copy of account_balance, which now calls itself :
$ ruby -w t4.rb
t4.rb:21: warning: method redefined; discarding old old_account_balance
t4.rb:2: warning: previous definition of old_account_balance was here
[ output of puts removed ]
t4.rb:6: stack level too deep (SystemStackError)
[from the Pickaxe] The problem with this technique [alias_method] is that you’re relying on there not being an existing method called old_xxx. A better alternative is to make use of method objects, which are effectively anonymous.
Having said that, if you own the source code, a simple alias is good enough. But for a more general case, i'll use Jörg's Method Wrapping technique.
class CoreClass
def account_balance
puts 'CoreClass#account_balance, stuff deferred to the original method.'
end
end
module CustomClient
def self.included host
#is_defined_account_balance = host.new.respond_to? :account_balance
puts "is_defined_account_balance=#{#is_defined_account_balance}"
# pass this flag from CustomClient to host :
host.instance_variable_set(:#is_defined_account_balance,
#is_defined_account_balance)
host.class_eval do
old_account_balance = instance_method(:account_balance) if
#is_defined_account_balance
define_method(:account_balance) do |*args|
puts 'CustomClient#account_balance, additional stuff'
# like super :
old_account_balance.bind(self).call(*args) if
self.class.instance_variable_get(:#is_defined_account_balance)
end
end
end
end
class CoreClass
include CustomClient
end
print 'CoreClass.new.account_balance : '
CoreClass.new.account_balance
Output :
$ ruby -w t5.rb
is_defined_account_balance=true
CoreClass.new.account_balance : CustomClient#account_balance, additional stuff
CoreClass#account_balance, stuff deferred to the original method.
Why not a class variable ##is_defined_account_balance ? [from the Pickaxe] The module or class definition containing the include gains access to the constants, class variables, and instance methods of the module it includes.
It would avoid passing it from CustomClient to host and simplify the test :
old_account_balance if ##is_defined_account_balance # = super
But some dislike class variables as much as global variables.
[from the Pickaxe] The method Object#instance_eval lets you set self to be some arbitrary object, evaluates the code in a block with, and then resets self.
module CustomClient
def self.included base
base.instance_eval do
puts "about to def account_balance in #{self}"
def account_balance
super
end
end
end
end
class Client
include CustomClient #=> about to def account_balance in Client
end
As you can see, def account_balance is evaluated in the context of class Client, the host class which includes the module, hence account_balance becomes a singleton method (aka class method) of Client :
print 'Client.singleton_methods : '
p Client.singleton_methods #=> Client.singleton_methods : [:account_balance]
Client.new.account_balance won't work because it's not an instance method.
"I have an app that includes modules into core Classes"
As you don't give much details, I have imagined the following infrastructure :
class SuperClient
def account_balance
puts 'SuperClient#account_balance'
end
end
class Client < SuperClient
include CustomClient
end
Now replace instance_eval by class_eval. [from the Pickaxe] class_eval sets things up as if you were in the body of a class definition, so method definitions will define instance methods.
module CustomClient
...
base.class_eval do
...
print 'Client.new.account_balance : '
Client.new.account_balance
Output :
#=> from include CustomClient :
about to def account_balance in Client #=> as class Client, in the body of Client
Client.singleton_methods : []
Client.new.account_balance : SuperClient#account_balance #=> from super
"But using instance_eval seems to take the super method out of the lookup path."
super has worked. The problem was instance_eval.
Please help me out.
I need to use the same bunch of attributes in many classes. I would suggest to create module with predefined attributes and extend this module in every class
module Basic
#a=10
end
class Use
extend Basic
def self.sh
#a
end
end
puts Use.sh
but the output is empty. It seems like I missed something.
Maybe there is a better way to do that?
Your thoughts?
It's all about the self:
module Basic
#a=10
end
has self evaluating to Basic. You want it to evaluate to Use when the latter is extended:
module Basic
# self = Basic, but methods defined for instances
class << self
# self = Basic's eigenclass
def extended(base)
base.class_eval do
# self = base due to class_eval
#a=10
end
end
end
end
class Use
# self = Use, but methods defined for instances
extend Basic # base = Use in the above
class << self
# self = Use's eigenclass
def sh
#a
end
end
end
Use.sh # 10
What you're describing is the Flyweight design pattern. While some view this as rarely used in ruby ( http://designpatternsinruby.com/section02/flyweight.html ), others provide an implementation ( http://www.scribd.com/doc/396559/gof-patterns-in-ruby page 14 )
Personally, what I would do is to put all these attributes into a yaml file, and parse them either into a global variable:
ATTRIBUTES = YAML.load_file(File.expand_path('attributes.yml', File.dirname(FILE))
or a class method (with caching here, assuming you won't change the yml file while the app is running and need the new values). I'd suggest using ActiveSupport::Concern here as it's easier to read than the traditional way of mixing in class methods:
module Basic
extend ActiveSupport::Concern
module ClassMethods
def attributes_file
File.expand_path('attributes.yml', File.dirname(__FILE__))
def attributes
#attributes ||= YAML.load_file(attributes_file)
#attributes
end
end
module InstanceMethods
# define any here that you need, like:
def attributes
self.class.attributes
end
end
end
You can define methods for each of the attributes, or rely on indexing into the attributes hash. You could also get fancy and define method_missing to check if an attribute exists with that name, so that you don't have to keep adding methods as you want to add more attributes to the shared configs.
Disclaimer: Although I'm asking in context of a Rails application, I'm not talking about Rails helpers (i.e. view helpers)
Let's say I have a helper method/function:
def dispatch_job(job = {})
#Do something
end
Now I want to use this from several different places (mostly controllers, but also a few BackgrounDRb workers)
What's the preferred way to do this?
I can think of two possibilities:
1. Use a class and make the helper a static method:
class MyHelper
def self.dispatch_job(job = {})
end
end
class MyWorker
def run
MyHelper.dispatch_job(...)
end
end
2. Use a module and include the method into whatever class I need this functionality
module MyHelper
def self.dispatch_job(job = {})
end
end
class MyWorker
include MyHelper
def run
dispatch_job(...)
end
end
3. Other possibilities I don't know yet
...
The first one is more Java-like, but I'm not sure if the second one is really an appropriate use of Ruby's modules.
The module approach is the direction I would take. I prefer it because of its flexibility and how nicely it allows you to organize your code. I suppose you could argue that they are just another form of mixin. I always think of mixins as direct extensions of a particular class
class Foo
def hello
'Hello'
end
end
class Foo
def allo
'Allo?'
end
end
f = Foo.new
f.hello => 'Hello'
f.allo => 'Allo?'
That always seems very specific, whereas the module approach can extend any class you include it in.
Peer
If you are going to use that in your controllers and some other code, you can create a mixin and add it to your application controller, from which other controllers derive from, that way you can have it in your controllers, then you can add the module to your other outside classes.