Class A
def foo
do s.t
end
end
class B
def initialize
#bar = Thread::new{
A::new
}
#Here I want to call A.foo in the thread #bar
end
end
bar = B::new
I want to start a new thread with the class A. How can I call the method foo from class B?
I think you are confused about your problem. Firstly, you say
I want to start a new thread with the class A
but it is unclear what you mean by that. You can't start a thread 'with' a class. Secondly, you say
Here I want to call A.foo in the thread #bar
but you're not inside the block that is being executed in the new Thread at that point. Even if you were, there is no class method 'foo' of class A, so A.foo will only result in a NoMethodError. Then you say you want to
call the method foo from class B?
even though the comment about calling foo is in an instance of B.
So, I'm assuming you mean the following:
Class A
def foo
end
end
class B
def initialize
#bar = Thread::new{
a = A::new
}
# Here I want to call a.foo
end
end
bar = B::new
Now, in that case, your problem is that the new instance of A that you created is local to the block that the thread #bar executes. It is not an instance variable of the Thread instance that you created and you cannot access any method of that instance. However, what you can do is create that instance beforehand and share it with the thread:
class B
def initialize
a = A.new
#bar = Thread::new {
do_stuff_with a
}
a.foo
end
This will work just fine. Of course, you run into concurrency hell and all problems generally associated with using threads. Beware.
Related
I'd like to reference an object while instantiating it in order to pass it to another object I'm instantiating. What I mean:
A.new(B.new(self))
In this case, self would refer to the scope in which I'm actually calling A.new. What I want is for self (or whatever other keyword) to refer to the newly instantiated A object, so that B would have a reference to A. Is there a way to do this?
The way you have written it (A.new(B.new(self))) is impossible, due to a circular reference.
In order to create an instance of A, you need an instance of B; in order to create the instance of B, you need the instance of A.
There are a few ways you tweak the implementation to make this possible, but you must first resolve this chicken-and-egg problem between the A and B. For example:
class A
def initialize
#b = yield(self)
end
end
class B
def initialize(a)
#a = a
end
end
A.new { |a| B.new(a) }
Note that in the above code, a is being initialized first. It is only being yielded in the scope after the object has been created.
Or, here's another way:
class A
def initialize
#b = B.new(self)
end
end
class B
def initialize(a)
#a = a
end
end
A.new
Like above, the instance of A is being created first. But this time, I've done all the initialization in one go rather than building it within the new() methed call.
One final example:
class A
attr_writer :b
def initialize
end
end
class B
def initialize(a)
#a = a
end
end
A.new.tap { |a| a.b = B.new(a) }
In this example, I have fully initialized a before defining its attribute of b. This could just as easily have been written in two lines of code, with a regular variable instead of the closure:
a = A.new
a.b = B.new(a)
Is there a way to count the amount of instances that get created as long as the program is running?
Something like
class Foo
#bar = 0
def initialize
#bar += 1
end
end
won't work (#bar is nil in initialize).
Can this be done somehow?
You should use a class variable instead of an instance variable:
class Foo
##count = 0
def initialize
##count += 1
end
def Foo.get_count
##count
end
end
foo1 = Foo.new
foo2 = Foo.new
foo3 = Foo.new
puts Foo.get_count
# => 3
Instance variables belong to objects (aka instances), that's why they are called instance variables after all. Your first #bar is an instance variable of Foo, your second #bar is an instance variable of the newly-created instance of Foo. Those are two completely different objects (they aren't even of the same class: the newly-created instance is of class Foo, whereas Foo is of class Class).
You obviously need to increment #bar in a method called on Foo, not in a method called on instances of Foo. So, can we think about a method that is a) called on Foo and b) called everytime an instance is created? What about new?
class Foo
#bar = 0
def self.new(*)
#bar += 1
super
end
end
Okay, technically speaking, this doesn't count the number of instances, only the number of times new was called. Sometimes, instances get created without calling new, e.g. when de-serializing. This should be the closest you can get without resorting to ugly hacks of the interpreter internals.
You might think you can override allocate instead (I thought so, too), but I just tested it and it doesn't work. Presumably, the default implementation of new doesn't call allocate via normal means but actually uses the interpreter internal implementation directly.
For example
class Foo
def bar
end
end
In that code, bar would only be available within any instance of the class.
Is it possible to change the execution context of the method to the Eigenclass
without changing how the method itself is defined so that the method is now available as a singleton without ever needing to call self.new?
Preferably I would like to do it any of the code that doe this to code that is added in via a class that Foo could inherit from.
At the moment what I'm doing amounts to:
class Test
def method_added method
self.define_singleton_method method do
self.new.send method
end
end
end
and for what I need this doesn't work as I'm changing the execution context by calling new.
You can simply do:
class Test
def self.method_added method
module_function method
end
end
class A < Test
def foo
:hello
end
end
A.foo #=> :hello
I worked out how to do it just now >_<.
Here's the code:
class Test
def method_added method
m = self.new.method(method) #get method object
self.define_singleton_method(method) do #create method with same name within the singleton class
m.call #call the block which will now run the code of the added method within the context of the Eigenclass/Singleton
end
end
end
So what it does is it grabs a method object form an instance and then calls that method as a block within the context of the class.
So the first code example becomes:
class Foo < Test
def bar
end
end
and the method bar can now be accessed as
Foo.bar rather then Foo.new.bar which means no instance creation; besides the time it does within method added, but that's fine as it's the only way to get the method object as far as I'm aware.
Which is why it's probably best to create an instance only the once when the class is inherited (within def self.inherited), store it within the class and then just access that instead of calling self.new.
In the the following tea timer code, there's a 'start' method inside SleepTimer, which calls 'notify.'
def start
sleep minutes * 60
notifier.notify("Tea is ready!")
end
If you look at the code below, you'll see that there's a notify method in the class StdioUi as well as a notify method in module UiWithBeep. The start method shown above calls the notify method in module UiWithBeep, which then, via 'super,' calls the notify method in class StdioUi. (The effect is that "BEEP!" is heard before "Tea is ready".) However, I don't understand why notifier.notify calls the notify method in module UiWithBeep rather than in class StdioUi.
First Question: how does it know to go to the one 'notify' over the other.
SecondQuestion And, although I understand super, what establishes the relationship so that notify in class StdioUi is 'super' to the other notify. Can you please explain
Tea Timer
class TeaClock
attr_accessor :timer
attr_accessor :ui
def initialize(minutes)
self.ui = StdioUi.new
self.timer = SleepTimer.new(minutes, ui)
init_plugins
end
def init_plugins
puts "init plugins"
#plugins = []
::Plugins.constants.each do |name|
#plugins << ::Plugins.const_get(name).new(self)
end
end
def start
timer.start
end
end
class StdioUi
def notify(text)
puts text
end
end
SleepTimer = Struct.new(:minutes, :notifier) do
def start
sleep minutes * 60
notifier.notify("Tea is ready!")
end
end
module Plugins
class Beep
def initialize(tea_clock)
tea_clock.ui.extend(UiWithBeep)
end
module UiWithBeep
def notify(*) #gets called by notifier.notify("Tea is ready")
puts "BEEP!"
super #calls notify in class StdioUi
end
end
end
end
t = TeaClock.new(0.01).start
The Book: I keep recommending this excellent book, Metaprogramming Ruby. I was consulting it while composing this answer.
So, here you extend an object with a module. In Ruby it's called Object Extension. In simple cases it all works as expected, like this one:
module Foo
def hello
puts "foo"
end
end
class Bar
end
bar = Bar.new
bar.extend Foo
bar.hello
# >> foo
Things get complicated when there are class' own methods involved. Here's a simplified version of your snippet that exhibits the same behaviour.
module Foo
def hello
puts "foo"
super
end
end
class Bar
def hello
puts 'bar'
end
end
bar = Bar.new
bar.extend Foo
bar.hello
# >> foo
# >> bar
When you call a method in ruby, the interpreter has to first find a method to call. This is called Method Lookup. Now, when you define an instance method, in reality it's a method on class object, not that instance. So, method lookup goes like this for first snippet:
1) bar instance => method hello not found here
2) Bar class => method hello found
When you extend an object, however, methods are injected into instance's eigenclass. It's a special "hidden" class, unique for each instance. And in reality method lookup goes through it first. First snippet again:
1) bar instance => method hello not found here
2) bar's eigenclass => method hello not found here
3) Bar class => method hello found
Now it should be clear why Foo.hello is called instead of Bar.hello: because it appears earlier in the method lookup process!
1) bar instance => method hello not found here
2) bar's eigenclass => method hello found
I may have made a few mistakes but this is roughly what happens.
each class has a property called ancestors that represents the inheritance chain. ruby walks through the list of inherited behavior and looks for matching methods. if it finds one, it calls it with the given parameters. if you call super it looks for the next match.
1.9.3-p194 :003 > String.class.ancestors
=> [Class, Mocha::ClassMethods, Module, NewRelic::Agent::MethodTracer::InstanceMethods, NewRelic::Agent::MethodTracer::InstanceMethods::TraceExecutionScoped, NewRelic::Agent::MethodTracer::ClassMethods, NewRelic::Agent::MethodTracer::ClassMethods::AddMethodTracer, Mocha::ModuleMethods, ActiveSupport::Dependencies::ModuleConstMissing, Object, FactoryGirl::Syntax::Vintage, Metaclass::ObjectMethods, Mocha::ObjectMethods, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Dependencies::Loadable, FriendlyId::ObjectUtils, Kernel, BasicObject]
In Ruby, I have a DAO class, which is extended by a class that makes managing the connections easier, which is extended by a class that represents and manipulates data in a DB, which is further extended by another class. To use an animal metaphor it would look like this:
class Animal
...
end
class Mammal < Animal
...
end
class Feline < Mammal
...
end
class Cat < Feline
...
end
class Lion < Cat
...
end
...
In PHP, there is __destruct method that runs when you destroy/delete a class. And should that class extend another class, you simply add parent::__destruct() to the class's __destruct method like this:
public function __destruct() {
// Clean up code for this class here
...
// Execute clean up code for Parent class
parent::__destruct();
}
I could have a similar method for all the classes except Animal. Since it doesn't extend anything, the parent::__destruct(); line is no longer valid.
However, as I understand it, Ruby doesn't have a method like this for its objects. A finalizer can be set, but I decided to just put in a cleanup method I can call whenever I want to destroy/delete a class. That would take care of anything that needed doing prior to my setting the class to nil.
This raises a new problem though. If the method is always named cleanup and I call lion_instance.cleanup, I assume it calls the Lion#cleanup. How then to get it to call the cleanup in class Cat and then Feline and on down the chain?
Or is this a wrong approach and you have a better idea?
The Ruby idiom for this is to yield to a block which does work, and when the block returns, do cleanup. Ruby's built-in "File.open" does this:
File.open("/tmp/foo") do |file|
file.puts "foo"
end
When the block ends, the file is closed for you, without you having to do anything. This is an excellent idiom. Here's how you might implement something like that:
class Foo
def self.open(*args)
foo = new(*args)
yield foo
foo.close
end
def initialize
# do setup here
end
def close
# do teardown here
end
end
And to use it:
Foo.open do |foo|
# use foo
end
Foo#close will be caused automatically after the end
This will work with subclassing as well. That's because class methods are inherited just as are instance methods. Here's the superclass:
class Superclass
def self.open(*args)
o = new(*args)
yield o
o.close
end
def initialize
# common setup behavior
end
def close
# common cleanup behavior
end
end
and two derived classes:
class Foo < Superclass
def initialize
super
# do subclass specific setup here
end
def close
super
# do subclass specific teardown here
end
end
class Bar < Superclass
def initialize
super
# do subclass specific setup here
end
def close
super
# do subclass specific teardown here
end
end
to use:
Foo.open do |foo|
# use foo
end
Bar.open do |bar|
# use bar
end
If you really need to make sure that cleanup happens no matter what, then use an ensure clause in the class method:
def self.open(*args)
foo = new(*args)
begin
yield foo
ensure
foo.close
end
end
This way, cleanup happens even if there is an exception in the block.
You can use ObjectSpace.define_finalizer
Something like:
class Animal
def initialize
ObjectSpace.define_finalizer(self, proc { # your code })
end
end
Well since no one answered your question about the method moving its way up the inheritance chain...
class Cat
def rawr
puts "rawr"
end
end
class Kitty < Cat
def rawr
puts "meow"
super
end
end
Cat.new.rawr
"Rawr"
Kitty.new.rawr
"rawr"
"meow"
Within a method, you can access the superclass's method of the same name by calling super.