sstruct 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/doc/sstruct.txt +204 -0
- data/lib/sstruct.rb +213 -0
- data/sstruct.gemspec +40 -0
- data/test/test-sstruct.rb +318 -0
- metadata +43 -0
data/doc/sstruct.txt
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
|
2
|
+
SuperStruct
|
3
|
+
Hal Fulton
|
4
|
+
Version 1.0
|
5
|
+
License: The Ruby License
|
6
|
+
|
7
|
+
This is an easy way to create Struct-like classes; it converts easily
|
8
|
+
between hashes and arrays, and it allows OpenStruct-like dynamic naming
|
9
|
+
of members.
|
10
|
+
|
11
|
+
Unlike Struct, it creates a "real" class, and it has real instance variables
|
12
|
+
with predictable names.
|
13
|
+
|
14
|
+
A basic limitation is that the hash keys must be legal method names (unless
|
15
|
+
used with send()).
|
16
|
+
|
17
|
+
Basically, ss["alpha"], ss[:alpha], and ss.alpha all mean the same.
|
18
|
+
|
19
|
+
|
20
|
+
NOTES:
|
21
|
+
|
22
|
+
|
23
|
+
It's like a Struct...
|
24
|
+
- you can pass in a list of symbols for accessors
|
25
|
+
- it will create a class for you
|
26
|
+
but...
|
27
|
+
- you don't have to pass in the class name
|
28
|
+
- it returns a "real" class
|
29
|
+
. instance variables have the expected names
|
30
|
+
. you can reopen and add methods
|
31
|
+
- it doesn't go into the Struct:: namespace
|
32
|
+
- it preserves the order of the fields
|
33
|
+
- you can use Strings instead of Symbols for the names
|
34
|
+
|
35
|
+
It's like an Array...
|
36
|
+
- you can access the items by [number] and [number]=
|
37
|
+
but...
|
38
|
+
- you can also access the items by ["name"] and ["name"]=
|
39
|
+
- you can access the items by accessors
|
40
|
+
|
41
|
+
It's like an OpenStruct...
|
42
|
+
- (if you use .open instead of .new) you can add fields
|
43
|
+
automatically with x.field or x.field=val
|
44
|
+
but...
|
45
|
+
- you can initialize it like a Struct
|
46
|
+
- it preserves the order of the fields
|
47
|
+
|
48
|
+
It's like a Hash...
|
49
|
+
- data can be accessed by ["name"]
|
50
|
+
but...
|
51
|
+
- order (of entry or creation) is preserved
|
52
|
+
- arbitrary objects are not allowed (it does obj.to_str or obj.to_s)
|
53
|
+
- strings must be valid method names
|
54
|
+
|
55
|
+
It's like Ara Howard's Named Array...
|
56
|
+
- we can access elements by ["name"] or ["name"]=
|
57
|
+
but...
|
58
|
+
- you can access the items by accessors
|
59
|
+
- strings must be valid method names
|
60
|
+
|
61
|
+
It's like Florian Gross's Keyed List...
|
62
|
+
(to be done)
|
63
|
+
but...
|
64
|
+
- it preserves the order of the fields
|
65
|
+
|
66
|
+
|
67
|
+
Some examples: (see test cases)
|
68
|
+
--------------
|
69
|
+
|
70
|
+
# Need not assign to existing fields (default to nil)
|
71
|
+
myStruct = SuperStruct.new(:alpha)
|
72
|
+
x = myStruct.new
|
73
|
+
x.alpha # nil
|
74
|
+
|
75
|
+
# A value assigned at construction may be retrieved
|
76
|
+
myStruct = SuperStruct.new(:alpha)
|
77
|
+
x = myStruct.new(234)
|
78
|
+
x.alpha # 234
|
79
|
+
|
80
|
+
# Unassigned fields are nil
|
81
|
+
myStruct = SuperStruct.new(:alpha,:beta)
|
82
|
+
x = myStruct.new(234)
|
83
|
+
x.beta # nil
|
84
|
+
|
85
|
+
# An open structure may not construct with nonexistent fields
|
86
|
+
myStruct = SuperStruct.open
|
87
|
+
x = myStruct.new(234) # error
|
88
|
+
|
89
|
+
# An open structure may assign fields not previously existing
|
90
|
+
myStruct = SuperStruct.open
|
91
|
+
x = myStruct.new
|
92
|
+
x.foo = 123
|
93
|
+
x.bar = 456
|
94
|
+
|
95
|
+
# The act of retrieving a nonexistent field from an open struct will
|
96
|
+
# create that field
|
97
|
+
myStruct = SuperStruct.open
|
98
|
+
x = myStruct.new
|
99
|
+
x.foo # nil
|
100
|
+
|
101
|
+
# A field (in an open struct) that is unassigned will be nil
|
102
|
+
myStruct = SuperStruct.open
|
103
|
+
x = myStruct.new
|
104
|
+
y = x.foobar
|
105
|
+
|
106
|
+
# A struct created with new rather than open cannot reference nonexistent
|
107
|
+
# fields
|
108
|
+
myStruct = SuperStruct.new
|
109
|
+
x = myStruct.new
|
110
|
+
x.foo # error
|
111
|
+
|
112
|
+
# Adding a field to a struct will create a writer and reader for that field
|
113
|
+
|
114
|
+
# An open struct will also create a writer and a reader together
|
115
|
+
|
116
|
+
# A field has a real writer and reader corresponding to it
|
117
|
+
|
118
|
+
# A string will work as well as a symbol
|
119
|
+
myStruct = SuperStruct.new("alpha")
|
120
|
+
|
121
|
+
# to_a will return an array of values
|
122
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
123
|
+
x = myStruct.new(7,8,9)
|
124
|
+
assert(x.to_a == [7,8,9])
|
125
|
+
|
126
|
+
# Instance method 'members' will return a list of members (as strings)
|
127
|
+
myStruct = SuperStruct.new(:alpha,"beta")
|
128
|
+
x = myStruct.new
|
129
|
+
assert_equal(["alpha","beta"],x.members)
|
130
|
+
|
131
|
+
# Class method 'members' will return a list of members (as strings)
|
132
|
+
myStruct = SuperStruct.new(:alpha,"beta")
|
133
|
+
assert_equal(["alpha","beta"],myStruct.members)
|
134
|
+
|
135
|
+
# to_ary will allow a struct to be treated like an array in
|
136
|
+
# multiple assignment
|
137
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
138
|
+
x = myStruct.new(7,8,9)
|
139
|
+
a,b,c = x
|
140
|
+
assert(b == 8)
|
141
|
+
|
142
|
+
# to_ary will allow a struct to be treated like an array in
|
143
|
+
# passed parameters
|
144
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
145
|
+
x = myStruct.new(7,8,9)
|
146
|
+
b = meth(*x)
|
147
|
+
|
148
|
+
# to_hash will return a hash with fields as keys
|
149
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
150
|
+
x = myStruct.new(7,8,9)
|
151
|
+
h = x.to_hash
|
152
|
+
assert_equal({"alpha"=>7,"beta"=>8,"gamma"=>9},h)
|
153
|
+
|
154
|
+
# A field name (String) may be used in a hash-like notation
|
155
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
156
|
+
x = myStruct.new(7,8,9)
|
157
|
+
y = x["beta"]
|
158
|
+
|
159
|
+
# A field name (Symbol) may be used in a hash-like notation
|
160
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
161
|
+
x = myStruct.new(7,8,9)
|
162
|
+
y = x[:beta]
|
163
|
+
|
164
|
+
# [offset,length] may be used as for arrays
|
165
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
166
|
+
x = myStruct.new(7,8,9)
|
167
|
+
y = x[0,2]
|
168
|
+
|
169
|
+
# Ranges may be used as for arrays
|
170
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
171
|
+
x = myStruct.new(7,8,9)
|
172
|
+
y = x[1..2]
|
173
|
+
|
174
|
+
# Adding a field to an open struct adds it to the instance
|
175
|
+
myStruct = SuperStruct.open(:alpha)
|
176
|
+
x = myStruct.new
|
177
|
+
x.beta = 5
|
178
|
+
|
179
|
+
# Adding a field to an open struct adds it to the class also
|
180
|
+
myStruct = SuperStruct.open(:alpha)
|
181
|
+
x = myStruct.new
|
182
|
+
x.beta = 5
|
183
|
+
|
184
|
+
# An array passed to SuperStruct.new need not be starred
|
185
|
+
myStruct = SuperStruct.new(%w[alpha beta gamma])
|
186
|
+
x = myStruct.new
|
187
|
+
|
188
|
+
# A hash passed to #set will set multiple values at once
|
189
|
+
myStruct = SuperStruct.new(%w[alpha beta gamma])
|
190
|
+
x = myStruct.new
|
191
|
+
hash = {"alpha"=>234,"beta"=>345,"gamma"=>456}
|
192
|
+
x.set(hash)
|
193
|
+
|
194
|
+
# ||= works properly
|
195
|
+
x = SuperStruct.open.new
|
196
|
+
x.foo ||= 333
|
197
|
+
x.bar = x.bar || 444
|
198
|
+
|
199
|
+
# attr_tester will create a ?-method
|
200
|
+
myStruct = SuperStruct.new(:alive)
|
201
|
+
myStruct.attr_tester :alive
|
202
|
+
x = myStruct.new(true)
|
203
|
+
x.alive? # true
|
204
|
+
|
data/lib/sstruct.rb
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
#
|
2
|
+
# SuperStruct
|
3
|
+
# Hal Fulton
|
4
|
+
# Version 1.0.0
|
5
|
+
# License: The Ruby License
|
6
|
+
#
|
7
|
+
# This is an easy way to create Struct-like classes; it converts easily
|
8
|
+
# between hashes and arrays, and it allows OpenStruct-like dynamic naming
|
9
|
+
# of members.
|
10
|
+
#
|
11
|
+
# Unlike Struct, it creates a "real" class, and it has real instance variables
|
12
|
+
# with predictable names.
|
13
|
+
#
|
14
|
+
# A basic limitation is that the hash keys must be legal method names (unless
|
15
|
+
# used with send()).
|
16
|
+
#
|
17
|
+
# Basically, ss["alpha"], ss[:alpha], ss[0], and ss.alpha all mean the same.
|
18
|
+
#
|
19
|
+
|
20
|
+
|
21
|
+
class SuperStruct
|
22
|
+
|
23
|
+
def SuperStruct.new(*args)
|
24
|
+
@table = []
|
25
|
+
@setsyms = [] # Setter symbols
|
26
|
+
klass = Class.new
|
27
|
+
if (args.size == 1) && (args[0].is_a? Array)
|
28
|
+
args = args[0]
|
29
|
+
end
|
30
|
+
strs = args.map {|x| x.to_s }
|
31
|
+
args.each_with_index do |k,i|
|
32
|
+
case
|
33
|
+
when (! [String,Symbol].include? k.class)
|
34
|
+
raise ArgumentError, "Need a String or Symbol"
|
35
|
+
when (strs[i] !~ /[_a-zA-Z][_a-zA-Z0-9]*/)
|
36
|
+
raise ArgumentError, "Illegal character"
|
37
|
+
end
|
38
|
+
k = k.intern if k.is_a? String
|
39
|
+
@table << k
|
40
|
+
@setsyms << (k.to_s + "=").intern
|
41
|
+
klass.instance_eval { attr_accessor k }
|
42
|
+
end
|
43
|
+
|
44
|
+
setsyms = @setsyms
|
45
|
+
table = @table
|
46
|
+
vals = @vals
|
47
|
+
klass.class_eval do
|
48
|
+
attr_reader :singleton
|
49
|
+
define_method(:initialize) do |*vals|
|
50
|
+
n = vals.size
|
51
|
+
m = table.size
|
52
|
+
case
|
53
|
+
when n < m
|
54
|
+
# raise ArgumentError, "Too few arguments (#{n} for #{m})"
|
55
|
+
# Never mind... extra variables will just be nil
|
56
|
+
when n > m
|
57
|
+
raise ArgumentError, "Too many arguments (#{n} for #{m})"
|
58
|
+
end
|
59
|
+
setsyms.each_with_index do |var,i|
|
60
|
+
self.send(var,vals[i])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
define_method(:pretty_print) do |q| # pp.rb support
|
64
|
+
q.object_group(self) do
|
65
|
+
q.seplist(self.members, proc { q.text "," }) do |member|
|
66
|
+
# self.members.each do |member|
|
67
|
+
# q.text "," # unless q.first?
|
68
|
+
q.breakable
|
69
|
+
q.text member.to_s
|
70
|
+
q.text '='
|
71
|
+
q.group(1) do
|
72
|
+
q.breakable ''
|
73
|
+
q.pp self[member]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
define_method(:inspect) do
|
79
|
+
str = "#<#{self.class}:"
|
80
|
+
table.each {|item| str << " #{item}=#{self.send(item)}" }
|
81
|
+
str + ">"
|
82
|
+
end
|
83
|
+
define_method(:[]) do |*index|
|
84
|
+
case index.map {|x| x.class }
|
85
|
+
when [Fixnum]
|
86
|
+
self.send(table[*index])
|
87
|
+
when [Fixnum,Fixnum], [Range]
|
88
|
+
table[*index].map {|x| self.send(x)}
|
89
|
+
when [String]
|
90
|
+
self.send(index[0].intern)
|
91
|
+
when [Symbol]
|
92
|
+
self.send(index[0])
|
93
|
+
else
|
94
|
+
raise ArgumentError,"Illegal index"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
define_method(:[]=) do |*index|
|
98
|
+
value = index[-1]
|
99
|
+
index = index[0..-2]
|
100
|
+
case index.map {|x| x.class }
|
101
|
+
when [Fixnum]
|
102
|
+
self.send(table[*index])
|
103
|
+
when [Fixnum,Fixnum], [Range]
|
104
|
+
setsyms[*index].map {|x| self.send(x,value) }
|
105
|
+
when [String]
|
106
|
+
self.send(index[0].intern,value)
|
107
|
+
when [Symbol]
|
108
|
+
self.send(index[0],value)
|
109
|
+
else
|
110
|
+
raise ArgumentError,"Illegal index"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
define_method(:to_a) { table.map {|x| eval("@"+x.to_s) } }
|
114
|
+
define_method(:to_ary) { to_a }
|
115
|
+
define_method(:members) { table.map {|x| x.to_s } }
|
116
|
+
define_method(:to_struct) do
|
117
|
+
mems = table
|
118
|
+
Struct.new("TEMP",*mems)
|
119
|
+
# Struct::TEMP.new(*vals) # Why doesn't this work??
|
120
|
+
data = mems.map {|x| self.send(x) }
|
121
|
+
Struct::TEMP.new(*data)
|
122
|
+
end
|
123
|
+
define_method(:to_hash) do
|
124
|
+
hash = {}
|
125
|
+
table.each do |mem|
|
126
|
+
mem = mem.to_s
|
127
|
+
hash.update(mem => self.send(mem))
|
128
|
+
end
|
129
|
+
hash
|
130
|
+
end
|
131
|
+
define_method(:set) {|h| h.each_pair {|k,v| send(k.to_s+"=",v) } }
|
132
|
+
|
133
|
+
# Class methods...
|
134
|
+
|
135
|
+
@singleton = class << self
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
@singleton.instance_eval do
|
140
|
+
define_method(:members) do
|
141
|
+
table.map {|x| x.to_s }
|
142
|
+
end
|
143
|
+
me = self
|
144
|
+
define_method(:attr_tester) do |*syms|
|
145
|
+
syms.each {|sym| alias_method(sym.to_s+"?",sym) }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
klass
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
def SuperStruct.open(*args)
|
155
|
+
klass = SuperStruct.new(*args)
|
156
|
+
table = @table
|
157
|
+
setsyms = @setsyms
|
158
|
+
table = @table
|
159
|
+
klass.class_eval do
|
160
|
+
define_method(:method_missing) do |meth, *args|
|
161
|
+
mname = meth.id2name
|
162
|
+
if mname =~ /=$/
|
163
|
+
getter = mname.chop
|
164
|
+
setter = mname
|
165
|
+
elsif mname =~ /\?$/
|
166
|
+
raise NoMethodError # ?-methods are not created automatically
|
167
|
+
else
|
168
|
+
getter = mname
|
169
|
+
setter = mname + "="
|
170
|
+
end
|
171
|
+
gsym = getter.intern
|
172
|
+
ssym = setter.intern
|
173
|
+
ivar = "@" + getter
|
174
|
+
setsyms << setter
|
175
|
+
table << getter
|
176
|
+
len = args.length
|
177
|
+
if mname == getter
|
178
|
+
klass.class_eval do # getter
|
179
|
+
define_method(getter) do
|
180
|
+
instance_variable_get(ivar)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
else
|
184
|
+
klass.class_eval do # setter
|
185
|
+
define_method(setter) do |*args|
|
186
|
+
if len != 1
|
187
|
+
raise ArgumentError, "Wrong # of arguments (#{len} for 1)",
|
188
|
+
caller(1)
|
189
|
+
end
|
190
|
+
instance_variable_set(ivar,args[0])
|
191
|
+
instance_variable_get(ivar)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
if mname == setter
|
196
|
+
self.send(setter,*args)
|
197
|
+
else
|
198
|
+
if len == 0
|
199
|
+
self.send(getter)
|
200
|
+
else
|
201
|
+
raise NoMethodError, "Undefined method '#{mname}' for #{self}",
|
202
|
+
caller(1)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
klass
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
require "test-sstruct" if $0 == __FILE__
|
data/sstruct.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
|
5
|
+
#### Basic information.
|
6
|
+
|
7
|
+
s.name = 'sstruct'
|
8
|
+
s.version = "1.0.1"
|
9
|
+
s.summary = <<-EOF
|
10
|
+
SuperStruct class: Best of Struct, OpenStruct, Array, Hash, etc.
|
11
|
+
EOF
|
12
|
+
s.description = <<-EOF
|
13
|
+
The SuperStruct class allows the easy and quick creation of classes that
|
14
|
+
consist mainly of data. It borrows from Struct, OpenStruct, Array, Hash,
|
15
|
+
ArrayFields, and others.
|
16
|
+
EOF
|
17
|
+
|
18
|
+
#### Dependencies and requirements.
|
19
|
+
|
20
|
+
#### Which files are to be included in this gem? Everything! (Except CVS)
|
21
|
+
|
22
|
+
s.files = Dir.glob("**/*").delete_if { |item| item.include?("CVS") }
|
23
|
+
|
24
|
+
#### Load-time details: library and application (you will need one or both).
|
25
|
+
|
26
|
+
s.require_path = 'lib' # Use these for libraries.
|
27
|
+
s.autorequire = 'sstruct'
|
28
|
+
|
29
|
+
#### Documentation and testing.
|
30
|
+
|
31
|
+
s.has_rdoc = false
|
32
|
+
s.test_file = "test/test-sstruct.rb"
|
33
|
+
|
34
|
+
#### Author and project details.
|
35
|
+
|
36
|
+
s.author = "Hal E. Fulton"
|
37
|
+
s.email = "hal9000@hypermetrics.com"
|
38
|
+
s.homepage = "http://sstruct.rubyforge.org"
|
39
|
+
s.rubyforge_project = "sstruct"
|
40
|
+
end
|
@@ -0,0 +1,318 @@
|
|
1
|
+
#
|
2
|
+
# SuperStruct test code
|
3
|
+
# Hal Fulton
|
4
|
+
# Version 1.0.0 (in sync with library code)
|
5
|
+
# License: The Ruby License
|
6
|
+
#
|
7
|
+
|
8
|
+
require "test/unit"
|
9
|
+
require "sstruct"
|
10
|
+
|
11
|
+
class Tester < Test::Unit::TestCase
|
12
|
+
|
13
|
+
def test001
|
14
|
+
# Must pass in String or Symbol
|
15
|
+
assert_raises(ArgumentError) { SuperStruct.new(0) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def test002
|
19
|
+
# Must pass in valid name(s)
|
20
|
+
assert_raises(ArgumentError) { SuperStruct.new("###") }
|
21
|
+
end
|
22
|
+
|
23
|
+
def test003
|
24
|
+
# Can't assign to nonexistent fields
|
25
|
+
myStruct = SuperStruct.new
|
26
|
+
assert_raises(ArgumentError) { myStruct.new(345) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def test004
|
30
|
+
# Need not assign to existing fields (default to nil)
|
31
|
+
myStruct = SuperStruct.new(:alpha)
|
32
|
+
assert_nothing_raised(ArgumentError) { myStruct.new }
|
33
|
+
end
|
34
|
+
|
35
|
+
def test005
|
36
|
+
# A value assigned at construction may be retrieved
|
37
|
+
myStruct = SuperStruct.new(:alpha)
|
38
|
+
x = myStruct.new(234)
|
39
|
+
assert(x.alpha == 234)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test006
|
43
|
+
# Unassigned fields are nil
|
44
|
+
myStruct = SuperStruct.new(:alpha,:beta)
|
45
|
+
x = myStruct.new(234)
|
46
|
+
assert(x.beta == nil)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test007
|
50
|
+
# An open structure still may not construct with nonexistent fields
|
51
|
+
myStruct = SuperStruct.open
|
52
|
+
assert_raises(ArgumentError) { x = myStruct.new(234) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def test008
|
56
|
+
# An open structure may assign fields not previously existing
|
57
|
+
myStruct = SuperStruct.open
|
58
|
+
x = myStruct.new
|
59
|
+
assert_nothing_raised { x.foobar = 123 }
|
60
|
+
end
|
61
|
+
|
62
|
+
def test009
|
63
|
+
# A field assigned to an open struct after its construction may be retrieved
|
64
|
+
myStruct = SuperStruct.open
|
65
|
+
x = myStruct.new
|
66
|
+
x.foobar = 123
|
67
|
+
assert(x.foobar == 123)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test010
|
71
|
+
# The act of retrieving a nonexistent field from an open struct will
|
72
|
+
# create that field
|
73
|
+
myStruct = SuperStruct.open
|
74
|
+
x = myStruct.new
|
75
|
+
assert_nothing_raised { y = x.foobar }
|
76
|
+
end
|
77
|
+
|
78
|
+
def test011
|
79
|
+
# A field (in an open struct) that is unassigned will be nil
|
80
|
+
myStruct = SuperStruct.open
|
81
|
+
x = myStruct.new
|
82
|
+
y = x.foobar
|
83
|
+
assert(y == nil)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test012
|
87
|
+
# A struct created with new rather than open cannot reference nonexistent
|
88
|
+
# fields
|
89
|
+
myStruct = SuperStruct.new
|
90
|
+
x = myStruct.new
|
91
|
+
assert_raises(NoMethodError) { y = x.foobar }
|
92
|
+
end
|
93
|
+
|
94
|
+
def test013
|
95
|
+
# Adding a field to a struct will create a writer and reader for that field
|
96
|
+
myStruct = SuperStruct.new(:alpha)
|
97
|
+
x = myStruct.new
|
98
|
+
x.send(:alpha=,1)
|
99
|
+
assert(x.alpha == 1)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test014
|
103
|
+
# Only a single value may be passed to a writer (for code coverage)
|
104
|
+
myStruct = SuperStruct.new(:alpha)
|
105
|
+
x = myStruct.new
|
106
|
+
assert_raises(ArgumentError) { x.send(:alpha=,1,2) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def test015
|
110
|
+
# An open struct will also create a writer and a reader together
|
111
|
+
myStruct = SuperStruct.open
|
112
|
+
x = myStruct.new
|
113
|
+
x.send(:alpha=,1)
|
114
|
+
assert(x.alpha == 1)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test016
|
118
|
+
# Only a single value may be passed to a writer (for code coverage)
|
119
|
+
myStruct = SuperStruct.open
|
120
|
+
x = myStruct.new
|
121
|
+
assert_raises(ArgumentError) { x.send(:alpha=,1,2) }
|
122
|
+
end
|
123
|
+
|
124
|
+
def test017
|
125
|
+
# A field has a real writer and reader corresponding to it
|
126
|
+
myStruct = SuperStruct.new(:alpha)
|
127
|
+
x = myStruct.new
|
128
|
+
assert(myStruct.instance_methods.include?("alpha"))
|
129
|
+
assert(myStruct.instance_methods.include?("alpha="))
|
130
|
+
end
|
131
|
+
|
132
|
+
def test018
|
133
|
+
# Creating a field by retrieval in an open struct will NOT create a writer
|
134
|
+
# (This behavior has changed!)
|
135
|
+
myStruct = SuperStruct.open
|
136
|
+
x = myStruct.new
|
137
|
+
y = x.alpha
|
138
|
+
assert(myStruct.instance_methods.include?("alpha"))
|
139
|
+
assert(!myStruct.instance_methods.include?("alpha="))
|
140
|
+
end
|
141
|
+
|
142
|
+
def test019
|
143
|
+
# Creating a field by writing in an open struct will NOT create a reader
|
144
|
+
# (This behavior has changed!)
|
145
|
+
myStruct = SuperStruct.open
|
146
|
+
x = myStruct.new
|
147
|
+
x.alpha = 5
|
148
|
+
assert(myStruct.instance_methods.include?("alpha="))
|
149
|
+
assert(!myStruct.instance_methods.include?("alpha"))
|
150
|
+
end
|
151
|
+
|
152
|
+
def test020
|
153
|
+
# A string will work as well as a symbol
|
154
|
+
myStruct = SuperStruct.new("alpha")
|
155
|
+
x = myStruct.new
|
156
|
+
assert(myStruct.instance_methods.include?("alpha"))
|
157
|
+
assert(myStruct.instance_methods.include?("alpha="))
|
158
|
+
end
|
159
|
+
|
160
|
+
def test021
|
161
|
+
# to_a will return an array of values
|
162
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
163
|
+
x = myStruct.new(7,8,9)
|
164
|
+
assert(x.to_a == [7,8,9])
|
165
|
+
end
|
166
|
+
|
167
|
+
def test022
|
168
|
+
# Instance method 'members' will return a list of members (as strings)
|
169
|
+
myStruct = SuperStruct.new(:alpha,"beta")
|
170
|
+
x = myStruct.new
|
171
|
+
assert_equal(["alpha","beta"],x.members)
|
172
|
+
end
|
173
|
+
|
174
|
+
def test023
|
175
|
+
# Class method 'members' will return a list of members (as strings)
|
176
|
+
myStruct = SuperStruct.new(:alpha,"beta")
|
177
|
+
assert_equal(["alpha","beta"],myStruct.members)
|
178
|
+
end
|
179
|
+
|
180
|
+
def test024
|
181
|
+
# to_ary will allow a struct to be treated like an array in
|
182
|
+
# multiple assignment
|
183
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
184
|
+
x = myStruct.new(7,8,9)
|
185
|
+
a,b,c = x
|
186
|
+
assert(b == 8)
|
187
|
+
end
|
188
|
+
|
189
|
+
def aux025(*arr) # Just used in test 25
|
190
|
+
arr[1]
|
191
|
+
end
|
192
|
+
|
193
|
+
def test025
|
194
|
+
# to_ary will allow a struct to be treated like an array in
|
195
|
+
# passed parameters
|
196
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
197
|
+
x = myStruct.new(7,8,9)
|
198
|
+
b = aux025(*x)
|
199
|
+
assert(b == 8)
|
200
|
+
end
|
201
|
+
|
202
|
+
def test026
|
203
|
+
# to_hash will return a hash with fields as keys
|
204
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
205
|
+
x = myStruct.new(7,8,9)
|
206
|
+
h = x.to_hash
|
207
|
+
assert_equal({"alpha"=>7,"beta"=>8,"gamma"=>9},h)
|
208
|
+
end
|
209
|
+
|
210
|
+
def test027
|
211
|
+
# A field name (String) may be used in a hash-like notation
|
212
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
213
|
+
x = myStruct.new(7,8,9)
|
214
|
+
y = x["beta"]
|
215
|
+
assert(8,y)
|
216
|
+
end
|
217
|
+
|
218
|
+
def test028
|
219
|
+
# A field name (Symbol) may be used in a hash-like notation
|
220
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
221
|
+
x = myStruct.new(7,8,9)
|
222
|
+
y = x[:beta]
|
223
|
+
assert(8,y)
|
224
|
+
end
|
225
|
+
|
226
|
+
def test029
|
227
|
+
# [offset,length] may be used as for arrays
|
228
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
229
|
+
x = myStruct.new(7,8,9)
|
230
|
+
y = x[0,2]
|
231
|
+
assert([7,8],y)
|
232
|
+
end
|
233
|
+
|
234
|
+
def test030
|
235
|
+
# Ranges may be used as for arrays
|
236
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
237
|
+
x = myStruct.new(7,8,9)
|
238
|
+
y = x[1..2]
|
239
|
+
assert([8,9],y)
|
240
|
+
end
|
241
|
+
|
242
|
+
def test031
|
243
|
+
# Adding a field to an open struct adds it to the instance
|
244
|
+
myStruct = SuperStruct.open(:alpha)
|
245
|
+
x = myStruct.new
|
246
|
+
x.beta = 5
|
247
|
+
assert_equal(["alpha","beta"],x.members)
|
248
|
+
end
|
249
|
+
|
250
|
+
def test032
|
251
|
+
# Adding a field to an open struct adds it to the class also
|
252
|
+
myStruct = SuperStruct.open(:alpha)
|
253
|
+
x = myStruct.new
|
254
|
+
x.beta = 5
|
255
|
+
assert_equal(["alpha","beta"],myStruct.members)
|
256
|
+
end
|
257
|
+
|
258
|
+
def test033
|
259
|
+
# An array passed to SuperStruct.new need not be starred
|
260
|
+
myStruct = SuperStruct.new(%w[alpha beta gamma])
|
261
|
+
x = myStruct.new
|
262
|
+
assert_equal(%w[alpha beta gamma],x.members)
|
263
|
+
end
|
264
|
+
|
265
|
+
def xtest034
|
266
|
+
# A hash passed to SuperStruct.new will initialize the values
|
267
|
+
# (but order will not be predictable!)
|
268
|
+
assert false, "Not implemented yet."
|
269
|
+
end
|
270
|
+
|
271
|
+
def test035
|
272
|
+
# A hash passed to #set will set multiple values at once
|
273
|
+
myStruct = SuperStruct.new(%w[alpha beta gamma])
|
274
|
+
x = myStruct.new
|
275
|
+
hash = {"alpha"=>234,"beta"=>345,"gamma"=>456}
|
276
|
+
x.set(hash)
|
277
|
+
assert_equal([234,345,456], x.to_a)
|
278
|
+
end
|
279
|
+
|
280
|
+
def test036
|
281
|
+
# Make sure ||= works properly
|
282
|
+
x = SuperStruct.open.new
|
283
|
+
x.foo ||= 333
|
284
|
+
x.bar = x.bar || 444
|
285
|
+
assert_equal(333,x.foo)
|
286
|
+
assert_equal(444,x.bar)
|
287
|
+
end
|
288
|
+
|
289
|
+
def test037
|
290
|
+
# A simple array index works ok
|
291
|
+
myStruct = SuperStruct.new("alpha","beta","gamma")
|
292
|
+
x = myStruct.new(7,8,9)
|
293
|
+
assert_equal(7,x[0])
|
294
|
+
assert_equal(8,x[1])
|
295
|
+
assert_equal(9,x[2])
|
296
|
+
end
|
297
|
+
|
298
|
+
def test038
|
299
|
+
# attr_tester will create a ?-method
|
300
|
+
klass = SuperStruct.new(:alpha,:beta,:gamma)
|
301
|
+
klass.attr_tester :alpha, :gamma
|
302
|
+
x = klass.new(22,33,nil)
|
303
|
+
assert(x.alpha?)
|
304
|
+
assert_raises(NoMethodError) { x.beta? }
|
305
|
+
assert(! x.gamma?)
|
306
|
+
end
|
307
|
+
|
308
|
+
def test039
|
309
|
+
# attr_tester works with open() (?-methods not created)
|
310
|
+
klass = SuperStruct.open(:alpha,:beta,:gamma)
|
311
|
+
klass.attr_tester :alpha, :gamma
|
312
|
+
x = klass.new(22,33,nil)
|
313
|
+
assert(x.alpha?)
|
314
|
+
assert_raises(NoMethodError) { x.beta? } # ?-methods are not automatic
|
315
|
+
assert(! x.gamma?)
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
metadata
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.1
|
3
|
+
specification_version: 1
|
4
|
+
name: sstruct
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.1
|
7
|
+
date: 2004-11-17
|
8
|
+
summary: "SuperStruct class: Best of Struct, OpenStruct, Array, Hash, etc."
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
author: Hal E. Fulton
|
12
|
+
email: hal9000@hypermetrics.com
|
13
|
+
homepage: http://sstruct.rubyforge.org
|
14
|
+
rubyforge_project: sstruct
|
15
|
+
description: "The SuperStruct class allows the easy and quick creation of classes that consist mainly of data. It borrows from Struct, OpenStruct, Array, Hash, ArrayFields, and others."
|
16
|
+
autorequire: sstruct
|
17
|
+
default_executable:
|
18
|
+
bindir: bin
|
19
|
+
has_rdoc: false
|
20
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
21
|
+
requirements:
|
22
|
+
-
|
23
|
+
- ">"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.0.0
|
26
|
+
version:
|
27
|
+
platform: ruby
|
28
|
+
files:
|
29
|
+
- doc
|
30
|
+
- sstruct.gemspec
|
31
|
+
- test
|
32
|
+
- lib
|
33
|
+
- doc/sstruct.txt
|
34
|
+
- test/test-sstruct.rb
|
35
|
+
- lib/sstruct.rb
|
36
|
+
test_files:
|
37
|
+
- test/test-sstruct.rb
|
38
|
+
rdoc_options: []
|
39
|
+
extra_rdoc_files: []
|
40
|
+
executables: []
|
41
|
+
extensions: []
|
42
|
+
requirements: []
|
43
|
+
dependencies: []
|