classy_struct 0.2.0 → 0.3.0
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/.gitignore +1 -0
- data/README.rdoc +35 -3
- data/VERSION +1 -1
- data/lib/classy_struct.rb +31 -1
- data/spec/classy_struct_spec.rb +76 -5
- metadata +2 -2
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -1,9 +1,41 @@
|
|
1
1
|
= classy_struct
|
2
2
|
|
3
|
-
|
3
|
+
A better-performing alternative to OpenStruct
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
First, create a class instance of ClassyStruct:
|
8
|
+
|
9
|
+
require 'classy_struct'
|
10
|
+
Widget = ClassyStruct.new
|
11
|
+
|
12
|
+
|
13
|
+
Next, create instances of that class the same as you would with any
|
14
|
+
other class:
|
15
|
+
|
16
|
+
w1 = Widget.new
|
17
|
+
|
18
|
+
|
19
|
+
These instances are open in much the same way that OpenStruct
|
20
|
+
instances are open:
|
21
|
+
|
22
|
+
w1.foo = :bar
|
23
|
+
w1.foo # => :bar
|
24
|
+
|
25
|
+
However, generated accessors are applied to the class instance (in
|
26
|
+
this case, Widget) instead of the object instance. This means that
|
27
|
+
accessors only need to be generated once for the class, and instances
|
28
|
+
of that class get the accessors automatically.
|
29
|
+
|
30
|
+
You can also pass a Hash to the constructor, to be recursively
|
31
|
+
converted to ClassyStruct objects:
|
32
|
+
|
33
|
+
w1 = Widget.new(:foo => :bar, :baz => {:xyzzy => :thud})
|
34
|
+
w1.foo # => :bar
|
35
|
+
w1.baz.xyzzy # => :thud
|
4
36
|
|
5
37
|
== Note on Patches/Pull Requests
|
6
|
-
|
38
|
+
|
7
39
|
* Fork the project.
|
8
40
|
* Make your feature addition or bug fix.
|
9
41
|
* Add tests for it. This is important so I don't break it in a
|
@@ -15,4 +47,4 @@ Description goes here.
|
|
15
47
|
|
16
48
|
== Copyright
|
17
49
|
|
18
|
-
Copyright (c) 2009
|
50
|
+
Copyright (c) 2009 Alf Mikula. See LICENSE for details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/classy_struct.rb
CHANGED
@@ -2,11 +2,12 @@ class ClassyStruct
|
|
2
2
|
def self.new(&block)
|
3
3
|
klass = Class.new(ClassyStructClass)
|
4
4
|
klass.method_mapper = block
|
5
|
+
klass.attr_names = []
|
5
6
|
klass
|
6
7
|
end
|
7
8
|
|
8
9
|
class ClassyStructClass
|
9
|
-
def initialize(hash=
|
10
|
+
def initialize(hash=nil)
|
10
11
|
if hash
|
11
12
|
hash.each_pair do |k,v|
|
12
13
|
k = self.class.method_mapper.call(k.to_s) if self.class.method_mapper
|
@@ -24,6 +25,7 @@ class ClassyStruct
|
|
24
25
|
|
25
26
|
class << self
|
26
27
|
attr_accessor :method_mapper
|
28
|
+
attr_accessor :attr_names
|
27
29
|
|
28
30
|
def node_class(name)
|
29
31
|
@__node_classes ||= {}
|
@@ -42,6 +44,32 @@ class ClassyStruct
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
47
|
+
def _attrs
|
48
|
+
self.class.attr_names.inject({}) do |retval, attr_name|
|
49
|
+
retval[attr_name] = send(attr_name)
|
50
|
+
retval
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
to_hash.inspect
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_hash
|
59
|
+
retval = _attrs
|
60
|
+
|
61
|
+
retval.each_pair do |key,val|
|
62
|
+
case val
|
63
|
+
when ClassyStruct::ClassyStructClass
|
64
|
+
retval[key] = val.to_hash
|
65
|
+
when Array
|
66
|
+
retval[key] = val.map{|e| e.is_a?(ClassyStruct::ClassyStructClass) ? e.to_hash : e}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
retval
|
71
|
+
end
|
72
|
+
|
45
73
|
def new_child(key)
|
46
74
|
self.send("#{key}=", self.class.node_class(key).new)
|
47
75
|
end
|
@@ -59,6 +87,8 @@ class ClassyStruct
|
|
59
87
|
end
|
60
88
|
EOF
|
61
89
|
|
90
|
+
self.class.attr_names << base.to_sym
|
91
|
+
|
62
92
|
send(name, *args)
|
63
93
|
end
|
64
94
|
end
|
data/spec/classy_struct_spec.rb
CHANGED
@@ -46,11 +46,11 @@ describe ClassyStruct do
|
|
46
46
|
|
47
47
|
o.bar = :baz
|
48
48
|
|
49
|
-
o.methods.should include('bar')
|
50
|
-
o.class.instance_methods.should include('bar')
|
49
|
+
o.methods.map { |m| m.to_s }.should include('bar')
|
50
|
+
o.class.instance_methods.map { |m| m.to_s }.should include('bar')
|
51
51
|
|
52
52
|
p = @foo_struct.new
|
53
|
-
p.methods.should include('bar')
|
53
|
+
p.methods.map { |m| m.to_s }.should include('bar')
|
54
54
|
|
55
55
|
p.should_not_receive(:method_missing)
|
56
56
|
p.bar
|
@@ -60,8 +60,15 @@ describe ClassyStruct do
|
|
60
60
|
o = @foo_struct.new
|
61
61
|
o.bar = :baz
|
62
62
|
|
63
|
-
@foo_struct.instance_methods.should include('bar')
|
64
|
-
@bar_struct.instance_methods.should_not include('bar')
|
63
|
+
@foo_struct.instance_methods.map { |m| m.to_s }.should include('bar')
|
64
|
+
@bar_struct.instance_methods.map { |m| m.to_s }.should_not include('bar')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'adds attribute names to attr_names on the base class' do
|
68
|
+
o = @foo_struct.new
|
69
|
+
o.bar = :baz
|
70
|
+
|
71
|
+
@foo_struct.attr_names.should include(:bar)
|
65
72
|
end
|
66
73
|
end
|
67
74
|
|
@@ -178,5 +185,69 @@ describe ClassyStruct do
|
|
178
185
|
o.new_child(:foo).should == o.foo
|
179
186
|
end
|
180
187
|
end
|
188
|
+
|
189
|
+
describe :_attrs do
|
190
|
+
it 'returns a hash with all the attribute names and values' do
|
191
|
+
instance = @foo_struct.new(:foo => :bar, :baz => :xyzzy)
|
192
|
+
|
193
|
+
instance._attrs.should == {:foo => :bar, :baz => :xyzzy}
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'returns values which have been overridden since initialization' do
|
197
|
+
instance = @foo_struct.new(:foo => :bar, :baz => :xyzzy)
|
198
|
+
instance.foo = :thud
|
199
|
+
|
200
|
+
instance._attrs.should == {:foo => :thud, :baz => :xyzzy}
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'returns nil for attribute values which have not been assigned for this instance' do
|
204
|
+
instance1 = @foo_struct.new(:foo => :bar, :baz => :xyzzy)
|
205
|
+
instance1.foo = :thud
|
206
|
+
|
207
|
+
instance2 = @foo_struct.new(:fizz => :buzz)
|
208
|
+
instance2._attrs[:fizz].should == :buzz
|
209
|
+
|
210
|
+
instance2._attrs.should have_key(:foo)
|
211
|
+
instance2._attrs[:foo].should be_nil
|
212
|
+
|
213
|
+
instance2._attrs.should have_key(:baz)
|
214
|
+
instance2._attrs[:baz].should be_nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'does not convert nested ClassyStruct objects' do
|
218
|
+
instance = @foo_struct.new(:foo => :bar, :baz => {:xyzzy => :thud})
|
219
|
+
|
220
|
+
instance._attrs[:baz].should be_a(ClassyStruct::ClassyStructClass)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe :to_hash do
|
225
|
+
it 'returns a hash with all the attribute names and values' do
|
226
|
+
instance = @foo_struct.new(:foo => :bar, :baz => :xyzzy)
|
227
|
+
|
228
|
+
instance.to_hash.should == {:foo => :bar, :baz => :xyzzy}
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'recursively converts classy_struct children to hashes' do
|
232
|
+
instance = @foo_struct.new(:foo => :bar, :baz => {:xyzzy => :thud})
|
233
|
+
|
234
|
+
instance.to_hash.should == {:foo => :bar, :baz => {:xyzzy => :thud}}
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'recursively converts classy_struct children in arrays to hashes' do
|
238
|
+
instance = @foo_struct.new(:foo => :bar, :baz => [{:xyzzy => :thud}])
|
239
|
+
|
240
|
+
instance.to_hash.should == {:foo => :bar, :baz => [{:xyzzy => :thud}]}
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe :inspect do
|
245
|
+
it 'returns to_hash.inspect' do
|
246
|
+
instance = @foo_struct.new
|
247
|
+
instance.should_receive(:to_hash).and_return(mock(:inspect => 'inspected!'))
|
248
|
+
|
249
|
+
instance.inspect.should == 'inspected!'
|
250
|
+
end
|
251
|
+
end
|
181
252
|
end
|
182
253
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: classy_struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- amikula
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-15 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|