blobject 0.2.3 → 0.3.2
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 -1
- data/.pryrc +1 -1
- data/Gemfile.lock +42 -0
- data/README.markdown +157 -0
- data/{README.md → README.md_} +0 -0
- data/Rakefile +1 -1
- data/benchmarks/benchmark.rb +100 -0
- data/benchmarks/results +12 -0
- data/blob_defn.png +0 -0
- data/blobject.gemspec +4 -3
- data/console +7 -0
- data/lib/blobject.rb +218 -168
- data/lib/blobject/version.rb +1 -1
- data/makefile +4 -0
- data/spec/blobject_spec.rb +241 -119
- data/spec/env.rb +12 -0
- data/spec/exec +7 -0
- data/spec/sample_data/sample.json +1 -0
- data/spec/sample_data/sample.yaml +6 -0
- data/spec/sample_data/sample2.json +1 -0
- data/spec/sample_data/sample2.yaml +8 -0
- metadata +51 -15
- data/.rspec +0 -2
- data/benchmark.rb +0 -71
- data/benchmark0 +0 -20
- data/spec/spec_helper.rb +0 -12
data/lib/blobject/version.rb
CHANGED
data/makefile
ADDED
data/spec/blobject_spec.rb
CHANGED
@@ -1,155 +1,277 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec/env'
|
2
2
|
require 'blobject'
|
3
3
|
|
4
4
|
describe Blobject do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
|
6
|
+
def b
|
7
|
+
@b ||= Blobject.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'raises an error if the call is not a reader, writer or checker' do
|
11
|
+
|
12
|
+
proc do
|
13
|
+
b.fish_for :salmon, :sole
|
14
|
+
end.must_raise NoMethodError
|
15
|
+
|
16
|
+
proc do
|
17
|
+
b.checker_with_an_arg? :this_should_not_be_here
|
18
|
+
end.must_raise NoMethodError
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'provides access tot he internal hash with #hash' do
|
23
|
+
assert b.hash.equal?(b.instance_variable_get :@hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sets values when calling a writer' do
|
27
|
+
b.number = 123
|
28
|
+
assert_equal b.number, 123
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'sets objects n levels deep' do
|
32
|
+
b.name.nickname.back_at_school = 'Richard Head'
|
33
|
+
assert_equal b.name.nickname.back_at_school, 'Richard Head'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'does not result in a graph containing empty blobjects' do
|
37
|
+
b.fish.food
|
38
|
+
assert !b.fish?, 'should not have assigned an empty blobject'
|
13
39
|
end
|
14
|
-
|
15
|
-
it '
|
16
|
-
expect {
|
17
|
-
blobject.name 'hello'
|
18
|
-
}.to raise_error
|
19
|
-
end
|
40
|
+
|
41
|
+
it 'turns hashes into blobjects when assigning' do
|
20
42
|
|
21
|
-
|
43
|
+
b.name = { christian: "Vinnie", surname: "Jones" }
|
22
44
|
|
23
|
-
|
24
|
-
|
25
|
-
|
45
|
+
assert_instance_of Blobject, b.name
|
46
|
+
assert_equal b.name.christian, "Vinnie"
|
47
|
+
assert_equal b.name.surname, "Jones"
|
26
48
|
end
|
27
|
-
|
28
|
-
describe '
|
29
|
-
it 'should return true on an empty blobject' do
|
30
|
-
blobject.should be_empty
|
31
|
-
end
|
49
|
+
|
50
|
+
describe 'respond_to?' do
|
32
51
|
|
33
|
-
it '
|
34
|
-
|
35
|
-
|
52
|
+
it 'returns true if the blobject has the corresponding member' do
|
53
|
+
b.name = 'jim'
|
54
|
+
assert b.respond_to?(:name)
|
55
|
+
assert b.respond_to?(:name=)
|
56
|
+
assert b.respond_to?(:name?)
|
36
57
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
it 'should store assignment of variables to any depth in the object graph' do
|
42
|
-
|
43
|
-
b = blobject.modify do
|
44
|
-
variable 'hello'
|
45
|
-
deep.object.graph.member 123
|
58
|
+
|
59
|
+
it 'should return true if a prohibited attribute name is a defined method' do
|
60
|
+
def b.to_ary
|
61
|
+
123
|
46
62
|
end
|
47
|
-
|
48
|
-
blobject.variable.should == 'hello'
|
49
|
-
blobject.deep.object.graph.member.should == 123
|
63
|
+
assert b.respond_to? :to_ary
|
50
64
|
end
|
51
|
-
|
52
|
-
it 'should
|
53
|
-
|
54
|
-
blobject.modify do
|
55
|
-
name(1, 2)
|
56
|
-
end
|
57
|
-
}.to raise_error(NoMethodError)
|
65
|
+
|
66
|
+
it 'should return false if the methods ends with a !' do
|
67
|
+
refute b.respond_to? :hello!
|
58
68
|
end
|
59
|
-
|
60
|
-
it '
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
69
|
+
|
70
|
+
it 'returns true if the blobject has no corresponding member' do
|
71
|
+
b.name = 'jim'
|
72
|
+
assert b.respond_to?(:name)
|
73
|
+
assert b.respond_to?(:name=)
|
74
|
+
assert b.respond_to?(:name?)
|
66
75
|
end
|
67
|
-
|
68
|
-
it 'should
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
blobject.name.first.should == 'Barry'
|
74
|
-
blobject.name.last.should == 'Watkins'
|
76
|
+
|
77
|
+
it 'should return true if the blobject has the corresponding member but the accessor has not been memoized' do
|
78
|
+
b = Blobject.new :name => 'barry'
|
79
|
+
assert b.respond_to?(:name)
|
80
|
+
assert b.respond_to?(:name=)
|
81
|
+
assert b.respond_to?(:name?)
|
75
82
|
end
|
76
|
-
|
77
|
-
it '
|
78
|
-
|
79
|
-
rtn.should equal blobject
|
83
|
+
|
84
|
+
it 'returns false for :to_ary because that method is not allowed' do
|
85
|
+
refute Blobject.new.respond_to? :to_ary
|
80
86
|
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'to_hash' do
|
90
|
+
|
91
|
+
it 'should recursively reify the blobject into a hash' do
|
92
|
+
b.name.first = 'barry'
|
93
|
+
b.number = 123456
|
94
|
+
|
95
|
+
h = b.to_hash
|
96
|
+
|
97
|
+
assert_instance_of Hash, h
|
98
|
+
assert_instance_of Hash, h[:name]
|
99
|
+
assert_equal h[:number], 123456
|
100
|
+
assert_equal h[:name][:first], 'barry'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'from_json' do
|
81
105
|
|
82
|
-
|
106
|
+
describe 'array' do
|
83
107
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
last 'mcdoodle'
|
93
|
-
end
|
108
|
+
it 'returns an array with blobjects not hashes' do
|
109
|
+
json = '[1, true, {"meaning": false}]'
|
110
|
+
array = Blobject.from_json json
|
111
|
+
|
112
|
+
assert_instance_of Array, array
|
113
|
+
assert_equal array[0], 1
|
114
|
+
assert_equal array[1], true
|
115
|
+
assert_instance_of Blobject, array[2]
|
94
116
|
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe 'json object' do
|
95
120
|
|
96
|
-
blobject
|
97
|
-
|
98
|
-
|
121
|
+
it 'returns a blobject which' do
|
122
|
+
json = '{"name": {"first": "doogle"}}'
|
123
|
+
b = Blobject.from_json json
|
124
|
+
assert_equal b.name.first, 'doogle'
|
125
|
+
assert b.name?
|
126
|
+
|
127
|
+
end
|
99
128
|
end
|
100
129
|
end
|
101
130
|
|
102
|
-
describe '
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
131
|
+
describe 'initialize' do
|
132
|
+
it 'takes an initial value as a hash' do
|
133
|
+
b = Blobject.new :inner => {:nested => :hash}, :value => 12345
|
134
|
+
assert_equal b.value, 12345
|
135
|
+
assert b.inner?
|
136
|
+
assert_equal b.inner.nested, :hash
|
107
137
|
end
|
108
|
-
|
109
|
-
it '
|
110
|
-
|
138
|
+
|
139
|
+
it 'recurses through the initial hash turning hashes into blobjects' do
|
140
|
+
b = Blobject.new :name => {:first => 'doogle', :last => 'mcfoogle'}
|
141
|
+
assert_instance_of Blobject, b.name
|
142
|
+
assert_equal b.name.first, 'doogle'
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'yields to a block with self as a parameter' do
|
146
|
+
b = Blobject.new do |b|
|
147
|
+
b.name = 'yield'
|
148
|
+
end
|
149
|
+
|
150
|
+
assert_equal 'yield', b.name
|
111
151
|
end
|
112
152
|
end
|
113
|
-
|
114
|
-
describe '
|
115
|
-
|
116
|
-
|
117
|
-
|
153
|
+
|
154
|
+
describe 'checking' do
|
155
|
+
|
156
|
+
it 'returns true if the attribute exists' do
|
157
|
+
b.fish = 'bass'
|
158
|
+
assert b.fish?
|
118
159
|
end
|
119
|
-
|
120
|
-
it '
|
121
|
-
|
160
|
+
|
161
|
+
it 'returns false if the attribute does not exist' do
|
162
|
+
assert !b.fish?
|
122
163
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
blobject.should_receive(:send).with(:name, 'barry')
|
128
|
-
blobject[:name] = 'barry'
|
164
|
+
|
165
|
+
it 'does not indicate the boolean status of the value' do
|
166
|
+
b.fish = false
|
167
|
+
assert b.fish?
|
129
168
|
end
|
130
169
|
end
|
131
170
|
|
132
|
-
describe '
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
171
|
+
describe 'memoization' do
|
172
|
+
|
173
|
+
it 'creates checker, reader and writer memoize methods after they are called the first time' do
|
174
|
+
|
175
|
+
b.method_unlikely_already_to_be_defined = 123
|
176
|
+
|
177
|
+
b.methods.must_include :method_unlikely_already_to_be_defined
|
178
|
+
b.methods.must_include :method_unlikely_already_to_be_defined=
|
179
|
+
b.methods.must_include :method_unlikely_already_to_be_defined?
|
180
|
+
|
181
|
+
b.another_method_unlikely_already_to_be_defined
|
182
|
+
|
183
|
+
b.methods.must_include :another_method_unlikely_already_to_be_defined
|
184
|
+
b.methods.must_include :another_method_unlikely_already_to_be_defined=
|
185
|
+
b.methods.must_include :another_method_unlikely_already_to_be_defined?
|
186
|
+
|
187
|
+
b.yet_another_method_unlikely_already_to_be_defined?
|
188
|
+
|
189
|
+
b.methods.must_include :another_method_unlikely_already_to_be_defined
|
190
|
+
b.methods.must_include :another_method_unlikely_already_to_be_defined=
|
191
|
+
b.methods.must_include :another_method_unlikely_already_to_be_defined?
|
139
192
|
end
|
140
|
-
|
141
|
-
it '
|
142
|
-
|
193
|
+
|
194
|
+
it 'does not redefine existing members' do
|
195
|
+
|
196
|
+
def b.hello
|
197
|
+
123
|
198
|
+
end
|
199
|
+
|
200
|
+
b.hello=456
|
201
|
+
|
202
|
+
assert_equal 123, b.hello
|
203
|
+
|
204
|
+
def b.oink= v
|
205
|
+
@oink = v
|
206
|
+
end
|
207
|
+
|
208
|
+
b.oink = 123
|
209
|
+
|
210
|
+
b.hash[:oink] = 456
|
211
|
+
|
212
|
+
def b.oink_value
|
213
|
+
@oink
|
214
|
+
end
|
215
|
+
|
216
|
+
assert_equal 123, b.oink_value
|
217
|
+
|
143
218
|
end
|
144
|
-
|
145
|
-
it 'should populate itself with the hash' do
|
146
|
-
blobject.merge data
|
147
219
|
|
148
|
-
|
149
|
-
blobject
|
150
|
-
|
151
|
-
|
220
|
+
describe 'memoized reader' do
|
221
|
+
it 'returns an empty blobject' do
|
222
|
+
|
223
|
+
b.name.first = 'Harry'
|
224
|
+
|
225
|
+
b = Blobject.new
|
226
|
+
|
227
|
+
assert !b.name.nil?
|
228
|
+
|
229
|
+
b.name.first = 'Barry'
|
230
|
+
|
231
|
+
assert_equal b.name.first, 'Barry'
|
232
|
+
end
|
152
233
|
end
|
153
234
|
end
|
154
235
|
|
155
|
-
|
236
|
+
describe 'frozen blobject' do
|
237
|
+
|
238
|
+
before :each do
|
239
|
+
list_element = Blobject.new
|
240
|
+
|
241
|
+
b.name.first = 'barry'
|
242
|
+
b.data.list = [1, 2, 3, list_element]
|
243
|
+
b.data.inner_hash = {:inner => {:one => 1}}
|
244
|
+
|
245
|
+
b.freeze
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'still provides access' do
|
249
|
+
refute_nil b.name.first
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'freezes the internal hash' do
|
253
|
+
assert b.hash.frozen?
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'allows access to existing attributes' do
|
257
|
+
assert_equal b.name.first, 'barry'
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'recursively freezes nested Blobjects' do
|
261
|
+
assert b.frozen?
|
262
|
+
assert b.name.frozen?
|
263
|
+
assert b.data.list[3].frozen?
|
264
|
+
assert b.data.inner_hash.frozen?
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'raises an error when trying to set an attribute' do
|
268
|
+
proc { b.hello = 123 }.must_raise RuntimeError
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'returns nil when trying to get an attribute' do
|
272
|
+
assert b.meow_face.nil?, 'method missing returned something'
|
273
|
+
# check again to test memoized method
|
274
|
+
assert b.meow_face.nil?, 'memoized method returned something'
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
data/spec/env.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
$:.push 'lib', 'spec'
|
5
|
+
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'minitest/spec'
|
8
|
+
|
9
|
+
require 'minitest/reporters'
|
10
|
+
|
11
|
+
MiniTest::Unit.runner = MiniTest::SuiteRunner.new
|
12
|
+
MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
|
data/spec/exec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
["one","two",{"three":{"a":1,"b":2,"c":3}}]
|
@@ -0,0 +1 @@
|
|
1
|
+
{"root":{"nested":[32,64,128,256,512]},"oink":false}
|