In this example from The Ruby Programming Language (p.270), I'm confused why the instance_eval method on the last line of the sample code defines a class method called String.empty.
Don't you use class_eval to define a class method and instance_eval when you want to define an instance method?
o.instance_eval("#x") # Return the value of o's instance variable #x
# Define an instance method len of String to return string length
String.class_eval("def len; size; end")
# Here's another way to do that
# The quoted code behaves just as if it was inside "class String" and "end"
String.class_eval("alias len size")
# Use instance_eval to define class method String.empty
# Note that quotes within quotes get a little tricky...
String.instance_eval("def empty; ''; end")
Don't you use class_eval to define a
class method and instance_eval when
you want to define an instance method?
Unfortunately, it is not as straightforward as that.
First take a closer look at what the examples of class_eval are doing. class_eval is a method which comes from Ruby's module class so can be called on any class or module. When you use String.class_eval you are evaluating the given code in the context of the class. i.e. when you write String.class_eval("def len; size; end") it's exactly like you reopened the class and typed the code passed to class_eval e.g.
class String
def len
size
end
end
Thus to add a class method using class_eval you would write String.class_eval("def self.empty; ''; end") which has the same effect as:
class String
def self.empty
''
end
end
instance_eval is defined in Ruby's Object class so is available on any Ruby object. In the general case it can be used to add a method to a specific instance. e.g. if we have a String str and say:
str.instance_eval("def special; size; end")
Then this will alias special to size just for str but not for any other String object:
irb(main):019:0> "other".special
NoMethodError: undefined method `special' for "other":String
from (irb):19
To understand what is going on with String.instance_eval remember that the class String is itself an object (an instance of the class Class) and that there is such a singleton instance object of every class defined. When you use String.instance_eval you are evaluating the given code in the context of the String instance object. i.e. it is equivalent to reopening String's metaclass and typing the code passed e.g.
class String
class << self
def empty
''
end
end
end
This is the general theme:
Use ClassName.instance_eval to define
singleton methods.
Use ClassName.class_eval to define
instance methods.
This post has a very neat explanation, give it a shot...
Related
I have the following code example:
drop_class = eval "class #{self}::LiquidDropClass < Liquid::Drop; self; end"
I understand what it's doing, but I don't understand why self is returned within the class definition. Is this even necessary, or is it an artefact of the eval class definition method?
In this case, methods are added later on to the class.
UPDATE
My confusion is around this:
class XYZ:::LiquidDropClass < Liquid::Drop
end
vs
eval "class XYZ::LiquidDropClass < Liquid::Drop; self; end"
I don't need the self in the first example and the class is created fine.
The value of a class (and module) definition body (note that a class definition body is an expression, and thus has a value; in fact, everything in Ruby is an expression and thus has a value, there are no statements) is the value of the last expression evaluated inside the class definition body. If self weren't the last expression inside that particular class definition body, the class definition body would be empty, and thus its value would be nil, i.e. drop_class would be nil.
Before Object#singleton_class was added to the core library, the idiomatic way to get a reference to the singleton class was to open the singleton class and have it evaluate to self, e.g.:
class Object
def singleton_class; class << self; self end end
end
Note that this particular piece of code, doesn't actually require eval, it could just as well (and probably clearer) be written as (untested):
drop_class = class const_get(to_s)::LiquidDropClass < Liquid::Drop; self end
Actually, in both cases the class can also be retrieved via other means, so assigning it to drop_class (and thus evaluating self) is not strictly necessary.
Given a class like:
class Thing
CONSTANT = 10
# other code
end
And another like:
class Other
def initialize
#thing = Thing.new
end
def method
puts CONSTANT
end
end
Is it possible to extend Forwardable to have Other's CONSTANT delegate to Thing's constant?
I have tried extendingSingleForwardable (see docs here ) like so:
class Other
extend SingleForwardable
def initialize
#thing = Thing.new
end
def method
puts CONSTANT
end
def_single_delegator :#thing, :CONSTANT
end
and:
def_single_delegator :#thing, :constant
but neither worked, am I getting the syntax wrong? If not, is there another way?
This one is answered by the documentation (bold emphasis mine):
def_single_delegator(accessor, method, new_name=method)
Defines a method method which delegates to accessor (i.e. it calls the method of the same name in accessor). If new_name is provided, it is used as the name for the delegate method.
So, no, you can only delegate message sends, not constant lookup.
Forwardable (and SingleForwardable) let you add class functions to your current class via a module. When you write a delegator you're specifying which methods are being passed on to the receiving object from the original module.
In your example, def_single_delegator :#thing, :CONSTANT is being interpreted as the following: Defines a method :CONSTANT which delegates to accessor :#thing (i.e. it calls the method of the same name in accessor).
As you can see, this is not passing on the value of the constant, instead it's passing on a method with the same name as the constant. If you want to pass on the same value as the constant you can provide an accessor method that returns to you the value of the original constant so that you can assign it in this class.
What is difference between class and Class.new & module and Module.new?
I know that:
Class.new/Module.new create an anonymous class/module. When we assign it to constant for the first time it becomes name of that class/module. class/module do this automatically.
When we want to inherit, we can pass an argument: Class.new(ancestor). When we don't specify an ancestor, it is set to the Object. class use this syntax: class A < Ancestor
Class.new returns an object. class A returns nil. Same goes for modules.
Did I miss something?
The interesting point that you missed between class keyword and Class::new is - Class::new accepts block. So when you will be creating a class object using Class::new you can also access to the surrounding variables. Because block is closure. But this is not possible, when you will be creating a class using the keyword class. Because class creates a brand new scope which has no knowledge about the outside world. Let me give you some examples.
Here I am creating a class using keyword class :
count = 2
class Foo
puts count
end
# undefined local variable or method `count' for Foo:Class (NameError)
Here one using Class.new :
count = 2
Foo = Class.new do |c|
puts count
end
# >> 2
The same difference goes with keyword module and Module::new.
Class.new returns an object. class A returns nil. Same goes for modules.
That's wrong. A class/module definition returns the value of the last expression evaluated inside of the class/module body:
class Foo
42
end
# => 42
Typically, the last expression evaluated inside of a class/module body will be a method definition expression, which in current versions of Ruby returns a Symbol denoting the name of the method:
class Foo
def bar; end
end
# => :bar
In older versions of Ruby, the return value of a method definition expression was implementation-defined. Rubinius returned a CompiledMethod object for the method in question, whereas YARV and most others simply returned nil.
I can create a class using a constant name with class keyword:
class MyClass1; end
I can also create a class with Class.new and assign that to a constant or a variable:
MyClass2 = Class.new do; end
myClass3 = Class.new do; end
but I cannot create a class using class keyword with a name that begins in lowercase:
class myclass4; end # => Error
Is there a fundamental difference between these four? Isn't myclass3 a regular class?
The first method (class MyClass; end) is an explicit part of the language syntax (in that class is a keyword), and the class’s name must be a constant.
The second method (Class.new) is just a normal method call, and returns an anonymous instance of Class. This anonymous instance can then be treated like any other object.
Other than that, there are no differences between the two methods. Note that you can still assign the first type into a non-constant, but it must also first be assigned into a constant:
class MyClass; end
my_class = MyClass
Similar to Andrew Marshall's answer, but also different.
Think of it this way:
The class Foo ... syntax does more than defining a class; in addition to defining a class, it necessarily names it when called for the first time, and a class name must be a constant. Note that, in principle, a class can be nameless (see #3).
On the other hand, assignment can be done to a variable or a constant. There is no restriction to that.
A purer way to create a class is to use Class.new. Using this syntax, you do not have to name it. So it is okay to assign it to a variable:
foo = Class.new
# => #<Class:0x007f36b23159a8>
Only when it is assigned to a constant for the first time does it get named:
Foo = foo
# => Foo
class MyClass
def instance_variable=(var)
puts "inside getter"
instance_variable = var
end
def function_1
self.instance_variable = "whatever"
end
def function_2
#instance_variable = "whatever"
end
end
myclass = MyClass.new
myclass.function1
results wiht "inside getter" on the console
myclass.function2
does not.
Im new to Ruby, do not know the difference, couldnt find it on the web...
Thanks in advance!
EDIT:
I assumed that by appending the "=", I overwrite a getter method for an implicitly defined instance variable "instance_variable."
That's also the reason why I called it that way.
Im not used to be allowed to use "=" in function names.
Thats why I assumed it would had some special meaning.
Thanks for your help.
EDIT2:
I just thought I really overwrite the assignment and not only the getter. I got it all mixed up.
Sorry and Thanks.
You have (misleading) named your setter instance_variable. It is not an instance variable, it is a method that sets an instance variable.
When you call self.instance_variable= you are calling that method. When you set #instance_variable directly you are setting the variable itself, and that is why the setter method is not called.
A more idiomatic naming convention would be something like:
def name=(value)
#name = value
end
Of course, for simply, pass-through type getters and setters you can use
attr_reader :name #generates getter only
attr_writer :name #generates setter only, not very common
attr_accessor :name #generates getter and setter
The above methods are syntactic sugar which generate the get and/or set methods for you. They can be overriden later to provide additional functionality if needed.
EDIT: I see that you have made an update and just wanted to point out that this method doesn't set an instance variable at all:
def instance_variable=(var)
puts "inside getter"
instance_variable = var
end
In this case instance_variable is simply a local variable and will be discarded as soon as the method exits. Local variables take precedence over instance methods, and instance variables always begin with a # symbol.