How to define a const on the singleton class? - ruby

I want to define a constant for a single instance of an object, not for all instances of an object.
class MyTest
def call
Foo
end
end
t = MyTest.new
t.call # => NameError (as expected)
t.singleton_class.class_eval do
const_set 'Foo', 'foo'
end
t.singleton_class::Foo # => 'foo'
t.call # => NameError
Why does the const lookup not include the const defined in the objects singleton class?
Here is another attempt:
Dog = Class.new { def call; Bark; end }
d = Dog.new
d.call # => NameError (expected)
d.singleton_class.const_set('Bark', 'woof')
d.call # => NameError (not expected)

The constant has been defined in the instance's singleton class but Foo doesn't include (singleton_class)::Foo in one of its possible evaluations so specify it explicitly:
class MyTest
def call
singleton_class::Foo
end
end

I believe it is not possible:
const_set is defined on Module
Ruby looks for constant in nesting and ancestors
There is no place where to define the constant for a MyTest instance
class MyTest
def call
puts (Module.nesting + Module.ancestors).uniq.inspect
end
end
MyTest.new.call
# => [MyTest, Module, Object, Kernel, BasicObject]

I think this comment is correct - t.singleton_class.class_eval first gets the singleton_class of t and then evals something on that singleton classes' class.
Instead what you want is to define the constant on the instance of that singleton class, like so:
t.singleton_class.instance_eval do
Foo = 'foo'
end
After that, t.call returns "foo".

Start be creating an arbitrary set and an instance of that set.
class A; end
a = A.new
#=> #<A:0x00007ff0bbaa9f98>
For convenience, assign a's singleton class1 to a variable.
as = a.singleton_class
#=> #<Class:#<A:0x00007ff0bbaa9f98>>
Create a constant in as whose value equals 3.
as.const_set(:A, 3)
#=> 3
Check that the constant was defined.
as.constants
#=> [:A]
Let's check its value also.
as.const_get(:A)
#=> 3
Now let's create a method in as that references the constant we've created.
as.define_method(:cat) { puts "#{as.const_get(:A)} cats"}
#=> :cat
Try it.
a.cat
#=> "3 cats"
See Module#const_set and Module#const_get.
1. Every Ruby object has a singleton class. Singleton classes are like regular classes except they cannot be subclassed and one cannot create instances of subclasses.

Related

How to set a class variable from a class-level method when using Class.new?

I recall reading somewhere that the following two pieces of code are identical in Ruby.
# Number 1
class A
# body
end
# Number 2
A = Class.new
# body
end
However I noticed that when I try to set a class variable from a class-level method, the two syntaxes produce different results.
With the first syntax, the variable is set on the class itself as expected.
irb(main):001:0> class A
irb(main):002:1> def self.foo
irb(main):003:2> ##a = :banana
irb(main):004:2> end
irb(main):005:1> end
=> :foo
irb(main):006:0> A.class_variables
=> []
irb(main):007:0> A.foo
=> :banana
irb(main):008:0> A.class_variables
=> [:##a]
irb(main):009:0> A.class_variable_get :##a
=> :banana
irb(main):010:0> Class.class_variable_get :##a
NameError: uninitialized class variable ##a in Class
from (irb):10:in `class_variable_get'
from (irb):10
from /usr/local/bin/irb:11:in `<main>'
irb(main):011:0>
With the second, the variable gets set on Class itself!
irb(main):015:0> K = Class.new do
irb(main):016:1* def self.foo
irb(main):017:2> ##k = :banana
irb(main):018:2> end
irb(main):019:1> end
=> K
irb(main):020:0> K.class_variables
=> []
irb(main):021:0> K.foo
(irb):17: warning: class variable access from toplevel
=> :banana
irb(main):022:0> K.class_variables
=> [:##k]
irb(main):023:0> K.class_variable_get :##k
=> :banana
irb(main):024:0> Class.class_variable_get :##k
=> :banana
Why does this happen?
In what I am working on, I have to generate a class dynamically, so I have no choice but to use the second syntax. As such, how do I ensure that the variable ##k gets set on the new Class object being defined, and not on Class itself?
The two pieces are not identical, there are differences in lexical scoping of the declarations.
In the first definition, the more common class declaration, definitions are lexically scoped to class A, so the class variable is set on A. Only A and classes that inherit from A will have that class variable. Since Class does not inherit from A, it doesn't get the class variable.
In the second definition, the dynamic class assignment, the definitions are lexically scoped to top level object, which is object. So a class variable will be set on Object, the class of the top level object.
Now, this has huge implications. Every object inherits from Object and every class is an instance of the class Class, you're defining a class variable on each and every class in your object space. Hence, A gets the class variable, and Class gets it as well. Try defining a new class F, and it will have it as well. This is why Ruby screams the warning:
class variable access from toplevel
This is one of reasons why class variables are typically avoided.
There are multiple ways to solve this. My favourite is, using the attr_accessor on the class instance:
K = Class.new do
class << self
attr_accessor :fruit
end
self.fruit = :banana
end
K.fruit
# => :banana
# The value isn't shared between inherited classes,
# but the variable is:
class L < K
end
L.fruit
# => nil
L.fruit = :mango
# => :mango
K.fruit
# => :banana
Edit:
Keep in mind, that these variables are still not thread-safe, and are shared by all threads. You will need thread-local variables for ensuring thread-safety.

What this Ruby does with Class.new to create class,

Please consider the following code:
module MyClass
def foo
"method"
end
end
now, I can instantiate a new class of this by usual
#my_new_class = MyClass.new
or, I can do some meta-programming magic
#my_new_class = Class.new { include MyClass }.send :new
Questions is what is the difference between the two?
The code above is (almost) equivalent to:
MyNewClass = Class.new { include MyClass }
#my_new_class = MyNewClass.new
Which is like
class MyNewClass
include MyClass
end
#my_new_class = MyNewClass.new
using Class.new declares an anonymous new class on the fly:
Creates a new anonymous (unnamed) class with the given superclass (or Object if no parameter is given). You can give a class a name by assigning the class object to a constant.
If a block is given, it is passed the class object, and the block is evaluated in the context of this class using class_eval.
Your naming of the module is akin to sue = Boy.new, so I've changed it to befit its heritage. I trust you won't mind.
module MyModule
def foo
"method"
end
end
Let's first gather some basic information:
Module.class #=> Class
Module.ancestors #=> [Module, Object, Kernel, BasicObject]
Module.methods.include? :new #=> true
Module.new #=> #<Module:0x000001022050c8>
As you see, Module is an instance of Class and has a method :new. Now let's look at the module you created:
MyModule.class #=> Module
MyModule.ancestors #=> [MyModule]
MyModule.instance_methods #=> [:foo]
MyModule.methods.include? :new #=> false
It is an instance of Class and has just one instance method (:foo), which you created. It has no ancestors, so it does not inherit any methods. Importantly, instances of Module do not have a method :new. If we try to invoke it, therefore, the results are predictable:
my_new_module = MyModule.new
#=> NoMethodError: undefined method `new' for MyModule:Module
End of story for approach #1`.
Now gather information related to your second approach:
my_new_instance = Class.new { include MyModule }.send :new
I've changed the name of the variable my_new_class to my_new_instance, for reasons that will soon become apparent. We can write this in two steps, like this:
Class1 = Class.new { include MyModule }
Class1.instance_methods.include? :foo #=> true
Class1.methods.include? :new #=> true
Class1.method(:new).owner #=> Class
So we confirm Class1 was constructed properly, has the instance method :foo and inherits the class method :new from Class.
my_new_instance = Class1.new #=> #<Class1:0x00000101a1edc8>
my_new_instance = Class1.send :new #=> #<Class1:0x0000010204eab8>
my_new_instance.class #=> Class1
my_new_instance.is_a? Class #=> false
my_new_instance.foo # (prints) "method"
my_new_instance.send :foo # (prints) "method"
We see that my_new_instance is indeed an instance of Class1 (which can be created by either of the methods shown), and invokes :foo in either of the two ways shown.

What's the difference between self.generate and Invoice.generate?

class Invoice
def Invoice.generate(order_id, charge_amount, credited_amount = 0.0)
Invoice.new(:order_id => order_id, :amount => charge_amount, :invoice_type => PURCHASE, :credited_amount => credited_amount)
end
end
Why would you create Invoice.generate inside Invoice class rather than self.generate?
self.generate is easier to work with, whereas Invoice.generate is arguably more explicit. Other than that, there's no difference between the two.
Explanation
You can define a method on any instance using this form
def receiver.method(args)
end
Check this out
class Foo
end
def Foo.bar
"bar"
end
Foo.bar # => "bar"
And yes, I mean any instance. It's absolutely possible that one instance has some method while another doesn't
f = Foo.new
def f.quux
'quux'
end
f2 = Foo.new
f.quux # => "quux"
f2.quux # => # ~> -:20:in `<main>': undefined method `quux' for #<Foo:0x007fe4e904a6c0> (NoMethodError)
A reminder: inside of class definition (but outside of method definitions) self points to that class.
class Foo
# self is Foo
end
So, armed with this knowledge, the difference between self.generate and Invoice.generate should be obvious.
Under normal circumstances, it would practically have no difference from def self.generate.
The only edge case I can think of is if you have a nested class with the same name, then the explicit version would apply only to the nested class.
class A
def self.x
name
end
def A.y
name
end
class A
# nested class A::A
end
def self.p
name
end
def A.q
name
end
end
> A.x # => "A"
> A.y # => "A"
> A.p # => "A"
> A.q # => NoMethodError: undefined method `q' for A:Class
> A::A.q # => "A::A"
As you see, after a nested class with the same name is defined, subsequent explicit class method definitions made with the class name refer to the nested class, but explicit definitions made beforehand refer to the original.
Implicit definitions made with self always refer to the base class.
You have 2 ways for defining a class method.
1) You can use the name of the class directly
class Test #Test is now an instance of a built-in class named Class
def Test.class_method
"I'm a class method."
end
end
2) You can use the self variable, which is always pointing to the current object
class Test
def self.class_method
"I'm a class method."
end
end
Once you understand that classes are objects, this use of the self variable to define a class method finally makes sense.
The value of self
Not too surprinsingly, when you are inside a class method, the value of self refers to the object that holds the class structure (the instance of class Class). This means that :
class Test
def self.class_method
self.x
end
end
is equivalent to :
class Test
def self.class_method
Test.x
end
end
When you are inside an instance method, the value of self still refers to the current object. This time however, the current object is an instance of class Test, not an instance of class Class.
More info. : http://www.jimmycuadra.com/posts/self-in-ruby

Constants in singleton classes

I have this code:
class A
def print
puts CONSTANT
end
end
module B
CONSTANT = "Don't Panic!"
end
Suppose a is an instance of class A.
So I need a definition of CONSTANT that should be able to be found to make a.print available.
I considered to include the module B into a's singleton class like:
a.singleton_class.send :include, B
a.print # error: CONSTANT isn't found
I assumed it should be okay now to call the method but actually not.
The constant should be successfully imported as the following code works as expectation:
a.singleton_class.constants # => [.., :CONSTANT, ..]
However, by including the constant into the class instead of singleton class, it works:
a.class.send :include, B
a.print # prints: Don't Panic!
I thought it is strange that I can't refer a constant that is defined in a singleton class. If this is reasonable, I want to know why.
The class returned by singleton_class is an anonymous class which was inherited from class of the object a.
So a.class and a.singleton_class refer to different objects.
puts a.class.object_id # => 79495930
puts a.singleton_class.object_id # => 79495830
And also different classes: a.singleton_class is a child class of A.
a.singleton_class.superclass # => A
a.singleton_class.ancestors # => [B, A, Object, Kernel, BasicObject]
a.class.ancestors # => [A, Object, Kernel, BasicObject]
And because of this, a.singleton_class doesn't share its own constants to parent just like any other child class do.
puts a.class.constants # => []
puts a.singleton_class.constants # => [:CONSTANT]

Ruby and class variables in inherit class

class A
def set(v)
##v = v
end
def put
puts ##v
end
end
class B < A
end
class C < A
end
B.new.set 'b'
B.new.put # => b
C.new.set 'c'
C.new.put # => c
B.new.put # => c
Why? And how should I write this to have 'b' in last B.new.put?
Here is a nice article on the subject - Class and Instance Variables In Ruby.
Basically, what you can do is:
class A
class << self
attr_accessor :class_var
end
def set_class_var(value)
self.class.class_var = value
end
def get_class_var
self.class.class_var
end
end
class B < A; end
A.class_var = 'a'
B.class_var = 'b'
puts A.class_var # => a
puts B.class_var # => b
A.new.set_class_var 'aa'
B.new.set_class_var 'bb'
puts A.new.get_class_var # => aa
puts B.new.get_class_var # => bb
To understand it you should think about A as an instance of Class class (and that's how it is in Ruby). But every object in Ruby has its own singleton class that stores object-specific stuff like methods defined on object itself:
a = A.new
def a.foo
puts 'foo'
end
In that case foo is method defined only for a object and not for every instance of A class. And another way to define method in object's singleton class is like that:
class << a # open a's singleton class
def bar # define method that will be available only on 'a' object
puts 'bar'
end
end
In the first code snippet we use that approach to define class_var attribute accessor in the context of singleton class of our A class (it's a bit tricky, so you need to think about it). As the result class itself has class_var variable as well as its descendant class B. The difference is that every one of them has its own class_var variable that do not interfere.
Another option is to pull out class_inheritable_accessor code from Rails and include its behavior in your classes. See here for a good discussion and the guts of the code.
Perhaps you don't really want a class variable, though.
Assigning a value to a class variable (an ## variable) sets it for EVERY instance of the class. It even "sets" it for instances that "aren't created yet." So, consider this...
B.new.set 'b' # OK, that set ##v for that particular instance of B
B.new.put # Hey, you just created *another* new instance of B!
How can ##v have a value in that one? The second object's value of ##v would be unset, except for the fact that ##v is a class variable, so it has the same value for every instance of the class.

Resources