The document discusses Ruby classes and class methods.
Class methods are defined within a class' eigenclass. The eigenclass is accessed using class << self. Modules can also define class methods using included callbacks. Ruby classes are dynamic and support method missing to handle undefined methods.
1. Goal: to grok this code
class Post < ActiveRecord::Base <= class extension mixin
belongs_to :user <= macro
end
my_post = Post.new
my_post.name = 'Chile L‘ <= employs #method_missing
my_post.subject = 'traveling in thailand'
my_post.content = 'sometimes you can almost not tell the
difference'
my_post.save!
2. Coming from a compiled
language, runtime execution is
foreign, all code is executed
code
Post.respond_to? Name
Ruby is a dynamic language
3. Classes are also like namespaces
too.
class MyClass
puts ‘Hello World’
end
# => Hello World
5. Singleton method variations on
the MyClass instance
class MyClass
def MyClass.my_method; end
def self.my_method; end
class << self
def my_method; end
end
end
6. class << Object
puts self
def my_method Different
puts ‘hi’
end
end
class Object class << Object is adding methods to the eigenclass of Object.
This method is now available to all objects as if it were a class
def self.meth2
puts self method.
puts ‘there’
end
However, opening the Object class and adding methods to self
class << self shows the current object is the instance Foo.
def meth3
puts self
puts ‘hahaha’
end
end
end
Foo = Class.new
Foo.my_method
Foo.meth2
Foo.meth3
# => #<Class:Object>
# => hi
# => Foo
# => there
# => Foo
# => hahaha
7. Including the module in the Eigenclass of
class C to create class methods
module M
def my_method
puts ‘hi’
end
end
class C
class << self
include M
end
end
C.my_method # => hi
8. Using extend to add class methods to C
module M
def my_method
puts ‘hi’
end
end
class C
extend M
end
C.my_method # => hi
9. Class methods are singletons of
the class object, that means they
are in the eigenclass
class C Self, therefore the current object, is
puts self changed by opening up the
class << self eigenclass
puts self
def my_method
puts ‘hi’
end
end
end
C.my_method # => C
# => #<Class:C>
# => hi
10. Examining self…
class Foo Self, the current object, is changed
puts self by opening up the eigenclass and
class << self we are now adding my_method to
puts self the Foo instance, but this is
def my_method equivalent to Foo.my_method
puts ‘hi’
end
end
end
Foo.my_method # => Foo
# => #<Class:Foo>
# => hi
13. Hook methods - Module#included
module Mod1
class << self
def included(othermod)
puts "Mod1 was mixed into #{othermod}"
end
end
end
class MyClass
include Mod1
end
# => Mod1 was mixed into MyClass
14. Hook methods - Module#include
(must call super if you override, to actually include
the module)
module Mod1; end
module Mod2; end
class MyClass
def self.include(*modules)
puts “#{modules} included”
super
end
include Mod1
include Mod2
end
# => [Mod1] included
# => [Mod2] included
16. module Associations This is obviously very dumbed down, but
now we can start to see some things in
def self.included(base) action.
base.extend(ClassMethods)
end We have defined the module
Associations which includes a submodule
module ClassMethods ClassMethods which will hold class
def belongs_to methods.
“I am in the ClassMethods module”
end Overriding included now acts on the
end including class which is base in this case.
end This class is sometimes called the
inclusor. The extend method adds the
class Base ClassMethods to the inclusor’s
include Associations eigenclass.
end
Now the Base class can include the
class Post < Base Associations module and our model can
belongs_to inherit from Base
end
One more step…
17. module ActiveRecord
module Associations
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def belongs_to
“I am in the ClassMethods module”
end
end
end
class Base
include Associations
end
end
class Post < ActiveRecord::Base
belongs_to
end
Add an ActiveRecord Namespace and we have something
resembling the original
18. Ghost Methods
class Post #method_missing
def initialize catches the call to
@attributes = {}
name=() or returns
end
def method_missing(name, *args) the value when it
attribute = name.to_s gets a method
if attribute =~ /=$/ without an ‘=‘
@attributes[attribute.chop] = args[0]
else It chops off the
@attributes[attribute]
equals sign to get
end
end the attribute name
end and then sets the
my_post = Post.new hash value
my_post.name = ‘Chile L’