Class (not instance) initializers

B

Bhrgunatha Deva

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

Bhrgunatha.
 
R

Robert Klemme

Bhrgunatha said:
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
Base was inherited by Foo
=> nil

Kind regards

robert
 
R

Ross Bamford

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

?
 
B

Bhrgunatha Deva

Ross said:
Do you mean something like:

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

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

I'm so dim. I didn't realise I could just call a method from inside the
class body.

Robert said:
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

Base was inherited by Foo
=> nil

Whoa, that's very neat!

Thanks.
 
D

Dave Baldwin

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.
 
A

ara.t.howard

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.

here is one simple way:

harp:~ > cat a.rb
class OpenStruct
alias_method "__eval__", "instance_eval"
alias_method "__set__", "instance_variable_set"
alias_method "__get__", "instance_variable_get"
instance_methods.each{ |m| undef_method m unless m =~ /^__/ }
def initialize(&block) __eval__ &block end
def method_missing m, *a, &b
m = m.to_s.delete "=?"
a.size == 0 ? __get__("@#{ m }") : __set__("@#{ m }", a.shift)
end
end

module Initializable
def initialize &block
os = OpenStruct.new &block
attributes.each{|a| instance_variable_set "@#{ a }", os.__send__(a)}
end
def to_s
require "yaml"
attributes.inject({}){|h,a| h.update a => send(a)}.to_yaml
end
def attributes
self.class::ATTRIBUTES
end
end

class Box
ATTRIBUTES = %w[ width height ]
ATTRIBUTES.each{|a| attr a}
include Initializable
end

def Box(*a, &b) Box.new(*a, &b) end

puts Box {
width 42
height 42
}



harp:~ > ruby a.rb
---
height: 42
width: 42


the idea is to initialize another object, the OpenStruct in this case, and then
relay the properties. this object can have any 'slow' but convenient behaviour
your desire, leaving the Box class to have normal 'fast' attributes.

hth.

-a
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top