[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Class (not instance) initializers

Bhrgunatha Deva

3/21/2006 10:20:00 AM

7 Answers

Robert Klemme

3/21/2006 11:02:00 AM

0

Bhrgunatha Deva wrote:
> Newbie question:
>
> Is there an equivalent to a static constructor in ruby?
> something like:
>
> class MyClass
> # want this to run before any instances of MyClass are created
> def class_initialize
> self.some_complex_initialisation
> end
> end
>
> At the moment I'm using:
> class MyClass
> def initialize
> @@init = self.some_complex_initialisation if @@init.nil?
> end
> end
>
> I'd love to know if there is a more rubyesque way of doing this

Just place your code in the class body:

class MyClass
@class_state = complex_calculation
end

Often one needs to inform a super class of a new child. This can be
done with #inherited:

class Base
def self.inherited(cl)
print Base, " was inherited by ", cl, "\n"
end
end

>> class Foo < Base
>> end
Base was inherited by Foo
=> nil

Kind regards

robert

Ross Bamford

3/21/2006 11:04:00 AM

0

On Tue, 2006-03-21 at 19:20 +0900, Bhrgunatha Deva wrote:
> Newbie question:
>
> Is there an equivalent to a static constructor in ruby?
> something like:
>
> class MyClass
> # want this to run before any instances of MyClass are created
> def class_initialize
> self.some_complex_initialisation
> end
> end

Do you mean something like:

class InitMe
def self.complex_init
puts "Initializing #{self}"
end

complex_init
end
#(p) Initializing InitMe
# => nil

or even just:

class InitMe
puts "Initializing #{self}"
end
#(p) Initializing InitMe
# => nil

?

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk



Bhrgunatha Deva

3/21/2006 11:50:00 AM

0

Dave Baldwin

3/21/2006 11:51:00 AM

0

I am creating a DSL using Ruby. A cut down version is below:

class _Box
attr_accessor :width

def initialize (&block)
self.width = 20 # some default value
instance_eval(&block) if block_given?
end
end

# Helper function to avoid the DSL user having to use .new
def Box(&block)
_Box.new(&block)
end

I want to do something like:

Box {width = 10}

but the only way I can get it to work is

Box {self.width = 10}

Having to prefix the ivar with self. makes the DSL look clunky and
wouldn't be acceptable to my users.

Is there anyway to avoid the self.? Using {@width = 10} will work
but prevents some necessary validation from taking place.


I have an alternative where width is a method:

class _Box
def width (val = :no_param)
if val != :no_param
@width = val
end
@width
end
end

so with this I can write

Box {width 10}

which is acceptable from the DSL view point, but makes the getter
operations more expensive. In the real version a getter operation
takes about 7 statements to allow for evaluation of block if the ivar
had been set to a Proc object and inheritance of values from its
parent object (in a visual hierarchy). The setter operation is often
only done when the object is created but the getter is done very
frequently so I want to move down the route of separate setters and
getters rather than combining them in the one method as an optimization.

Dave.



Tim Hunter

3/21/2006 1:08:00 PM

0

Dave Baldwin wrote:
> I am creating a DSL using Ruby. A cut down version is below:
>
> class _Box
> attr_accessor :width
>
> def initialize (&block)
> self.width = 20 # some default value
> instance_eval(&block) if block_given?
> end
> end
>
> # Helper function to avoid the DSL user having to use .new
> def Box(&block)
> _Box.new(&block)
> end
>
> I want to do something like:
>
> Box {width = 10}
>
> but the only way I can get it to work is
>
> Box {self.width = 10}
>
> Having to prefix the ivar with self. makes the DSL look clunky and
> wouldn't be acceptable to my users.
>
> Is there anyway to avoid the self.? Using {@width = 10} will work but
> prevents some necessary validation from taking place.
>
>
> I have an alternative where width is a method:
>
> class _Box
> def width (val = :no_param)
> if val != :no_param
> @width = val
> end
> @width
> end
> end
>
> so with this I can write
>
> Box {width 10}
>
> which is acceptable from the DSL view point, but makes the getter
> operations more expensive. In the real version a getter operation
> takes about 7 statements to allow for evaluation of block if the ivar
> had been set to a Proc object and inheritance of values from its parent
> object (in a visual hierarchy). The setter operation is often only
> done when the object is created but the getter is done very frequently
> so I want to move down the route of separate setters and getters rather
> than combining them in the one method as an optimization.
>
> Dave.
>
>
>
Good article on DSLs and addresses your question:
http://www.artima.com/rubycs/articles/ruby_a...

Its Me

3/21/2006 2:17:00 PM

0


"Dave Baldwin" <dave.baldwin@3dlabs.com> wrote

> Having to prefix the ivar with self. makes the DSL look clunky

I agree, though some experienced Rubyists don't see it that way.

> so with this I can write
>
> Box {width 10}
>
> which is acceptable from the DSL view point, but makes the getter
> operations more expensive. In the real version a getter operation takes
> about 7 statements to allow for evaluation of block if the ivar had been
> set to a Proc object and inheritance of values from its parent object (in
> a visual hierarchy). The setter operation is often only done when the
> object is created but the getter is done very frequently so I want to
> move down the route of separate setters and getters rather than combining
> them in the one method as an optimization.

If you have some guarantees about the ordering of getters and setters, you
can dynamically (re)define the getter and setter at the instance level. The
attached worked for the case of instance variables being initialized only
once, but being read at any time (the context for this was some kind of lazy
creation of an object graph including forward references). Perhaps some bits
of it will apply to your case.

class Object
def singleton_class
class << self; self; end
end
end

module LazyForwardRef
UNDEFINED = nil
def forward_ref(attr)
getter = attr
setter = (attr.to_s + '=').intern
ivar = ('@' + attr.to_s).intern
suspension = lambda { self.send getter }
self.singleton_class.send :define_method, getter, lambda {
v = instance_variable_get ivar
if v == UNDEFINED
suspension
elsif v.is_a?(Proc)
current = v.call
self.send(setter, current) if current != v
current
else v
end
}
self.singleton_class.send :define_method, setter, lambda {|val|
self.instance_variable_set ivar, val
}
end
end


require 'pp'

x = Object.new
x.extend LazyForwardRef

begin
p x.foo
rescue NoMethodError => detail
pp detail
pp [__LINE__, x, x.methods.sort - Object.instance_methods]
end

x.forward_ref(:foo)
pp [__LINE__, x, x.methods.sort - Object.instance_methods]

x.foo
pp [__LINE__, x, x.foo]

x.foo = 'Something else'
pp [__LINE__, x, x.foo]

y = Object.new
y.extend LazyForwardRef

y.forward_ref(:bar)
pp [__LINE__, y, y.methods.sort - Object.instance_methods]

z = Object.new
z.extend LazyForwardRef
z.forward_ref(:baz)

y.bar = z.baz
pp [__LINE__, x, y, z, x.foo, y.bar, z.baz, x.foo==z.baz]

x.foo = y.bar
pp [__LINE__, x, y, x.foo, y.bar]

z.baz= 10
pp [__LINE__, x, y, z]

pp [__LINE__, x.foo, y.bar, z.baz]

pp [__LINE__, x, y, z]


Ara.T.Howard

3/21/2006 3:45:00 PM

0