In my Ruby application, I want to clone a class so that I can make some slight changes to the clone without affecting the original class (see the note below for details). Unfortunately, the cloned class isn't behaving the way I would expect. Specifically, class methods of the cloned class seem to have trouble accessing constants and class variables. Observe:
irb(main):001:0> class Foo
irb(main):002:1> HELLO = "Hello, world!"
irb(main):003:1> def self.say_hello
irb(main):004:2> HELLO
irb(main):005:2> end
irb(main):006:1> def self.cls_var=(val)
irb(main):007:2> @@cls_var = val
irb(main):008:2> end
irb(main):009:1> def self.cls_var
irb(main):010:2> @@cls_var
irb(main):011:2> end
irb(main):012:1> end
=> nil
irb(main):013:0> Foo.say_hello
=> "Hello, world!"
irb(main):014:0> Foo.cls_var = "Test"
=> "Test"
irb(main):015:0> Foo.cls_var
=> "Test"
irb(main):016:0> Bar = Foo.clone
=> Bar
irb(main):017:0> Bar.say_hello
NameError: uninitialized constant Class::HELLO # ???
from (irb):4:in `say_hello`
from (irb):17
from C:/Ruby193/bin/irb:12:in `<main>`
irb(main):018:0> Bar.cls_var = "Another test"
(irb):7: warning: class variable access from toplevel # Say what?
=> "Another test"
irb(main):019:0> Bar.cls_var
(irb):10: warning: class variable access from toplevel
=> "Another test"
irb(main):020:0> Foo.cls_var
=> "Another test" # Why???
What's going on here, and how do I fix this so that Bar works exactly the same as Foo does after I clone it?
Note: This question is a follow up to In Ruby, is there a way to 'override' a constant in a subclass so that inherited methods use the new constant instead of the old?
Update: Sorry guys, I guess I wasn't very clear about why I want to do this. So in my case, Foo
is a class in a gem which has functionality thats nearly identical to what I want for one of my classes. In fact, the only difference between Foo
and what I want is that pesky HELLO
constant. I want MyClass.say_hello
to return "Hello, Bob!" instead of "Hello, World!". (And before you suggest just overriding say_hello
, in my case Foo has lots of other methods that use HELLO
and say_hello
is much more complicated than it is in my example.)
Now I could just change Foo::HELLO
with Foo::HELLO.slice!(0, 7) << "Bob!"
, but that changes the behavior of the gem, which I don't want. So how would I create an exact duplicate of Foo
that has a different value for HELLO
?
TLDR: Foo is part of a gem so I don't want to edit the source. I want a class that behaves exactly the same way Foo does, except with HELLO
set to a different value.