bigbertha 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,99 @@
1
+ module Bigbertha
2
+ class Snapshot
3
+
4
+ class Node
5
+ attr_accessor :priority, :name, :parent, :children, :value
6
+
7
+ def initialize( name )
8
+ @name = name
9
+ @priority = nil
10
+ @children = []
11
+ @value = nil
12
+ @parent = nil
13
+ end
14
+
15
+ def add_child( child )
16
+ child.parent = self
17
+ children << child
18
+ end
19
+
20
+ def to_map
21
+ map = Map.new
22
+ order( map )
23
+ map
24
+ end
25
+
26
+ def dump
27
+ puts "#{' '*level}#{name} [#{priority.inspect}] --#{value.inspect}"
28
+ children.sort_by do |c|
29
+ if c.priority and c.priority.is_a? Integer
30
+ "b_#{c.priority}_#{c.name}"
31
+ elsif c.priority
32
+ "z_#{c.priority}_#{c.name}"
33
+ else
34
+ "a_#{c.name}"
35
+ end
36
+ end.each do |c|
37
+ c.dump
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def order( map )
44
+ map[name] = children.empty? ? value : Map.new
45
+ children.sort_by do |c|
46
+ if c.priority and c.priority.is_a? Numeric
47
+ "b_#{'%05.2f' % c.priority}_#{c.name}"
48
+ elsif c.priority
49
+ "z_#{c.priority}_#{c.name}"
50
+ else
51
+ "a_#{c.name}"
52
+ end
53
+ end.each do |c|
54
+ c.send( :order, map[name] )
55
+ end
56
+ end
57
+
58
+ def level
59
+ level = 0
60
+ node = self
61
+ while node.parent do
62
+ level +=1
63
+ node = node.parent
64
+ end
65
+ level
66
+ end
67
+ end
68
+
69
+ def initialize( map )
70
+ @map = map
71
+ @root = Node.new( 'root' )
72
+ build( @map, @root )
73
+ end
74
+
75
+ def to_map
76
+ @root.to_map.root
77
+ end
78
+
79
+ def dump
80
+ @root.dump
81
+ end
82
+
83
+ private
84
+
85
+ def build( map, root )
86
+ map.each_pair do |k,v|
87
+ node = Node.new( k )
88
+ if v.is_a? Hash
89
+ priority = v.delete('.priority')
90
+ node.priority = priority if priority
91
+ build( v, node )
92
+ else
93
+ node.value = v.is_a?(String) ? v.to_val : v
94
+ end
95
+ root.add_child( node )
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,3 @@
1
+ module Bigbertha
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Map do
4
+ describe '#diff' do
5
+ describe 'single vals' do
6
+ it "tracks value changes correctly" do
7
+ prev = Map(:a,1)
8
+ curr = Map(:a,2)
9
+ evts = prev.diff( curr )
10
+ evts.should have(1).item
11
+ evts.first.event_type.should == Bigbertha::Load.evt_value
12
+ evts.first.ref.should == 'a'
13
+ end
14
+
15
+ it "tracks adds correctly" do
16
+ prev = Map.new
17
+ curr = Map(:a,2)
18
+ evts = prev.diff( curr )
19
+ evts.should have(1).item
20
+ evts.first.event_type.should == Bigbertha::Load.evt_child_added
21
+ evts.first.ref.should == 'a'
22
+ end
23
+
24
+ it "tracks deletes correctly" do
25
+ prev = Map(:a,2)
26
+ curr = Map.new
27
+ evts = prev.diff( curr )
28
+ evts.should have(1).item
29
+ evts.first.event_type.should == Bigbertha::Load.evt_child_removed
30
+ evts.first.ref.should == 'a'
31
+ end
32
+ end
33
+
34
+ describe 'multi vals' do
35
+ it 'tracks multi value changes correctly' do
36
+ prev = Map(:a,1)
37
+ curr = Map({a:{a_1:10, a_2:20}})
38
+ evts = prev.diff( curr )
39
+ evts.should have(1).item
40
+ evts.first.event_type.should == Bigbertha::Load.evt_value
41
+ evts.first.ref.should == 'a'
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe String do
4
+ describe '#to_val' do
5
+ it "keep strings unchanged" do
6
+ "fred".to_val.should == "fred"
7
+ end
8
+
9
+ it "converts an integer correctly" do
10
+ "10".to_val.should == 10
11
+ end
12
+
13
+ it "converts an float correctly" do
14
+ "10.5".to_val.should == 10.5
15
+ end
16
+
17
+ it "converts a boolean correctly" do
18
+ "true".to_val.should == true
19
+ "false".to_val.should == false
20
+ end
21
+
22
+ it 'converts null correctly' do
23
+ 'null'.to_val.should == "null"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bigbertha::Ref do
4
+ before :all do
5
+ @ref = Bigbertha::Load.new( ENV['fb_url'] )
6
+ end
7
+
8
+ describe '#child?' do
9
+ it "retrieves complex values correctly" do
10
+ @ref.set( a:{b:{c:1, d:"hello"}} )
11
+ @ref.child?( :a ).should == true
12
+ @ref.child?( 'a/b' ).should == true
13
+ @ref.child?( :z ).should == false
14
+ end
15
+ end
16
+
17
+ describe '#children?' do
18
+ it "retrieves complex values correctly" do
19
+ @ref.set( a:{b:{c:1, d:"hello"}} )
20
+ @ref.child(:a).children?.should == true
21
+ @ref.child('a/b').children?.should == true
22
+ @ref.child( 'a/b/c' ).children?.should == false
23
+ end
24
+ end
25
+
26
+ describe '#num_children' do
27
+ it "retrieves complex values correctly" do
28
+ @ref.set( a:{b:{c:1, d:"hello"}} )
29
+ @ref.child(:a).num_children.should == 1
30
+ @ref.child('a/b').num_children.should == 2
31
+ @ref.child( 'a/b/c' ).num_children.should == 0
32
+ end
33
+ end
34
+
35
+ describe '#val' do
36
+ it "retrieves simple value correctly" do
37
+ @ref.set( a:1 )
38
+ @ref.child( :a ).val.to_i.should == 1
39
+ end
40
+
41
+ it "retrieves complex values correctly" do
42
+ @ref.set( a:{b:{c:1, d:"hello"}} )
43
+ @ref.child( :a ).val.should == {b:{c:1, d:"hello"}}
44
+ end
45
+ end
46
+
47
+ describe '#child' do
48
+ it "creates a child ref correctly" do
49
+ child_ref = @ref.child( 'fred')
50
+ child_ref.name.should == 'fred'
51
+ child_ref.parent.to_s.should == ENV['fb_url']
52
+ end
53
+
54
+ it "creates a deep child ref correctly" do
55
+ child_ref = @ref.child( 'fred/blee/duh')
56
+ child_ref.name.should == 'duh'
57
+ child_ref.parent.to_s.should == ENV['fb_url'] + '/fred/blee'
58
+ end
59
+ end
60
+
61
+ describe '#name' do
62
+ it "identifies / as the root name correctly" do
63
+ @ref.name.should be_nil
64
+ end
65
+
66
+ it "identifies a url name correctly" do
67
+ ref = Bigbertha::Load.new( ENV['fb_url'] + '/fred/blee' )
68
+ ref.name.should == 'blee'
69
+ end
70
+ end
71
+
72
+ describe '#root' do
73
+ it "identifies / as root correctly" do
74
+ @ref.root.should == @ref
75
+ end
76
+
77
+ it "identifies non root url correctly" do
78
+ ref = Bigbertha::Load.new( ENV['fb_url'] + '/fred/blee' )
79
+ ref.root.to_s.should == ENV['fb_url']
80
+ end
81
+ end
82
+
83
+ describe '#root?' do
84
+ it "identifies root correctly" do
85
+ @ref.should be_root
86
+ end
87
+
88
+ it "identifies / as root correctly" do
89
+ ref = Bigbertha::Load.new( ENV['fb_url'] + '/' )
90
+ ref.should be_root
91
+ end
92
+
93
+ it "identifies non root correctly" do
94
+ ref = Bigbertha::Load.new( ENV['fb_url'] + '/fred' )
95
+ ref.should_not be_root
96
+ end
97
+ end
98
+
99
+ describe '#parent' do
100
+ it "identifies parent from root correctly" do
101
+ @ref.parent.should be_nil
102
+ end
103
+
104
+ it "identifies a parent correctly" do
105
+ ref = Bigbertha::Load.new( ENV['fb_url'] + '/fred/blee' )
106
+ ref.parent.to_s.should == ENV['fb_url'] + '/fred'
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,301 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bigbertha::Load do
4
+ before :all do
5
+ @url = ENV['fb_url']
6
+ @fb = Bigbertha::Load.new( @url )
7
+ end
8
+
9
+ describe '#inc' do
10
+ before :all do
11
+ @fb.remove
12
+ @fb.set(
13
+ {
14
+ a: {
15
+ a_1: 1,
16
+ },
17
+ b: {
18
+ b_1: 1.5
19
+ },
20
+ c: {
21
+ c_1: "fred"
22
+ }
23
+ }
24
+ )
25
+ end
26
+
27
+ it "increases an integer value correctly" do
28
+ @fb.child( :a ).inc( :a_1 )
29
+ @fb.child( 'a/a_1' ).read.should == 2
30
+ end
31
+
32
+ it "increases an float value correctly" do
33
+ @fb.child( :b ).inc( :b_1 )
34
+ @fb.child( 'b/b_1' ).read.should == 2.5
35
+ end
36
+
37
+ it "set the value to zero is the data does not exist" do
38
+ @fb.child( :b ).inc( :b_2 )
39
+ @fb.child( 'b/b_2' ).read.should == 0
40
+ end
41
+
42
+ it "fails if the field is non numeric" do
43
+ lambda { @fb.child( :c ).inc( :c_1 ) }.should raise_error( Bigbertha::Load::NonNumericFieldError )
44
+ end
45
+ end
46
+
47
+ describe '#dec' do
48
+ before :all do
49
+ @fb.remove
50
+ @fb.set(
51
+ {
52
+ a: {
53
+ a_1: 2,
54
+ },
55
+ b: {
56
+ b_1: 1.5
57
+ },
58
+ c: {
59
+ c_1: "fred"
60
+ }
61
+ }
62
+ )
63
+ end
64
+
65
+ it "decreases an integer value correctly" do
66
+ @fb.child( :a ).dec( :a_1 )
67
+ @fb.child( 'a/a_1' ).read.should == 1
68
+ end
69
+
70
+ it "decreases an float value correctly" do
71
+ @fb.child( :b ).dec( :b_1 )
72
+ @fb.child( 'b/b_1' ).read.should == 0.5
73
+ end
74
+
75
+ it "set the value to zero is the data does not exist" do
76
+ @fb.child( :b ).dec( :b_2 )
77
+ @fb.child( 'b/b_2' ).read.should == 0
78
+ end
79
+
80
+ it "fails if the field is non numeric" do
81
+ lambda { @fb.child( :c ).dec( :c_1 ) }.should raise_error( Bigbertha::Load::NonNumericFieldError )
82
+ end
83
+ end
84
+
85
+ describe '#set_rules' do
86
+ before :each do
87
+ @auth_fb = Bigbertha::Load.new( @url, ENV['fb_auth_token'] )
88
+ end
89
+
90
+ after :each do
91
+ @auth_fb.set_rules( { '.read' => true, '.write' => true } )
92
+ end
93
+
94
+ it "fetch security rules correctly" do
95
+ @auth_fb.set( tmp: { a: 0, b: 1 } )
96
+ @auth_fb.set_rules(
97
+ { '.read' => true, '.write' => false,
98
+ "tmp" => { '.read' => true, '.write' => false }
99
+ })
100
+ res= @auth_fb.get_rules
101
+ res.rules.tmp['.read'].should be_true
102
+ res.rules.tmp['.write'].should be_false
103
+
104
+ res = @fb.child(:tmp).read
105
+ res.should == { a: 0, b: 1 }
106
+
107
+ lambda { @fb.set( tmp: { d: 0 } ) }.should raise_error Bigbertha::Load::PermissionDeniedError
108
+ end
109
+ end
110
+
111
+ describe "#read" do
112
+ before :all do
113
+ @fb.remove
114
+ @fb.set( {
115
+ test_1: {
116
+ test_1_1: {
117
+ key_1: 'Hello',
118
+ key_2: 'World'
119
+ },
120
+ test_1_2: {
121
+ key_1: 10,
122
+ key_2: [10,20,30],
123
+ key_3: {
124
+ test_1_2_1: {
125
+ key_1: 50
126
+ }
127
+ }
128
+ }
129
+ },
130
+ test_2: 10,
131
+ test_3: :Blee,
132
+ test_4: %w[hello world],
133
+ test_5: [{a:1,b:2}, {c:3,d:4}]
134
+ }
135
+ )
136
+ end
137
+
138
+ it "reads a simple number correctly" do
139
+ @fb.child( :test_2 ).read.to_i.should == 10
140
+ end
141
+
142
+ it "reads a string correctly" do
143
+ @fb.child( :test_3 ).read.should == "Blee"
144
+ end
145
+
146
+ it "reads a simple array correctly" do
147
+ @fb.child( :test_4 ).read.should == %w[hello world]
148
+ end
149
+
150
+ it "reads an array of hash correctly" do
151
+ @fb.child( 'test_5/0' ).read.a.should == 1
152
+ end
153
+
154
+ it "reads a deeply nested hash correctly" do
155
+ @fb.child( 'test_1/test_1_2/key_3').read.test_1_2_1.key_1.should == 50
156
+ end
157
+ end
158
+
159
+ describe '#push' do
160
+ before :each do
161
+ @fb.remove
162
+ end
163
+
164
+ it "makes up an empty ref if no data" do
165
+ resp = @fb.push()
166
+ resp.name.should_not be_nil
167
+ end
168
+
169
+ it "builds a list with values" do
170
+ resp = @fb.push( {a:1,b:2} )
171
+ resp.name.should_not be_nil
172
+ @fb.child( resp.name ).read.a.should == 1
173
+ @fb.child( resp.name ).read.b.should == 2
174
+ end
175
+ end
176
+
177
+ describe 'priority' do
178
+ before :each do
179
+ @fb.remove
180
+ end
181
+
182
+ it "sets priority with complex data correctly" do
183
+ @fb.set( c:{d:1} )
184
+ ref = @fb.child( :c )
185
+ ref.set_priority( 2.0 )
186
+ ref.get_priority.to_i.should == 2.0
187
+ end
188
+
189
+ it "unsets priority correctly" do
190
+ @fb.set( c:{d:1} )
191
+ ref = @fb.child( :c )
192
+ ref.set_priority( 2.0 )
193
+ ref.get_priority.to_i.should == 2.0
194
+ ref.set_priority( nil )
195
+ ref.get_priority.should == nil
196
+ end
197
+
198
+ it "sets priority for lists correctly" do
199
+ a_ref = @fb.push( {b:1, a:2} )
200
+ b_ref = @fb.push( {e:1, d:2} )
201
+ a_ref.set_priority( 20 )
202
+ b_ref.set_priority( 10 )
203
+ a_ref.get_priority.to_i.should == 20
204
+ b_ref.get_priority.to_i.should == 10
205
+ res = a_ref.parent.read
206
+ keys = [b_ref.name, a_ref.name]
207
+ index = 0
208
+ res.each_pair do |k,v|
209
+ k.should == keys[index]
210
+ index += 1
211
+ end
212
+ end
213
+
214
+ it "sets priority for lists correctly" do
215
+ a_ref = @fb.push
216
+ a1_ref = a_ref.push( a:1 )
217
+ a2_ref = a_ref.push( b:1 )
218
+ b_ref = @fb.push
219
+ b1_ref = b_ref.push( c:1 )
220
+ b2_ref = b_ref.push( d:1 )
221
+
222
+ a_ref.set_priority( 20 )
223
+ a1_ref.set_priority( 50 )
224
+ a2_ref.set_priority( 30 )
225
+ b_ref.set_priority( 10 )
226
+ b1_ref.set_priority( 50 )
227
+ b2_ref.set_priority( 30 )
228
+
229
+ a1_ref.get_priority.to_i.should == 50
230
+ a2_ref.get_priority.to_i.should == 30
231
+ b1_ref.get_priority.to_i.should == 50
232
+ b2_ref.get_priority.to_i.should == 30
233
+
234
+ res = a_ref.parent.read
235
+ keys = [b_ref.name, a_ref.name]
236
+ index = 0
237
+ res.each_pair do |k,v|
238
+ k.should == keys[index]
239
+ index += 1
240
+ end
241
+ end
242
+
243
+ end
244
+
245
+ it "reads a simple number correctly" do
246
+ @fb.update( {test_1: 20 } )
247
+ @fb.child( :test_1 ).read.to_i.should == 20
248
+ end
249
+
250
+ describe '#remove' do
251
+ before :each do
252
+ @fb.remove
253
+ end
254
+
255
+ it "removes data correctly" do
256
+ @fb.set( {fred: 10} )
257
+ @fb.child( :fred ).remove
258
+ lambda { @fb.child( :fred ).read }.should raise_error( /No data/ )
259
+ end
260
+ end
261
+
262
+ describe '#update' do
263
+ before :all do
264
+ @fb.remove
265
+ @fb.set( a:{b:1,c:2} )
266
+ @a_ref = @fb.child( :a )
267
+ end
268
+
269
+ describe 'oneshot' do
270
+ it "updates an integer correctly" do
271
+ @a_ref.update( c:5 )
272
+ @a_ref.child( :c ).read.should == 5
273
+ end
274
+
275
+ it "updates a float correctly" do
276
+ @a_ref.update( c:5.0 )
277
+ @a_ref.child( :c ).read.should == 5.0
278
+ end
279
+
280
+ it "updates a boolean correctly" do
281
+ @a_ref.update( c:true )
282
+ @a_ref.child( :c ).read.should be_true
283
+ end
284
+
285
+ it "updates a boolean correctly" do
286
+ @a_ref.update( c:true )
287
+ @a_ref.child( :c ).read.should be_true
288
+ end
289
+
290
+ it "updates an object correctly" do
291
+ @a_ref.update( c:{fred:'Hello', blee:'World'} )
292
+ @a_ref.child( :c ).read.should == {fred:'Hello', blee:'World'}
293
+ end
294
+
295
+ it "updates an array correctly" do
296
+ @a_ref.update( c:%w[Hello World] )
297
+ @a_ref.child( :c ).read.should == %w[Hello World]
298
+ end
299
+ end
300
+ end
301
+ end