1 # depends on: class.rb enumerable.rb hash.rb
13 # Struct.new( [aString] [, aSym]+> ) => StructClass
14 # StructClass.new(arg, ...) => obj
15 # StructClass[arg, ...] => obj
17 # Creates a new class, named by <em>aString</em>, containing accessor
18 # methods for the given symbols. If the name <em>aString</em> is omitted,
19 # an anonymous structure class will be created. Otherwise, the name of
20 # this struct will appear as a constant in class <tt>Struct</tt>, so it
21 # must be unique for all <tt>Struct</tt>s in the system and should start
22 # with a capital letter. Assigning a structure class to a constant
23 # effectively gives the class the name of the constant.
25 # <tt>Struct::new</tt> returns a new <tt>Class</tt> object, which can then
26 # be used to create specific instances of the new structure. The number of
27 # actual parameters must be less than or equal to the number of attributes
28 # defined for this class; unset parameters default to \nil{}. Passing too
29 # many parameters will raise an \E{ArgumentError}.
31 # The remaining methods listed in this section (class and instance) are
32 # defined for this generated class.
34 # # Create a structure with a name in Struct
35 # Struct.new("Customer", :name, :address) #=> Struct::Customer
36 # Struct::Customer.new("Dave", "123 Main") #=> #<Struct::Customer
37 # name="Dave", address="123 Main">
38 # # Create a structure named by its constant
39 # Customer = Struct.new(:name, :address) #=> Customer
40 # Customer.new("Dave", "123 Main") #=> #<Customer
41 # name="Dave", address="123 Main">
43 def self.new(klass_name, *attrs, &block)
44 unless klass_name.nil? then
46 klass_name = StringValue klass_name
48 attrs.unshift klass_name
54 attrs = attrs.map { |attr| attr.to_sym }
55 rescue NoMethodError => e
56 raise TypeError, e.message
59 raise ArgumentError if attrs.any? { |attr| attr.nil? }
61 klass = Class.new self do
66 return subclass_new(*args)
75 Struct.const_set klass_name, klass if klass_name
77 klass.const_set :STRUCT_ATTRS, attrs
79 klass.module_eval(&block) if block
84 def self.allocate # :nodoc:
89 return self.class.const_get(:STRUCT_ATTRS)
92 def instance_variables
93 # Hide the ivars used to store the struct fields
94 super() - _attrs.map { |a| "@#{a}" }
98 raise ArgumentError unless args.length <= _attrs.length
99 _attrs.each_with_index do |attr, i|
100 instance_variable_set "@#{attr}", args[i]
108 # struct == other_struct => true or false
110 # Equality---Returns <tt>true</tt> if <em>other_struct</em> is equal to
111 # this one: they must be of the same class as generated by
112 # <tt>Struct::new</tt>, and the values of all instance variables must be
113 # equal (according to <tt>Object#==</tt>).
115 # Customer = Struct.new(:name, :address, :zip)
116 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
117 # joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
118 # jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345)
119 # joe == joejr #=> true
120 # joe == jane #=> false
123 return self.class == other.class && self.values == other.values
128 # struct[symbol] => anObject
129 # struct[fixnum] => anObject
131 # Attribute Reference---Returns the value of the instance variable named
132 # by <em>symbol</em>, or indexed (0..length-1) by <em>fixnum</em>. Will
133 # raise <tt>NameError</tt> if the named variable does not exist, or
134 # <tt>IndexError</tt> if the index is out of range.
136 # Customer = Struct.new(:name, :address, :zip)
137 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
138 # joe["name"] #=> "Joe Smith"
139 # joe[:name] #=> "Joe Smith"
140 # joe[0] #=> "Joe Smith"
146 a_len = _attrs.length
147 if var > a_len - 1 then
148 raise IndexError, "offset #{var} too large for struct(size:#{a_len})"
151 raise IndexError, "offset #{var + a_len} too small for struct(size:#{a_len})"
154 when Symbol, String then
161 unless _attrs.include? var.to_sym then
162 raise NameError, "no member '#{var}' in struct"
165 return instance_variable_get("@#{var}")
170 # struct[symbol] = obj => obj
171 # struct[fixnum] = obj => obj
173 # Attribute Assignment---Assigns to the instance variable named by
174 # <em>symbol</em> or <em>fixnum</em> the value <em>obj</em> and returns
175 # it. Will raise a <tt>NameError</tt> if the named variable does not
176 # exist, or an <tt>IndexError</tt> if the index is out of range.
178 # Customer = Struct.new(:name, :address, :zip)
179 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
180 # joe["name"] = "Luke"
181 # joe[:zip] = "90210"
182 # joe.name #=> "Luke"
183 # joe.zip #=> "90210"
189 a_len = _attrs.length
190 if var > a_len - 1 then
191 raise IndexError, "offset #{var} too large for struct(size:#{a_len})"
194 raise IndexError, "offset #{var + a_len} too small for struct(size:#{a_len})"
197 when Symbol, String then
204 unless _attrs.include? var.to_s.intern then
205 raise NameError, "no member '#{var}' in struct"
208 return instance_variable_set("@#{var}", obj)
213 # struct.each {|obj| block } => struct
215 # Calls <em>block</em> once for each instance variable, passing the value
218 # Customer = Struct.new(:name, :address, :zip)
219 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
220 # joe.each {|x| puts(x) }
225 # 123 Maple, Anytown NC
229 return values.each(&block)
234 # struct.each_pair {|sym, obj| block } => struct
236 # Calls <em>block</em> once for each instance variable, passing the name
237 # (as a symbol) and the value as parameters.
239 # Customer = Struct.new(:name, :address, :zip)
240 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
241 # joe.each_pair {|name, value| puts("#{name} => #{value}") }
246 # address => 123 Maple, Anytown NC
250 raise LocalJumpError unless block_given? # HACK yield should do this
251 _attrs.map { |var| yield var, instance_variable_get("@#{var}") }
260 # struct.eql?(other) => true or false
262 # Two structures are equal if they are the same object, or if all their
263 # fields are equal (using <tt>eql?</tt>).
266 return true if self == other
267 return false if self.class != other.class
273 # struct.hash => fixnum
275 # Return a hash value based on this struct's contents.
283 # struct.length => fixnum
284 # struct.size => fixnum
286 # Returns the number of instance variables.
288 # Customer = Struct.new(:name, :address, :zip)
289 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
300 # struct.members => array
302 # Returns an array of strings representing the names of the instance
305 # Customer = Struct.new(:name, :address, :zip)
306 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
307 # joe.members #=> ["name", "address", "zip"]
310 return const_get(:STRUCT_ATTRS).map { |member| member.to_s }
314 return self.class.members
319 # struct.select(fixnum, ... ) => array
320 # struct.select {|i| block } => array
322 # The first form returns an array containing the elements in
323 # <em>struct</em> corresponding to the given indices. The second form
324 # invokes the block passing in successive elements from <em>struct</em>,
325 # returning an array containing those elements for which the block returns
326 # a true value (equivalent to <tt>Enumerable#select</tt>).
328 # Lots = Struct.new(:a, :b, :c, :d, :e, :f)
329 # l = Lots.new(11, 22, 33, 44, 55, 66)
330 # l.select(1, 3, 5) #=> [22, 44, 66]
331 # l.select(0, 2, 4) #=> [11, 33, 55]
332 # l.select(-1, -3, -5) #=> [66, 44, 22]
333 # l.select {|v| (v % 2).zero? } #=> [22, 44, 66]
341 # struct.to_a => array
342 # struct.values => array
344 # Returns the values for this instance as an array.
346 # Customer = Struct.new(:name, :address, :zip)
347 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
348 # joe.to_a[1] #=> "123 Maple, Anytown NC"
351 return _attrs.map { |var| instance_variable_get "@#{var}" }
356 # struct.to_s => string
357 # struct.inspect => string
359 # Describe the contents of this struct in a string.
362 "#<struct #{self.class.name} #{_attrs.zip(self.to_a).map{|o| o[1] = o[1].inspect; o.join('=')}.join(', ') }>"
369 # struct.to_a => array
370 # struct.values => array
372 # Returns the values for this instance as an array.
374 # Customer = Struct.new(:name, :address, :zip)
375 # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
376 # joe.to_a[1] #=> "123 Maple, Anytown NC"
382 # struct.values_at(selector,... ) => an_array
384 # Returns an array containing the elements in <em>self</em> corresponding
385 # to the given selector(s). The selectors may be either integer indices or
386 # ranges. See also </code>.select<code>.
388 # a = %w{ a b c d e f }
389 # a.values_at(1, 3, 5)
390 # a.values_at(1, 3, 5, 7)
391 # a.values_at(-1, -3, -5, -7)
392 # a.values_at(1..3, 2...5)
395 to_a.values_at(*args)