Stefano Crocco
10/28/2008 7:31:00 PM
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