Try using define_method. Def puts you inside a new scope.
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
item.singleton_class.send(:define_method, :singl) do
[self, @a].join(" + ")
end
item
end
end
test = Test.new("cao")
item = test.item
item.singl #=> "hola + "
In your example though, you still have a problem, inside the singleton class of a string @a hasn't been defined. This is primarily because self in this context is the string instance, not a test instance where @a exists. To fix this you can rebind the instance variable to something else, but this might not be the behavior you're looking for. You can also, set the instance variable in your new singleton class.
For example,
Rebind the variable
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
new_self = self
item.singleton_class.send(:define_method, :singl) do
[self, new_self.instance_variable_get(:@a)].join(" + ")
end
item
end
end
test = Test.new("cao")
item = test.item
item.singl
Set a instance string variable
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
item.singleton_class.send(:define_method, :singl) do
[self, @a].join(" + ")
end
item.singleton_class.send(:define_method, :set) do
@a = "cao"
end
item
end
end
test = Test.new("cao")
item = test.item
item.set
item.singl
Its important to note the differences between the two methods. In the first method, we retain a reference to the original instance variable, via the original object. In the second method, we make a new instance variable, bound under the new singleton class, containing a copy of the original test.@a.
If you are using a non-native object you may be able to get away with a mixture of both methods. Referencing the old instance variable's object with the singelton classes new instance variable via a pointer, but this won't work for int, string, float, etc...
EDIT: As Benoit pointed out, in the second method the "set" method should just be an attr_accessor. In fact, you can set the instance variable without defining a new method at all. Via item.instance_variable_set(:@, "cao")