Creating a new class with an existing name - ruby

We can create a class and then create another class with the same name. That is not surprising.
[1] pry(main)> class A; end
=> nil
[2] pry(main)> a = A.new
=> #<A:0x0000000bd8a008>
[3] pry(main)> A = Class.new
(pry):3: warning: already initialized constant A
(pry):1: warning: previous definition of A was here
=> A
[4] pry(main)> new_a = A.new
=> #<A:0x0000000be001e0>
[5] pry(main)> a.class.name == new_a.class.name
=> true
[6] pry(main)> a.class == new_a.class
=> false
[7] pry(main)> a.class == A
=> false
[8] pry(main)> new_a.class == A
=> true
However, after redefining the constant we get what seems to be a collision: constant A and new_a.classmethod return the new class, while a.class returns the original class. These classes are different, yet they have the same name. How can this be possible and what exactly is going on when this code is executed?

class A; end does two things:
it creates a new class object
it assigns this class object to the constant A
Removing or resassigning the constant only affects (2), it doesn't change the class object (1).
Ruby also sets the class name when assigning a class to a constant:
A.name #=> "A"
The class name is stored in a special instance variable (see below) and you see this name when inspecting an instance of your class:
A.new
#=> #<A:0x007febc1230848>
# ^
# |
# +- this is A.name
The class name is independent of the constant a class is assigned to:
B = A
B.name #=> "A"
B.new #=> #<A:0x007febc1313e68>
And this is why you can create multiple classes with the same name.
How the class name is stored internally
Ruby stores the class name in a special instance variable __classpath__. It can't be accessed from within Ruby, but if you would remove this restriction (I've patched Ruby for this example), you could read it:
A.instance_variable_get('__classpath__') #=> "A"
and even change it:
a = A.new #=> #<A:0x007fe0cd03ad30>
A.instance_variable_set('__classpath__', 'just a name')
A.name #=> "just a name"
a #=> #<just a name:0x007fe0cd03ad30>

These classes are different, yet they have the same name. How can this be possible and what exactly is going on when this code is executed?
It's perfectly possible for two different objects to return the same value when you call a certain method. There's really nothing sophisticated about that:
a = [1, 2]
b = 'AB'
a.size # => 2
b.size # => 2
Note that both a and b return 2 when I call size, but that does not imply any sort of relationship at all between a and b.

It’s the same like having two “John Smith” entries in your phonebook. Consider we have a class:
class A
def whoami
puts 'original'
end
end
Let’s now instantiate it:
a = new A
a_frozen = new A
a.whoami
#⇒ original
a_frozen.whoami
#⇒ original
Let’s modify a’s eighenclass:
class << a
def whoami
'modified'
end
end
a.whoami
#⇒ modified
a_frozen.whoami
#⇒ original
And, of course, it’s still like:
a.class.name == a_frozen.class.name == 'A'
Name is the name only, nothing more. And there is no problem for different class instances share the same name.
Hope it helps.

a and new_a are instances of two different classes.
You can access these classes with a.class and new_a.class.
These classes are two instances of Class. They appear to have the same name they really are different classes, with different methods, etc.
class A
def a
end
end
a= A.new
A = Class.new
new_a = A.new
puts a.respond_to?(:a) # => true
puts new_a.respond_to?(:a) # => false

Related

Why include module affeacting all my instance object?

This has been puzzling me:
class Entry
end
module A
def test
print "A"
end
end
class Entry
include A
end
i = Entry.new
i.test # --> print 'A', expected
p i.class.ancestors # --> [Entry, A, Object, Kernel, BasicObject]
module B
def test
print "B"
end
end
class Entry
include B
end
ii = Entry.new
ii.test # --> print 'B', expected
p ii.class.ancestors # --> [Entry, B, A, Object, Kernel, BasicObject]
i.test # --> print 'B', now this is unexpected!
p i.class.ancestors # --> [Entry, B, A, Object, kernel, BasicObject] --> WHY?
It seems include is changing all instance internal state too. Is there any reason it behave that way?
Thanks!
It is actually a pretty expected behaviour. In ruby, pretty much everything is a reference. object.class is a reference to an instance of Class class, and instances of Class are fully mutable.
Your i object holds a reference to Entry class, so does ii. When you do Entry.include B you modify the existing Entry class which will affect all the object that holds any reference to it. It is conceptually similar to:
class A
def initialize(str)
#str = str # holding reference to string object
end
attr_reader :str
end
string = 'hello'
a = A.new(string)
a.str #=> "hello"
string << " there" # modifying the string object
a.str #=> "hello there"
a.str.object_id == string.object_id #=> true
Now imagine how difficult it would be to work with a code where two instances of the same class would have different behaviour.
If you want some instances to have slightly different behaviour, you need to either use subclasses
class BEntry < Entry
include B
end
Entry.new.test #=> 'A'
BEntry.new.test #=> 'B'
or you can make use of singleton classes of specific objects (warning - this can make the code a bit less maintainable)
a = Entry.new
b = Entry.new
b.extend(B)
a.test #=> 'A'
b.test #=> 'B'

Struct with and without member

I'm a new Rubyist, currently I'm going to use the Struct in class in order to create a temporary object. However, I encounter a question when I use a member in Struct like this:
class A
attr_accessor :b
B = Struct.new(:name, :print_name) do
def print_name
p "Hello #{name}"
end
end
def initialize(input_name)
#b = B.new(input_name)
end
end
a = A.new('Leo')
a.b.print_name # Hello Leo
But I also receive the same result when my Struct B params don't include :print_name.
B = Struct.new(:name) do
...
end
So what is the different ? And when should I use the member param and when I'm not ?
Thanks
In first case you define a class which's initializer takes two arguments - name and print_name.
In second case you define a class which's initializer takes single argument - name.
These has nothing to do with the fact, that you are defining an instance method called print_name.
So instances of both classes (with and without print_name argument) have print_name method defined, thus both examples work identically.
The difference will be visible when you inspect created objects:
# first case with two arguments
foo = B.new(:a, :b)
foo.inspect
=> "#<struct B name=:a, print_name=:b>"
# second case with single argument
foo = B.new(:a)
foo.inspect
=> "#<struct B name=:a>"
Also, when you'll check instance methods of B class for both cases, you can see the difference:
# first case with two arguments
B.instance_methods false
#=> [:name, :name=, :print_name, :print_name=]
# second case with single argument
B.instance_methods false
#=> [:name, :name=, :print_name]
But I also receive the same result when my Struct B params don't
include :print_name
The difference, is that in first case you are able to do the following:
a.b.print_name = 'new print name'
a.b.inspect
#=> "#<struct B name='Leo', print_name='new print name'>"
Whereas in second case it will fail:
a.b.print_name = 'new print name'
#=> NoMethodError: undefined method 'print_name=' for #<struct B name='Leo'>

How to define a const on the singleton class?

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.

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]

Adding an instance variable to a class in Ruby

How can I add an instance variable to a defined class at runtime, and later get and set its value from outside of the class?
I'm looking for a metaprogramming solution that allows me to modify the class instance at runtime instead of modifying the source code that originally defined the class. A few of the solutions explain how to declare instance variables in the class definitions, but that is not what I am asking about.
Ruby provides methods for this, instance_variable_get and instance_variable_set. (docs)
You can create and assign a new instance variables like this:
>> foo = Object.new
=> #<Object:0x2aaaaaacc400>
>> foo.instance_variable_set(:#bar, "baz")
=> "baz"
>> foo.inspect
=> #<Object:0x2aaaaaacc400 #bar=\"baz\">
You can use attribute accessors:
class Array
attr_accessor :var
end
Now you can access it via:
array = []
array.var = 123
puts array.var
Note that you can also use attr_reader or attr_writer to define just getters or setters or you can define them manually as such:
class Array
attr_reader :getter_only_method
attr_writer :setter_only_method
# Manual definitions equivalent to using attr_reader/writer/accessor
def var
#var
end
def var=(value)
#var = value
end
end
You can also use singleton methods if you just want it defined on a single instance:
array = []
def array.var
#var
end
def array.var=(value)
#var = value
end
array.var = 123
puts array.var
FYI, in response to the comment on this answer, the singleton method works fine, and the following is proof:
irb(main):001:0> class A
irb(main):002:1> attr_accessor :b
irb(main):003:1> end
=> nil
irb(main):004:0> a = A.new
=> #<A:0x7fbb4b0efe58>
irb(main):005:0> a.b = 1
=> 1
irb(main):006:0> a.b
=> 1
irb(main):007:0> def a.setit=(value)
irb(main):008:1> #b = value
irb(main):009:1> end
=> nil
irb(main):010:0> a.setit = 2
=> 2
irb(main):011:0> a.b
=> 2
irb(main):012:0>
As you can see, the singleton method setit will set the same field, #b, as the one defined using the attr_accessor... so a singleton method is a perfectly valid approach to this question.
#Readonly
If your usage of "class MyObject" is a usage of an open class, then please note you are redefining the initialize method.
In Ruby, there is no such thing as overloading... only overriding, or redefinition... in other words there can only be 1 instance of any given method, so if you redefine it, it is redefined... and the initialize method is no different (even though it is what the new method of Class objects use).
Thus, never redefine an existing method without aliasing it first... at least if you want access to the original definition. And redefining the initialize method of an unknown class may be quite risky.
At any rate, I think I have a much simpler solution for you, which uses the actual metaclass to define singleton methods:
m = MyObject.new
metaclass = class << m; self; end
metaclass.send :attr_accessor, :first, :second
m.first = "first"
m.second = "second"
puts m.first, m.second
You can use both the metaclass and open classes to get even trickier and do something like:
class MyObject
def metaclass
class << self
self
end
end
def define_attributes(hash)
hash.each_pair { |key, value|
metaclass.send :attr_accessor, key
send "#{key}=".to_sym, value
}
end
end
m = MyObject.new
m.define_attributes({ :first => "first", :second => "second" })
The above is basically exposing the metaclass via the "metaclass" method, then using it in define_attributes to dynamically define a bunch of attributes with attr_accessor, and then invoking the attribute setter afterwards with the associated value in the hash.
With Ruby you can get creative and do the same thing many different ways ;-)
FYI, in case you didn't know, using the metaclass as I have done means you are only acting on the given instance of the object. Thus, invoking define_attributes will only define those attributes for that particular instance.
Example:
m1 = MyObject.new
m2 = MyObject.new
m1.define_attributes({:a => 123, :b => 321})
m2.define_attributes({:c => "abc", :d => "zxy"})
puts m1.a, m1.b, m2.c, m2.d # this will work
m1.c = 5 # this will fail because c= is not defined on m1!
m2.a = 5 # this will fail because a= is not defined on m2!
Mike Stone's answer is already quite comprehensive, but I'd like to add a little detail.
You can modify your class at any moment, even after some instance have been created, and get the results you desire. You can try it out in your console:
s1 = 'string 1'
s2 = 'string 2'
class String
attr_accessor :my_var
end
s1.my_var = 'comment #1'
s2.my_var = 'comment 2'
puts s1.my_var, s2.my_var
The other solutions will work perfectly too, but here is an example using define_method, if you are hell bent on not using open classes... it will define the "var" variable for the array class... but note that it is EQUIVALENT to using an open class... the benefit is you can do it for an unknown class (so any object's class, rather than opening a specific class)... also define_method will work inside a method, whereas you cannot open a class within a method.
array = []
array.class.send(:define_method, :var) { #var }
array.class.send(:define_method, :var=) { |value| #var = value }
And here is an example of it's use... note that array2, a DIFFERENT array also has the methods, so if this is not what you want, you probably want singleton methods which I explained in another post.
irb(main):001:0> array = []
=> []
irb(main):002:0> array.class.send(:define_method, :var) { #var }
=> #<Proc:0x00007f289ccb62b0#(irb):2>
irb(main):003:0> array.class.send(:define_method, :var=) { |value| #var = value }
=> #<Proc:0x00007f289cc9fa88#(irb):3>
irb(main):004:0> array.var = 123
=> 123
irb(main):005:0> array.var
=> 123
irb(main):006:0> array2 = []
=> []
irb(main):007:0> array2.var = 321
=> 321
irb(main):008:0> array2.var
=> 321
irb(main):009:0> array.var
=> 123
Readonly, in response to your edit:
Edit: It looks like I need to clarify
that I'm looking for a metaprogramming
solution that allows me to modify the
class instance at runtime instead of
modifying the source code that
originally defined the class. A few of
the solutions explain how to declare
instance variables in the class
definitions, but that is not what I am
asking about. Sorry for the confusion.
I think you don't quite understand the concept of "open classes", which means you can open up a class at any time. For example:
class A
def hello
print "hello "
end
end
class A
def world
puts "world!"
end
end
a = A.new
a.hello
a.world
The above is perfectly valid Ruby code, and the 2 class definitions can be spread across multiple Ruby files. You could use the "define_method" method in the Module object to define a new method on a class instance, but it is equivalent to using open classes.
"Open classes" in Ruby means you can redefine ANY class at ANY point in time... which means add new methods, redefine existing methods, or whatever you want really. It sounds like the "open class" solution really is what you are looking for...
I wrote a gem for this some time ago. It's called "Flexible" and not available via rubygems, but was available via github until yesterday. I deleted it because it was useless for me.
You can do
class Foo
include Flexible
end
f = Foo.new
f.bar = 1
with it without getting any error. So you can set and get instance variables from an object on the fly.
If you are interessted... I could upload the source code to github again. It needs some modification to enable
f.bar?
#=> true
as method for asking the object if a instance variable "bar" is defined or not, but anything else is running.
Kind regards, musicmatze
It looks like all of the previous answers assume that you know what the name of the class that you want to tweak is when you are writing your code. Well, that isn't always true (at least, not for me). I might be iterating over a pile of classes that I want to bestow some variable on (say, to hold some metadata or something). In that case something like this will do the job,
# example classes that we want to tweak
class Foo;end
class Bar;end
klasses = [Foo, Bar]
# iterating over a collection of klasses
klasses.each do |klass|
# #class_eval gets it done
klass.class_eval do
attr_accessor :baz
end
end
# it works
f = Foo.new
f.baz # => nil
f.baz = 'it works' # => "it works"
b = Bar.new
b.baz # => nil
b.baz = 'it still works' # => "it still works"

Resources