I'm implementing a semi-duplicate Rails pipeline by refactoring an existing Ruby class, say A, which extends ActiveRecord, to have a module, say M, with common functionality, then to be mixed into two similar AR classes, now shallow wrappers.
When taking the meat of A and mincing it into M, A's instance methods simply become methods in M, and A's class methods go into a ClassMethods submodule of M, to be mixed back into A at class-level with a self.included hook of M and extend, via the well-known idiom.
However, A is not just any class -- we use some of its class methods from DelayedJob, which does not naturally understand class methods; hence we moved some of the original class methods of A into A's eigenclass, defining them as
class A
...
def old_plain_vanilla_class_method
...
end
class << self
def new_eigenclassed_class_method
...
end
...
end
...
end
The question now is, how do we represent that in M, so it mixes right back into A's eigenclass?
Not sure that I understand you well (more code please), but can't you do something like this:
module M
def M.included(c)
class << c.class
def foo
"foo"
end
end
end
end
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
While creating a class, we use the keyword class like:
class Abc
Z = 5
def add
puts "anything here"
end
end
In console, Abc.class # => Class
How does Abc internally become a class? What is the difference between class and Class?
It would be great if anyone could explain how class constants and method are internally called, and if a method is not defined, then how we get the exception "undefined class method". What is the internal logic behind it?
There are three different things here:
class is a keyword, which is used to define or reopen a class
Object#class is a method, which returns the class of a given object
Class is the class which all classes are an instance of (including Class itself)
ndn's answer gives a nice overview of the different things "class" could refer to.
To answer your specific question:
How does Abc internally become a class?
Almost like any other object.
class Abc
end
is equivalent to:
Abc = Class.new do
end
It creates a new instance of Class and assigns it to the constant Abc.
To see what the different "class" things in Ruby mean, check out my other answer.
As for how methods are looked up:
There are multiple places a method can come from:
The class of the object
The parent of the class of the object
Modules, which are included/prepended
The singleton class of the object
The order of lookup is the following:
If it exists, the singleton class
Prepended modules
Methods defined in the class
Included modules
Recursively, the above rules for the parent class
There are a few things that have to be noted here:
If multiple modules are included/prepended, they will be looked up in the reverse order of how they were included/prepended
If a module was already included/prepended in one of the parrents, it won't be included/prepended again
If using these rules the method was not found til the very start of the hierarchy (BasicObject), the ancestor chain is searched again for a different method, called method_missing
BasicObject#method_missing is defined so that it throws a NoMethodError and that is where the error comes from
module M1
def foo
puts 'Defined in M1'
end
end
module M2
def foo
puts 'Defined in M2'
end
end
class C
include M1
prepend M2
def foo
puts 'Defined in C'
end
def method_missing(method_name)
puts 'Method missing' if method_name == :foo
end
end
c = C.new
# singleton method
def c.foo
puts "Defined in c's singleton"
end
puts c.singleton_class.ancestors
# => [#<Class:#<C:0xa2d0f8>>, M2, C, M1, Object, Kernel, BasicObject]
# ^ the singleton class,
# the prepended module,
# the C class itself,
# the included module,
# the rest of the hierarchy
# (Object is the implicit parent of all classes with no explicit parent)
with class Abc you define a class.
Abc.class is returning the Type, and the type of Abc is a Class
another example:
1337.class
=> Fixnum
"hi babe!".class
=> String
12.55.class
=> Float
(1..12).class
=> Range
so as you can see, each "datatype" is a class. in your case Abc is also a Datatype. And for the end of that chain, the class of a class is Class! :-)
Answering second par of the question, undefined class method happens when method you called is not present in such class - classes are just objects in Ruby, and as such they have their own set of methods. Ruby has several ways to define class methods, most common is probably
class Klass
def self.klass_method
...
end
end
the other is
class Klass
# some ordinary instance methods here
class << self
def klass_method
# this is class method
end
end
end
Some Rubyists prefer the latter, as it keeps all class methods in single block, but they are equivalent.
I'm going through the Ruby Koans Ruby Koans and I'm at a place in "about_class_methods.rb" where there is a discussion of setting up class methods, and the Koans talk about three ways.
The two major ways to write class methods are:
1:
class Demo (define/open class)
def self.method
end
2:
class << self
def class_methods
end
end
The koans also talk about a third method, I've never seen (that I remember):
def Demo.class_method_third_way
end
Q1 This third way is actually clearer to me than any other. Is there a reason I don't understand about why no one uses it?
Q2 Why am I wrong in thinking the syntax for 2 should be "self << def name end"? That is "Why is the syntax the way it is?" Does the class Object hold a reference to all Classes and this sticks in the method for the self class?
As always, thanks for your help and patience!
In (early) development classes get renamed as insight grows (not Person but Employee, not Job but one or more Roles etc.) This renaming is prone to errors if the class name is hardcoded in the class itself.
In class body, self refers exactly the class object being defined. That's why def self.some_method works the same as def Demo.some_method.
class Demo
puts self.object_id == Demo.object_id
end
#=> true
class << some_obj is the syntax to access the singleton class of some_obj. Refer to the Ruby doc:
The singleton class (also known as the metaclass or eigenclass) of an object is a class that holds methods for only that instance. You can access the singleton class of an object using class << object ... Most frequently you’ll see the singleton class accessed like this:
class C
class << self
# ...
end
# or
class << C
end
end
Given a class A and a module B, mixin the instance methods of B so that it overrides the correspnding instance methods of A.
module B
def method1
"B\#method1"
end
def method2
"B\#method2"
end
end
class A
def method1
"A\#method1"
end
def method2
"A\#method2"
end
# include B does not override instance methods!
# (module gets mixed into the superclass)
end
puts A.new.method1 # want it to print out "B#method1"
puts A.new.method2 # want it to print out "B#method2"
Module#include inserts the module M as a superclass of the class C. So, you can't override C's methods in M, rather it's the other way around: C's methods override M's methods. (Technically speaking, Ruby doesn't make M a superclass of C, rather it creates an invisible Include Class ⟦M′⟧ whose method table and constant table point to M's method table and constant table, and makes that class the superclass, but this distinction is not important for this particular question.)
In Ruby 2.0, there is a new method, Module#prepend which, just as the name implies, prepends M to C's ancestors, in other words, makes M a subclass of C.
So, in short: you can't, at least not yet.
You could remove each of B's methods from A before including B.
class A
def method1
"A\#method1"
end
def method2
"A\#method2"
end
B.instance_methods(false).each { |method|
remove_method(method) if instance_methods(false).include?(method)
}
include B
end
Or from within B:
module B
def method1
"B\#method1"
end
def method2
"B\#method2"
end
def self.append_features(mod)
instance_methods(false).each { |method|
mod.send(:remove_method, method) if mod.instance_methods(false).include?(method)
}
super
end
end
I personally don't have anything against this, apart from the fact that's is long, but what really bothers me is the word eval.
I do a lot of stuff in JavaScript and I run from anything resembling eval like it's the devil, I also don't fancy the fact that the parameter is a string (again, probably because it's eval).
I know I could write my own method to fix the method-name-length problem, my 'method name issue' and the parameter-being-a-string thingy, but what I really want to know is: Is there a better, shorter, fancier, yet native, way of doing class_eval to extract class variables?
Side note: I know about the existence of class_variable_get() and class_variables(), but they don't really look appealing to me; horribly long, aren't they?
EDIT: Updated the question to be more specific.
Thanks!
Use class_variable_get, but only if you must
class_variable_get is the better way, other than the fact that it is not "appealing" to you. If you are reaching inside a class and breaking encapsulation, perhaps it is appropriate to have this extra barrier to indicate that you're doing something wrong.
Create accessor methods for the variables you want to access
If these are your classes, and accessing the variables doesn't break encapsulation, then you should create class accessor methods for them to make it easier and prettier:
class Foo
def self.bar
##bar
end
end
p Foo.bar
If this is your class, however, are you sure that you need class variables? If you don't understand the implications (see below), you may actually be wanting instance variables of the class itself:
class Foo
class << self
attr_accessor :bar
end
end
Foo.bar = 42
p Foo.bar
The behavior of class variables
Class variables appear to newcomers like the right way to store information at a class level, mostly because of the name. They are also convenient because you can use the same syntax to read and write them whether you are in a method of the class or an instance method. However, class variables are shared between a class and all its subclasses.
For example, consider the following code:
class Rectangle
def self.instances
##instances ||= []
end
def initialize
(##instances ||= []) << self
end
end
class Square < Rectangle
def initialize
super
end
end
2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]
Square.new
p Square.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>, #<Square:0x25c76d0>]
Ack! Rectangles are not squares! Here's a better way to do the same thing:
class Rectangle
def self.instances
#instances ||= []
end
def initialize
self.class.instances << self
end
end
class Square < Rectangle
def initialize
super
end
end
2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]
2.times{ Square.new }
p Square.instances
#=> [#<Square:0x25c76d0>, #<Square:0x25c76b8>]
By creating an instance variable and accesor methods on the class itself—which happens to be an instance of the Class class, similar to MyClass = Class.new—all instances of the class (and outsiders) have a common, clean location to read/write information that is not shared between other classes.
Note that explicitly tracking every instance created will prevent garbage collection on 'unused' instances. Use code like the above carefully.
Using class_eval in a cleaner manner
Finally, if you're going to use class_eval, note that it also has a block form that doesn't have to parse and lex the string to evaluate it:
Foo.class_eval('##bar') # ugh
Foo.class_eval{ ##bar } # yum