Ruby "Base" classes - ruby

It seems commonplace to name classes "Base" in Ruby. I'm not sure why, nor how I feel about it.
Consider, for example, ActiveRecord. ActiveRecord is a module that contains a number of classes such as Observer and Migration, as well as a class called Base. What's the benefit of this, as opposed to having an ActiveRecord class that contains Observer and Migration?
class ActiveRecord
class Observer
[...]
end
class Migration
[...]
end
end
vs
module ActiveRecord
class Base
[...]
end
class Observer
[...]
end
class Migration
[...]
end
end

The Base class is commonly used to identify an abstract class, intended to be extended and implemented in a concrete class by the developer.
For instance, ActiveRecord::Base is the abstract class for any Active Record model in a Rails project. A model looks like
class User < ActiveRecord::Base
end
Likewise, Observer defines its own Observer::Base and Action Controller defines ActionController::Base which, in a Rails project, is immediately implemented by ApplicationController::Base.
Ruby doesn't provide and language-level keyword or syntax to define abstract classes. Technically speaking, ActiveRecord::Base it's not a real abstract class, but it's a kind of convention to use Base for this pattern.

Related

Overwriting a dependency gem class which inherits from a parent class

Overwriting a dependency gem class which inherits from a parent class
If I am using blah gem, and this gem has a class called foo which inherits from bar. But I want to change this class on this gem. Is there a way I can do that, I have seen ways to overwrite methods on classes from gems but not to overwrite the actual classes.
eg.
The class I want to overwrite is as follows:
class foo < bar
def some_method
end
def another_method
end
end
How I want to overwrite this class:
class foo < not_bar
def a_different_some_method
end
def a_different_another_method
end
end
No, you can't actually change the parent class without basically rewriting the subclass. If you only have two methods in each class that's probably fine, but Ruby classes use single-inheritance, so you can't re-assign a subclass to a different superclass without redefining it. You can, however, do any of the following:
Re-open the class and redefine its methods.
Prepend a module to redefine the behavior of existing methods.
Add or modify methods for the singleton class, or on a singleton instance of that class.
If your class is inheriting from Delegator, you can change the delegate class with #__setobj__.
Since you haven't really defined a use case, it's hard to tell which method would be best for you. Once the parent class is defined, though, it stays defined, so you'll have to do whatever you're trying to do another way.

Use ActiveSupport's number helper in a Class Method

I have an embarrassingly basic question:
I'm working on a plain-old-ruby model that deals with money, and some of the class methods return prices which need to be formatted for display.
In the past I've used include ActionView::Helpers::NumberHelper to stick the number_to_currency method in a model, but that only works for instance methods.
How do you get that method to be accessible from a class method?
Use extend:
class MyClass
extend ActionView::Helpers::NumberHelper
end

Using class << self, when to use classes or modules?

Is there a difference in usage between
class Helper
class << self
# ...
end
end
and
module Helper
class << self
# ...
end
end
When would you use one over the other?
The class<<self seems to be a red herring, as the only difference here is a class versus a module. Perhaps you're asking "I want to create an object that I do not intend to instantiate, but which exists only as a namespace for some methods (and possibly as a singleton with its own, global, state)."
If this is the case, both will function equally well. If there is any chance that you might want to create a derivative (another object inheriting the same methods) then you should use a class as it slightly is easier to write:
class Variation < Helper
instead of
module Helper
module OwnMethods
# Put methods here instead of class << self
end
extend OwnMethods
end
module Variation
extend Helper::OwnMethods
However, for just namespacing I would generally use a module over a class, as a class implies that instantiation will occur.
The difference between a Module and a Class is that you can make an instance of a Class, but not a Module. If you need to create an instance of Helper (h = Helper.new) then it should be a class. If not, it is probably best to remain a module. I'm not sure how the rest of your code is relevant to the question; whether you have class methods on a Module or a Class is not relevant to whether you need to create instances of that object.

Ruby: nesting classes in classes same as nesting classes in modules?

In Ruby, one can declare classes like
class A
class B
end
end
and then instantiate the inner class like A::B.new.
Does B have some sort of special relationship with A (as is the case in Java) or is A just its namespace? In other words, is nesting a class in a class the same as nesting it in a module?
This is one of those times when you should really just fire up irb and try it.
Yes, a class can be defined within another class. Since a class's superclass is Module (i.e. Class extends Module), they can do almost everything a Module can. A notable exception is that you cannot include (mixin) a class.
That said, there's very little reason to actually use this design pattern. It is more likely that A and B can be considered siblings. There is no need to arbitrarily namespace until you are blue in the face. If you are more than 3 levels deep, stop and consider refactoring.
A better design pattern for this example might be:
module Alphabet
class A; end
class B; end
end
For something more complicated, this continues to work nicely using Mixins:
module Animals
class Dog
include Walking
end
module Walking
# some methods pertaining to the ability to walk
end
end
Yes, it's essentially the same as nesting in module. Nested class does not have any kind of special relationship to the class it's nested in.
Yes and...no. A Module can't be instantiated whereas a class can, so there is a difference in nesting a class within a Module vs. using a class nested within a class.
For example: You cannot instantiate an object of Ford here (i.e. Cobra, F-150, Mustang, etc.) because you cannot instantiate a module,.
`module Ford
class Engine
...
end
end`
But you can have an instance of the class Ford as well as instances of Ford engines with using nested classes like so:
`class Ford
class Engine
##actions = ['list', 'find', 'add', 'quit']
def self.actions; ##actions; end
end
def self.truck_exists?
#Some more stuff here
end
end`
Classes (and Modules) have different usages:
Namespace: when you define a class (or module) inside another class (or module), you have to use a different notation outside the defining class to reach the inner class or module.
Template for instances: There modules and classes behave totally (well mostly) different.
Inheritance: You may extend a class, so you inherit all its attributes and methods, which works for modules as well. Or you may include a module (not: a class) to add its methods (and attributes) to your scope. Ruby plays here tricks by mixin the module in the class hierarchy.
So in the context of using name spaces, they are the same. However I would all the time use modules (only), but that is more a matter of style. The best book on this topic is in my opinion "Metaprogramming Ruby" by Paolo Perrotta.

Dynamically instantiating an ActiveRecord Observer for multiple models

I'm trying to develop a plugin/gem at the moment which observes multiple models. Ideally, the observer should be instantiated automatically with just one singleton method...
class MyModel < ActiveRecord::Base
# a class method like this will tell the observer to observe this model
observe_me
end
My initial approach was to define class methods included into AR base:
module ClassMethods
def observe_me
#observe_me = true
end
def should_observe_me?
#observe_me
end
end
ActiveRecord::Base.extend(ClassMethods)
And then use this to detect which models to observe within the Observer:
class MyObserver < ActiveRecord::Observer
# this should observe all models where should_observe_me? #=> true
observe ActiveRecord::Base.descendants.select { |m| m.try(:should_observe_me?) }.map(&:model_name)
end
The problem that I'm running into is that the observer is being loaded before the models are defined, so ActiveRecord has no descendants and MyObserver doesn't know which models to observe.
My next attempt was to hack around with ActiveRecord::Base.observers and ActiveRecord::Base.instantiate_observers but with no luck.
So, as it is at the moment:
Observer is defined but doesn't know which models to observe.
Models are defined and flag themselves to be observed but the observer has already been observed.
Is there a way I can delay the loading of the observer until after the models are defined or can someone think of a better approach to this problem?
#gavin: The structure of the application initialization has changed in Rails3 -- this might be your problem.
When / how are you including the ClassMethods module? IF you are in Rails3, and IF you added "require 'observe_me'" to $ROOT/config/environment.rb, then you'd see the (mis)behavior you describe.
If so, instead, create $ROOT/config/initializers/my_extensions.rb and stick the "require ..." in there.

Resources