[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Proper way to define a subclass within parent file?

Scott Strattner

10/28/2008 5:58:00 PM

I am starting to build a script to manipulate various network device
information, including a list of Vlans from a switch. To that end, I
created a Vlan class:

class Vlan
@@max = 399
@@min = 1
@@protected = [1,2,5]
@@namelen = 32
def initialize (id,desc)
self.set_name(desc) if (self.set_id(id))
end
def set_id (id)
return nil unless (id.kind_of? Integer)
return nil if (@@protected.index(id) || id > @@max || id < @@min)
@id = id
end
def set_name (desc)
desc.gsub!(/\s+/,"_")
desc = desc[0..@@namelen-1] if (desc.length > @@namelen)
@description = desc
end
def to_s
return "#{@id}\t#{@description}"
end
def valid?
return true if (@id.kind_of? Integer)
return false
end
# snip various other methods
end

This works as expected; to test it out I added some debugging code to
loop through some values and verify it only created valid instances:

v = Array.new
20.times { |a|
temp = Vlan.new(a,"this is vlan id #{a}")
v.insert(-1,temp) if (temp.valid?)
}
v.length.times { |a| puts "#{a} #{v[a].to_s}" }

I then added a simple subclass, within the same file. This special kind
of Vlan acts like the others, except it uses a different range of valid
id values:

class HMC_Vlan < Vlan
@@min = 701
@@max = 799
@@protected = [700,705]
end

I then added to the debug code:

v2 = Array.new
700.upto(720) { |a|
temp2 = HMC_Vlan.new(a,"hmcvlan.#{a}")
v2.insert(-1,temp2) if (temp2.valid?)
}
v2.length.times { |a| puts "#{a} #{v2[a].to_s}" }

When I ran this file, it created HMC_Vlans as expected, but no longer
created any valid Vlans ("v" array was empty). It turns out the class
variables @@max, min, protected in HMC_Vlan are overwriting the class
variables in Vlan - even though no instance of HMC_Vlan is created until
after my debug code creates the "v" array.
It was my understanding that a Class declaration was treated as a
conditional block - *if* someone creates this Class, *then* run through
the contents. But here it appears the class declaration is processed
before any instance of it is made. Even so, shouldn't a class variable
be specific to that class, and not be shared with children? Is there
another kind of inheritance I can use to maintain this separation in
class variables? Is there a specific way to define a subclass within the
same file as the parent? Why does the class HMC_Vlan definition get
executed before any instances are created?

I am running this under Windows (ActiveRuby 1.8.6)
--
Posted via http://www.ruby-....

4 Answers

Stefano Crocco

10/28/2008 7:31:00 PM

0

Alle Tuesday 28 October 2008, Scott Strattner ha scritto:
> I am starting to build a script to manipulate various network device
> information, including a list of Vlans from a switch. To that end, I
> created a Vlan class:
>
> class Vlan
> @@max = 399
> @@min = 1
> @@protected = [1,2,5]
> @@namelen = 32
> def initialize (id,desc)
> self.set_name(desc) if (self.set_id(id))
> end
> def set_id (id)
> return nil unless (id.kind_of? Integer)
> return nil if (@@protected.index(id) || id > @@max || id < @@min)
> @id = id
> end
> def set_name (desc)
> desc.gsub!(/\s+/,"_")
> desc = desc[0..@@namelen-1] if (desc.length > @@namelen)
> @description = desc
> end
> def to_s
> return "#{@id}\t#{@description}"
> end
> def valid?
> return true if (@id.kind_of? Integer)
> return false
> end
> # snip various other methods
> end
>
> This works as expected; to test it out I added some debugging code to
> loop through some values and verify it only created valid instances:
>
> v = Array.new
> 20.times { |a|
> temp = Vlan.new(a,"this is vlan id #{a}")
> v.insert(-1,temp) if (temp.valid?)
> }
> v.length.times { |a| puts "#{a} #{v[a].to_s}" }
>
> I then added a simple subclass, within the same file. This special kind
> of Vlan acts like the others, except it uses a different range of valid
> id values:
>
> class HMC_Vlan < Vlan
> @@min = 701
> @@max = 799
> @@protected = [700,705]
> end
>
> I then added to the debug code:
>
> v2 = Array.new
> 700.upto(720) { |a|
> temp2 = HMC_Vlan.new(a,"hmcvlan.#{a}")
> v2.insert(-1,temp2) if (temp2.valid?)
> }
> v2.length.times { |a| puts "#{a} #{v2[a].to_s}" }
>
> When I ran this file, it created HMC_Vlans as expected, but no longer
> created any valid Vlans ("v" array was empty). It turns out the class
> variables @@max, min, protected in HMC_Vlan are overwriting the class
> variables in Vlan - even though no instance of HMC_Vlan is created until
> after my debug code creates the "v" array.
> It was my understanding that a Class declaration was treated as a
> conditional block - *if* someone creates this Class, *then* run through
> the contents.

You're wrong here. The body of a class definition is executed when it's found.
Method bodies (for both instance methods and class methods) aren't executed
untill they're called, but all the rest of the class body is executed
immediately. For example, the code

class C

puts "body of class C"

def method1
puts "body of method method1"
end

end

when read produces the output

"body of class C"

and, after that, calling C.instance_methods will return an array which
contains the string "method1", showing that the method method1 has already
been defined. On the other hand, the body of method1 is only executed after a
call to it, for example with the code C.new.method1.

> But here it appears the class declaration is processed
> before any instance of it is made. Even so, shouldn't a class variable
> be specific to that class, and not be shared with children? Is there
> another kind of inheritance I can use to maintain this separation in
> class variables? Is there a specific way to define a subclass within the
> same file as the parent?

Class variables are shared among a class and all its subclasses. If you don't
want that, you can use class instance variables, that is instance variables of
the class object. They work like common instance variables, and can be
accessed outside the class body only if appropriate class methods are defined
(note: this is also true inside instance methods of the class). You could do
this:

class Vlan
@max = 399
@min = 1
@protected = [1,2,5]
@namelen = 32

def self.max
@max
end

def self.min
@min
end

def self.protected
@protected
end

def set_id (id)
return nil unless (id.kind_of? Integer)
return nil if (self.class.protected.index(id) || id > self.classl.max ||
id < self.class.min)
@id = id
end

...

The only problem with this approach is that all instance variables should be
initialized in all classes which need them (you don't need to redefine the
methods, instead).

Another possibility, if the values in the instance variables shouldn't change
is to use constants:

class Vlan
MAX = 399
MIN = 1
PROTECTED = [1,2,5]
NAMELEN = 32

I hope this helps

Stefano

Scott Strattner

10/28/2008 8:08:00 PM

0

Stefano Crocco wrote:


> Class variables are shared among a class and all its subclasses. If you
> don't
> want that, you can use class instance variables, that is instance
> variables of
> the class object.

I knew of instance variables, and class variables, but not class
instance variables. It seems to do what I need, although the syntax will
take some getting used to.

> Another possibility, if the values in the instance variables shouldn't
> change
> is to use constants:

I originally had methods to modify these class variables, but I just
tried using constants, and that worked. So I will probably create a
subclass for every kind of VLAN encountered (which will then define the
constant values for that particular subclass).

> I hope this helps

It did. Thanks.

--
Posted via http://www.ruby-....

Brian Candler

10/28/2008 8:32:00 PM

0

Scott Strattner wrote:
>> Another possibility, if the values in the instance variables shouldn't
>> change
>> is to use constants:
>
> I originally had methods to modify these class variables, but I just
> tried using constants, and that worked. So I will probably create a
> subclass for every kind of VLAN encountered (which will then define the
> constant values for that particular subclass).

Note: when referring to constant Foo, use self.class::Foo in a subclass
if you want dynamic lookup, otherwise Foo will statically be resolved to
the one in the parent.

class Bar
Foo = 1
def test1
Foo # always refers to Bar::Foo, even in a subclass
end
def test2
self.class::Foo
end
end

class Baz < Bar
Foo = 2
end

p Bar.new.test1 # prints 1
p Baz.new.test1 # prints 1
p Bar.new.test2 # prints 1
p Baz.new.test2 # prints 2
--
Posted via http://www.ruby-....

dppe@huskeraccess. com<dppe@huskeraccess.com>

12/21/2010 2:46:00 AM

0

On Dec 20, 7:42 pm, "Lloyd Olson" <l...@ssbilliards.com> wrote:
> Maybe I missed it, but it is for local pick up only, and no where did I see
> where exactly this local pick up is ?  LTG :)
>
> "caver" <ridgeline_...@verizon.net> wrote in message
>
> news:f532eeb1-bb66-4423-9b13-b15ab5680a50@s4g2000yql.googlegroups.com...
> On Dec 20, 8:57 pm, "d...@neb.rr.com" <d...@neb.rr.com> wrote:
>
http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&item=170580095474......
>
>)
Game is located in Lincoln, Nebraska. Sorry, but the Heat Wave is not
for sale unless you have very deep pockets ($2500.)- hee! hee!