I want to make a simple module that makes its including classes
self-countable.
Here is the code (that does not work, incidentally):
#—code
module Countable
@@counter = 0
def initialize
@@counter += 1
end
module ClassMethods
def population
return @@counter
end
end
def self.included(base)
base.extend(ClassMethods)
end
end
class User
include Countable
end
User.new
User.new
puts User.population
#—code
The error message says that the @@counter class variable is not
initialized in Countable::ClassMethods (so in the population method).
Obviously, this @@counter variable is not the same as the one that is
declared when including Countable, since User.new works as expected.
Can someone explain me why and how to solve this?
The error message says that the @@counter class variable is not
initialized in Countable::ClassMethods (so in the population method).
Obviously, this @@counter variable is not the same as the one that is
declared when including Countable, since User.new works as expected.
Can someone explain me why and how to solve this?
I think what you really want is an instance variable in the including
class,
since the counter is a property of the class. The instance variable must
be
created anew in every including class, whereas I think your code will
try to
reuse Countable’s @@counter variable for all classes. This code works:
module Countable
def initialize
self.class.instance_eval do
@counter ||= 0
@counter += 1
end
end
module ClassMethods
def population
return @counter || 0
end
end
def self.included(base)
base.extend(ClassMethods)
end
end
class User
include Countable
end
User.new
User.new
puts User.population
On Tue, Jul 22, 2008 at 8:07 PM, ara.t.howard [email protected]
wrote:
Maybe there is a way to leave Class alone 
This will track instances for all ancestors of InstanceTracker.
module InstanceTracker
Define a block that defines the included
inclusion = proc { | by_module |
singleton = class << by_module; self end
unless Class === by_module then
singleton.send :define_method, :included, &inclusion
return
end
by_module.instance_variable_set "@__instances__", []
singleton.send :define_method, :inherited, &inclusion
singleton.module_eval do
def new *args, &blk
o = allocate
o.send( :initialize, *args, &blk )
@__instances__ << o
o
end
def instances; @__instances__ end
end
}
Define included in base module
class << self; self end.
send :define_method, :included, &inclusion
end # module InstanceTracker
M2 = Module::new {
include InstanceTracker
}
class A
include M2
end
B = Class::new A do
def initialize; 42 end
end
A::new
B::new
A::new
p A.instances
p B.instance
One could take special care of classes that define a custom new, but
that would make the code too complicated for the demonstrational
purpose I feel.
HTH
Robert
–
http://ruby-smalltalk.blogspot.com/
There’s no one thing that’s true. It’s all true.
On Jul 22, 2008, at 10:24 AM, Julien T. wrote:
I want to make a simple module that makes its including classes
self-countable.
Here is the code (that does not work, incidentally):
something like ?
cfp:~ > cat a.rb
class Class
New = method :new unless defined?(New)
Count = Hash.new{|h,k| h[k] = 0} unless defined?(Count)
def new *a, &b
New.call(*a, &b)
ensure
Count[self] += 1 unless $!
end
def count
Count[self]
end
end
class C; end
3.times{ C.new }
3.times{ Array.new }
p ‘C.count’ => C.count
p ‘Array.count’ => Array.count
p ‘Hash.count’ => Hash.count
cfp:~ > ruby a.rb
{“C.count”=>3}
{“Array.count”=>3}
{“Hash.count”=>0}
a @ http://codeforpeople.com/
Robert D. wrote:
One could take special care of classes that define a custom new, but
that would make the code too complicated for the demonstrational
purpose I feel.
In fact, the purpose of my example was educational.
Defining a custom new would illustrate how to be evil in my case 
By the way, I can not think of a legitimate use of redefining new.
By the way, I can not think of a legitimate use of redefining new.
Do you mean my code is not legitimate?
I think this is precisely a good use case.
Robert
–
http://ruby-smalltalk.blogspot.com/
There’s no one thing that’s true. It’s all true.
James C. wrote:
I think what you really want is an instance variable in the including
class,
since the counter is a property of the class. The instance variable must
be
created anew in every including class, whereas I think your code will
try to
reuse Countable’s @@counter variable for all classes. This code works:
Thanks James.
I was trying to illustrate the use of class variables with modules but,
as you pointed out, my example is precisely a case where we need class
instance variables
(http://www.martinfowler.com/bliki/ClassInstanceVariable.html).
On Fri, Jul 25, 2008 at 3:22 PM, Julien T. [email protected] wrote:
Robert D. wrote:
By the way, I can not think of a legitimate use of redefining new.
Do you mean my code is not legitimate?
I think this is precisely a good use case.
I meant other than for hacking purpose.
Posted via http://www.ruby-forum.com/.
Yes but that was my point, I guess if you wanted to expose this method
of tracking, you should check if your classes implement new for some
hacking reason ;). I would prefer the term “metaprogramming” though.
I just wanted to be sure that you are aware of that, if we redefine
new in a legitimate way, someone else might have.
Cheers
Robert
–
http://ruby-smalltalk.blogspot.com/
There’s no one thing that’s true. It’s all true.
On Jul 25, 2008, at 7:22 AM, Julien T. wrote:
I meant other than for hacking purpose.
there are many good reasons - one is for subclassing, if you override
new clients do not have to remember to call ‘super’
class C
def C.new *a, &b
(object = allocate).instance_eval do
init *a, &b
initialize *a, &b
self
end
end
def init
@you = ‘do not have to remember to call this’
end
end
class D < C
def initialize
end
end
another reason is for instance in the case of dike.rb, by re-defining
‘new’ it can track object creation, register a finalizer, and thereby
track the object lifecycle to detect memory leaks
regards.
a @ http://codeforpeople.com/
On Fri, Jul 25, 2008 at 6:40 PM, ara.t.howard [email protected]
wrote:
class C
end
it can track object creation, register a finalizer, and thereby track the
Ara I know your code is quite fine and demonstrating what you wanted
to, I am however still not sure that
I brought my point across 
The dilemma of a way to redefine new statically (1) or dynamically (2)
is to allow it to tolerate other new implementations in the
inheritance chain.
(1)
class C
def self.new *args, &blk
super(*args, &blk).instance_eval do
…
self
end
end
end
(2)
module M
def self.inherited a_mod
return if Class === a_mod
class << a_mod
alias_method :old, :new rescue nil
self
end.module_eval do
def new *args, &blk
old(args,&blk).instance_eval do
…
self
end
Cheers
Robert
–
http://ruby-smalltalk.blogspot.com/
There’s no one thing that’s true. It’s all true.
Robert D. wrote:
By the way, I can not think of a legitimate use of redefining new.
Do you mean my code is not legitimate?
I think this is precisely a good use case.
I meant other than for hacking purpose.