A simpler alternative is to just use Struct:
Song = Struct.new :name, :artist, :duration
# other methods
Wait wait wait...I never grokked Struct before.
Is it really just a convenient factory for generating classes with a set of accessor properties, and a constructor that accepts zero or more of those properties in order?
Holy crap, I see that Song.class is in fact Class.
I may finally get it! Re-reading the ri documentation for Struct, I see that the above is sort of what it's trying to say. But the wording always made me believe that the returned object was some sort of non-class class. Some half-breed freakiness.
The combination of the name and documentation threw me off before. I suppose 'Struct' sort of works, but something like 'AttributeClass' (while wordier and not as memorable). So apparently I have no better suggestion for the name. But for the documentation...
At a minimum, I suggest replacing the first sentence:
"A +Struct+ is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class."
Maybe I'm the only one (am I the only one?) but that makes it sound like the return value isn't a class. Instead, I suggest something like:
The +Struct+ class provides a convenient way to quickly create a class that contains a set of attributes. In addition to predefining the accessor methods for these attributes, the returned class contains other instance methods for accessing and modifying the attributes. (These methods are documented below as instance methods of the Struct class, but are in fact methods available to instances of the class returned from the call to Struct.new).
User = Struct.new( :first, :last, :email )
p User.class #=> Class
p User.superclass #=> Struct
nobody = User.new
gk = User.new( 'Gavin', 'Kistner' )
p nobody #=> #<struct User first=nil, last=nil, email=nil>
p gk #=> #<struct User first="Gavin", last="Kistner", email=nil>
p gk.size #=> 3
gk.email = 'email@example.com'
p gk.members #=> ["first", "last", "email"]
p gk.values #=> ["Gavin", "Kistner", "firstname.lastname@example.org"]
p gk.values_at(1..2) #=> ["Kistner", "email@example.com"]
p gk.first #=> "Gavin"
p gk['last'] #=> "Kistner"
p gk.fullname #=> "Gavin Kistner"
(I think it's very helpful to have an example usage at the very top of the documentation, showing a simple usage with a type of object that everyone understands. Obviously, it doesn't have to be my name or email, though
Also, the documentation for the Struct#values_at method seems to have been lifted from the Array#values_at method, without changing the example code to use a Struct rather than array. The example should be something like:
Stuff = Struct.new( :a, :b, :c, :d, :e, :f )
chars = Stuff.new( 'a1', 'b1', 'c1', 'd1', 'e1', 'f1' )
p chars.values_at(1, 3, 5) #=> ["b1", "d1", "f1"]
p chars.values_at(-1, -3, -5) #=> ["f1", "d1", "b1"]
p chars.values_at(1..3, 2...5) #=> ["b1", "c1", "d1", "c1", "d1", "e1"]
p chars.values_at(1,7) #=> offset 7 too large for struct(size:6) (IndexError)
(Aside: Has anyone ever used the #values_at method of the Struct class? If so, what for?)
On Aug 22, 2005, at 2:31 AM, Robert Klemme wrote:
cc: ruby-doc mailing list