Greetings, fellow Rubyists…
I am revisiting a small project that has lain dormant for
some time…
As I make changes and improvements, I’d be interested in
hearing your comments.
You’re welcome to critique the idea itself, the implementation,
missing features, the code, the style, or whatever.
I’ve pasted the README here for your convenience.
Thanks,
Hal F.
Structure
Hal F.
Version 1.0.3
License: The Ruby License
This is a newer version of the older “SuperStruct” (sstruct) library.
This is an easy way to create Struct-like classes; it converts easily
between hashes and arrays, and it allows OpenStruct-like dynamic naming
of members.
Unlike Struct, it creates a “real” class, and it has real instance
variables
with predictable names.
A basic limitation is that the hash keys must be legal method names
(unless
used with send()).
Basically, ss[“alpha”], ss[:alpha], and ss.alpha all mean the same.
NOTES:
It’s like a Struct…
- you can pass in a list of symbols for accessors
- it will create a class for you
but… - you don’t have to pass in the class name
- it returns a “real” class
. instance variables have the expected names
. you can reopen and add methods - it doesn’t go into the Struct:: namespace
- it preserves the order of the fields
- you can use Strings instead of Symbols for the names
It’s like an Array…
- you can access the items by [number] and [number]=
but… - you can also access the items by [“name”] and [“name”]=
- you can access the items by accessors
It’s like an OpenStruct…
- (if you use .open instead of .new) you can add fields
automatically with x.field or x.field=val
but… - you can initialize it like a Struct
- it preserves the order of the fields
It’s like a Hash…
- data can be accessed by [“name”]
but… - order (of entry or creation) is preserved
- arbitrary objects as keys are not allowed (it does obj.to_str or
obj.to_s) - keys must be valid method names
It’s like Ara Howard’s Named Array…
- we can access elements by [“name”] or [“name”]=
but… - you can access the items by accessors
- strings must be valid method names
It’s like Florian G.'s Keyed List…
(to be done)
but…
- it preserves the order of the fields
Some examples: (see test cases)
Need not assign to existing fields (default to nil)
myStruct = Structure.new(:alpha)
x = myStruct.new
x.alpha # nil
A value assigned at construction may be retrieved
myStruct = Structure.new(:alpha)
x = myStruct.new(234)
x.alpha # 234
Unassigned fields are nil
myStruct = Structure.new(:alpha,:beta)
x = myStruct.new(234)
x.beta # nil
An open structure may not construct with nonexistent fields
myStruct = Structure.open
x = myStruct.new(234) # error
An open structure may assign fields not previously existing
myStruct = Structure.open
x = myStruct.new
x.foo = 123
x.bar = 456
The act of retrieving a nonexistent field from an open struct will
create that field
myStruct = Structure.open
x = myStruct.new
x.foo # nil
A field (in an open struct) that is unassigned will be nil
myStruct = Structure.open
x = myStruct.new
y = x.foobar
A struct created with new rather than open cannot reference
nonexistent
fields
myStruct = Structure.new
x = myStruct.new
x.foo # error
Adding a field to a struct will create a writer and reader for that
field
An open struct will also create a writer and a reader together
A field has a real writer and reader corresponding to it
A string will work as well as a symbol
myStruct = Structure.new(“alpha”)
to_a will return an array of values
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
assert(x.to_a == [7,8,9])
Instance method ‘members’ will return a list of members (as strings)
myStruct = Structure.new(:alpha,“beta”)
x = myStruct.new
assert_equal([“alpha”,“beta”],x.members)
Class method ‘members’ will return a list of members (as strings)
myStruct = Structure.new(:alpha,“beta”)
assert_equal([“alpha”,“beta”],myStruct.members)
to_ary will allow a struct to be treated like an array in
multiple assignment
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
a,b,c = x
assert(b == 8)
to_ary will allow a struct to be treated like an array in
passed parameters
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
b = meth(*x)
to_hash will return a hash with fields as keys
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
h = x.to_hash
assert_equal({“alpha”=>7,“beta”=>8,“gamma”=>9},h)
A field name (String) may be used in a hash-like notation
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
y = x[“beta”]
A field name (Symbol) may be used in a hash-like notation
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
y = x[:beta]
[offset,length] may be used as for arrays
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
y = x[0,2]
Ranges may be used as for arrays
myStruct = Structure.new(“alpha”,“beta”,“gamma”)
x = myStruct.new(7,8,9)
y = x[1…2]
Adding a field to an open struct adds it to the instance
myStruct = Structure.open(:alpha)
x = myStruct.new
x.beta = 5
Adding a field to an open struct adds it to the class also
myStruct = Structure.open(:alpha)
x = myStruct.new
x.beta = 5
An array passed to Structure.new need not be starred
myStruct = Structure.new(%w[alpha beta gamma])
x = myStruct.new
A hash passed to #assign will set multiple values at once
myStruct = Structure.new(%w[alpha beta gamma])
x = myStruct.new
hash = {“alpha”=>234,“beta”=>345,“gamma”=>456}
x.assign(hash)
||= works properly
x = Structure.open.new
x.foo ||= 333
x.bar = x.bar || 444
attr_tester will create a ?-method
myStruct = Structure.new(:alive)
myStruct.attr_tester :alive
x = myStruct.new(true)
x.alive? # true