bigbertha 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +42 -0
- data/README.md +322 -0
- data/Rakefile +21 -0
- data/bigbertha.gemspec +28 -0
- data/examples/a.rb +10 -0
- data/examples/b.rb +5 -0
- data/examples/c.rb +6 -0
- data/examples/d.rb +15 -0
- data/examples/e.rb +21 -0
- data/examples/f.rb +20 -0
- data/examples/g.rb +20 -0
- data/examples/h.rb +22 -0
- data/examples/i.rb +26 -0
- data/examples/j.rb +10 -0
- data/lib/bigbertha.rb +17 -0
- data/lib/bigbertha/action.rb +141 -0
- data/lib/bigbertha/core.rb +1 -0
- data/lib/bigbertha/core_ext/map.rb +23 -0
- data/lib/bigbertha/core_ext/string.rb +15 -0
- data/lib/bigbertha/faults.rb +9 -0
- data/lib/bigbertha/load.rb +22 -0
- data/lib/bigbertha/ref.rb +64 -0
- data/lib/bigbertha/snapshot.rb +99 -0
- data/lib/bigbertha/version.rb +3 -0
- data/spec/bigbertha/.firebase_spec.rb.swp +0 -0
- data/spec/bigbertha/core_ext/map_spec.rb +45 -0
- data/spec/bigbertha/core_ext/string_spec.rb +26 -0
- data/spec/bigbertha/ref_spec.rb +109 -0
- data/spec/bigbertha/root_spec.rb +301 -0
- data/spec/bigbertha/snapshot_spec.rb +174 -0
- data/spec/spec_helper.rb +10 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Nzk1YTdiNTBlYTE1NDlmMzVlZWI4MTA0MDQzODU3ZDRlYzQ1NzAyZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZGVlNjFkMDQxZGZjOGEwYmM2OTQxMjBhZjEwYzRhMmVjOWExZGFhNQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MDU1YzFmYzJiNjNkNTk0MmFlMjU2ZTFjMjQyYTMzZTQ3OTEwNDliMTZiZTI4
|
10
|
+
N2NkZDlhMzEwNmRlZmUwZjk4ZGMzZGFmNGVmOGNjMWZkNzMxMTIxNTZkNjIw
|
11
|
+
ZTI5NjM2ZDQxMDVhNWIwYWZiYmQ3MDM3NTUyYzc4NDE3YzE3ZjA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWU5YTQyNGI2YTAzZDI3NWFkMjM5NjQwZGU3NmM3MTBkYzAzMDA1YjNhODM0
|
14
|
+
ZjAzMjZiNzRmMzNmZjBmOGU5MWZkYTdmYmFiNmMwOTU0M2MzOTg3MDI5YzE0
|
15
|
+
ZGQ1ODM3NTE3MjE1NTkzOTUzMzNjMDM3N2UxYmE3ZDZkNThjYjE=
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
ZenTest (4.9.0)
|
5
|
+
autotest (4.4.6)
|
6
|
+
ZenTest (>= 4.4.1)
|
7
|
+
autotest-growl (0.2.16)
|
8
|
+
diff-lcs (1.2.1)
|
9
|
+
ethon (0.5.10)
|
10
|
+
ffi (~> 1.3.0)
|
11
|
+
mime-types (~> 1.18)
|
12
|
+
ffi (1.3.1)
|
13
|
+
map (6.3.0)
|
14
|
+
mime-types (1.21)
|
15
|
+
multi_json (1.7.2)
|
16
|
+
rspec (2.13.0)
|
17
|
+
rspec-core (~> 2.13.0)
|
18
|
+
rspec-expectations (~> 2.13.0)
|
19
|
+
rspec-mocks (~> 2.13.0)
|
20
|
+
rspec-core (2.13.1)
|
21
|
+
rspec-expectations (2.13.0)
|
22
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
23
|
+
rspec-mocks (2.13.0)
|
24
|
+
simplecov (0.7.1)
|
25
|
+
multi_json (~> 1.0)
|
26
|
+
simplecov-html (~> 0.7.1)
|
27
|
+
simplecov-html (0.7.1)
|
28
|
+
typhoeus (0.6.2)
|
29
|
+
ethon (~> 0.5.10)
|
30
|
+
values (1.5.0)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
autotest
|
37
|
+
autotest-growl
|
38
|
+
map
|
39
|
+
rspec
|
40
|
+
simplecov
|
41
|
+
typhoeus
|
42
|
+
values
|
data/README.md
ADDED
@@ -0,0 +1,322 @@
|
|
1
|
+
# BigBertha - Ruby firepower for your Firebase battery
|
2
|
+
|
3
|
+
Firebase is a real-time backend that allows one to store key-value pairs in a hierarchical fashion, without
|
4
|
+
having to manage additional servers. Firebase offers api's for a variety of client libs such as javascript,
|
5
|
+
REST, IOS and now Ruby ;-). A cool feature of firebase is that it allows disparate clients to broadcast updates and
|
6
|
+
sync up across the wire. Checkout http://firebase.com for the firehose...
|
7
|
+
|
8
|
+
|
9
|
+
## Requirements
|
10
|
+
|
11
|
+
- Ruby >= 1.9
|
12
|
+
- Map
|
13
|
+
- Typhoeus
|
14
|
+
|
15
|
+
## Getting Started
|
16
|
+
|
17
|
+
$ gem install bigbertha
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Setup your Firebase
|
22
|
+
|
23
|
+
Sign up for a firebase account and create a new firebase of your liking.
|
24
|
+
In the following code samples, we will use the following as our base url:
|
25
|
+
|
26
|
+
+ https://zerodarkthirty.firebaseio.com
|
27
|
+
|
28
|
+
Then you can specify an entry point into the data using the following call:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
ref = Bigbertha::Load.new( 'https://zerodarkthirty.firebaseio.com' )
|
32
|
+
```
|
33
|
+
|
34
|
+
NOTE: You don't have to start a the root, but usually a good idea since this api
|
35
|
+
offers ways to traverse the hierarchy up or down. But more on this later...
|
36
|
+
|
37
|
+
|
38
|
+
### Populating firebase
|
39
|
+
|
40
|
+
Firebase supports the following data types:
|
41
|
+
|
42
|
+
+ String
|
43
|
+
+ Number
|
44
|
+
+ Boolean
|
45
|
+
+ Array
|
46
|
+
+ Hash
|
47
|
+
|
48
|
+
#### Adding primitive types
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
data = {
|
52
|
+
a: 0,
|
53
|
+
b: %s(Hello World),
|
54
|
+
c: 10.5
|
55
|
+
}
|
56
|
+
ref.set( data )
|
57
|
+
```
|
58
|
+
|
59
|
+
Yields:
|
60
|
+
|
61
|
+
+ a:0
|
62
|
+
+ b:"Hello World"
|
63
|
+
+ c:10.5
|
64
|
+
|
65
|
+
NOTE: Set is a destructive operation and will replace the previous content for the reference it is
|
66
|
+
called from.
|
67
|
+
|
68
|
+
Thus
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
data = {
|
72
|
+
a: 0
|
73
|
+
}
|
74
|
+
ref.set( data )
|
75
|
+
```
|
76
|
+
|
77
|
+
Yields
|
78
|
+
+ a:0
|
79
|
+
|
80
|
+
Hence replacing the previously assigned content.
|
81
|
+
|
82
|
+
|
83
|
+
#### Adding arrays
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
ref.set( %w(Hello World) )
|
87
|
+
```
|
88
|
+
|
89
|
+
Yields:
|
90
|
+
|
91
|
+
+ 0:"Hello"
|
92
|
+
+ 1:"World"
|
93
|
+
|
94
|
+
|
95
|
+
#### Adding arrays (ordered data)
|
96
|
+
|
97
|
+
The preferred method to construct lists in your firebase is to use the push operation, which
|
98
|
+
will automatically provide ordering to your list.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
ref.push( "BumbleBee" )
|
102
|
+
ref.push( "Tuna" )
|
103
|
+
```
|
104
|
+
|
105
|
+
Yields:
|
106
|
+
|
107
|
+
+ -IrMr3Yp1mozVNzDePKy: "BumbleBee"
|
108
|
+
+ -IrMr3cM6XjTpNebsYRh: "Tuna"
|
109
|
+
|
110
|
+
NOTE: The list indexes will be autogenerated by firebase to ensure correct ordering on retrieval.
|
111
|
+
|
112
|
+
|
113
|
+
#### Adding hashes
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
data = {
|
117
|
+
a: {
|
118
|
+
a_1: %s(Hello World),
|
119
|
+
a_2: 10.5
|
120
|
+
},
|
121
|
+
b: {
|
122
|
+
b_1: 10,
|
123
|
+
b_2: true
|
124
|
+
}
|
125
|
+
}
|
126
|
+
ref.set( data )
|
127
|
+
```
|
128
|
+
|
129
|
+
Yields:
|
130
|
+
|
131
|
+
+ a:
|
132
|
+
+ a_1:"Hello World"
|
133
|
+
+ a_2_:10.5
|
134
|
+
+ b:
|
135
|
+
+ b_1:10
|
136
|
+
+ b_2:true
|
137
|
+
|
138
|
+
|
139
|
+
### Reading data
|
140
|
+
|
141
|
+
Fetching data in the hierarchy is done via the read operation.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
# Setup...
|
145
|
+
data = {
|
146
|
+
a: {
|
147
|
+
a_1: %s(Hello World),
|
148
|
+
a_2: 10.5
|
149
|
+
},
|
150
|
+
b: {
|
151
|
+
b_1: 10,
|
152
|
+
b_2: true
|
153
|
+
}
|
154
|
+
}
|
155
|
+
ref.set( data )
|
156
|
+
```
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
ref.child( 'a/a_2' ).read # => 10.5
|
160
|
+
a_val = ref.child( :a ).read
|
161
|
+
a_val.a_1 # => 'Hello World'
|
162
|
+
a_val[:a_1] # => 'Hello World' or use hash indexing...
|
163
|
+
a_val.a_2 # => 10.5
|
164
|
+
```
|
165
|
+
|
166
|
+
### Updating data
|
167
|
+
|
168
|
+
You can use the #update on a reference to modify nodes in the hierarchy
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
# Setup...
|
172
|
+
data = {
|
173
|
+
a: {
|
174
|
+
a_1: %s(Hello World),
|
175
|
+
a_2: {
|
176
|
+
a_2_1: 10.5,
|
177
|
+
a_2_2: "Word!"
|
178
|
+
}
|
179
|
+
},
|
180
|
+
b: {
|
181
|
+
b_1: 10,
|
182
|
+
b_2: true
|
183
|
+
}
|
184
|
+
}
|
185
|
+
ref.set( data )
|
186
|
+
```
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
ref.child( :a ).update( a_1:"BumbleBee Tuna" )
|
190
|
+
ref.child( 'a/a_2' ).update( a_2_2:"You bet!" )
|
191
|
+
ref.child( 'a' ).child( 'a_3' ).update( a_3_1:"You better!" )
|
192
|
+
```
|
193
|
+
|
194
|
+
Yields:
|
195
|
+
|
196
|
+
+ a
|
197
|
+
+ a_1:"BumbleBee Tuna"
|
198
|
+
+ a_2
|
199
|
+
+ a_2_1: 10.5
|
200
|
+
+ a_2_2: "You bet!"
|
201
|
+
+ a_3
|
202
|
+
+ a_3_1: "You better!"
|
203
|
+
|
204
|
+
Note: the last call inserts a branch new node in the hierarchy. We could have use set here as well to
|
205
|
+
perform the insert.
|
206
|
+
|
207
|
+
You can leverage #inc/#dec to increment/decrement counter like data.
|
208
|
+
|
209
|
+
IMPORTANT! Sadly Firebase currently does not offer transactions using their REST api, hence there is
|
210
|
+
no guarantees about the atomicity of read/write operations ;-(
|
211
|
+
|
212
|
+
### Deleting data
|
213
|
+
|
214
|
+
Use the #remove operation to delete nodes at any level in the hierarchy.
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
# Setup...
|
218
|
+
data = {
|
219
|
+
a: {
|
220
|
+
a_1: %s(Hello World),
|
221
|
+
a_2: {
|
222
|
+
a_2_1: 10.5,
|
223
|
+
a_2_2: "Word!"
|
224
|
+
}
|
225
|
+
},
|
226
|
+
b: {
|
227
|
+
b_1: 10,
|
228
|
+
b_2: true
|
229
|
+
}
|
230
|
+
}
|
231
|
+
ref.set( data )
|
232
|
+
ref.child( 'a/a_2/a_2_2' ).remove
|
233
|
+
ref.child( :b ).remove
|
234
|
+
```
|
235
|
+
|
236
|
+
NOTE: Calling remove on the root ref will delete the entire hierarchy.
|
237
|
+
|
238
|
+
### Traversing the data
|
239
|
+
|
240
|
+
You can traverse the hierarchy using the #child or #parent. These calls can be chained.
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
data = {
|
244
|
+
a: {
|
245
|
+
a_1: %s(Hello World),
|
246
|
+
a_2: {
|
247
|
+
a_2_1: 10.5,
|
248
|
+
a_2_2: "Word!"
|
249
|
+
}
|
250
|
+
},
|
251
|
+
b: {
|
252
|
+
b_1: 10,
|
253
|
+
b_2: true
|
254
|
+
}
|
255
|
+
}
|
256
|
+
ref.set( data )
|
257
|
+
```
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
a_2_2_ref = ref.child( 'a/a_2/a_2_2' )
|
261
|
+
a_2_2_ref = ref.child( :a ).child( :a_2 ).child( :a_2_2 ) # or...
|
262
|
+
a_2_2_ref.name #=> 'a_2_2'
|
263
|
+
|
264
|
+
a_2_ref = a_2_2_ref.parent
|
265
|
+
a_2_ref.name # => 'a_2'
|
266
|
+
|
267
|
+
a_ref = a_2_2_ref.parent.parent
|
268
|
+
a_ref.name # => 'a'
|
269
|
+
```
|
270
|
+
|
271
|
+
### Priorities
|
272
|
+
|
273
|
+
Firebase provides for setting priorities on ordered list in order to affect the retrieval. By default priority is null.
|
274
|
+
Setting priority affects the retrieval as follows (See firebase web site for details!):
|
275
|
+
|
276
|
+
+ Children with no priority are retrieved first ordered lex asc by name
|
277
|
+
+ Children with number priority are next, ordered lex asc priority, name
|
278
|
+
+ Children with a non numeric priority come last, ordered lex asc priority, name
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
a_ref = ref.push( {a:1, b:2} )
|
282
|
+
b_ref = ref.push( {c:1, d:2} )
|
283
|
+
a_ref.set_priority( 20 )
|
284
|
+
b_ref.set_priority( 10 )
|
285
|
+
a_ref.parent.read #=> {-IrNhTASqxqEpNMw8NGq: {c: 1, d: 2}, -IrNhT2vsoQ1WlgSG6op: {a: 1, b: 2} }
|
286
|
+
```
|
287
|
+
|
288
|
+
### Auth and rules
|
289
|
+
|
290
|
+
You can secure you firebase store using a secret token and grant access for permissions on the store using rules.
|
291
|
+
Please refer to the firebase docs for details.
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
ref = Bigbertha::Load.new( 'https://bozo.firebaseio.com', my_secret_token )
|
295
|
+
ref.set( tmp: { a: 0, b: 1 } )
|
296
|
+
ref.set_rules(
|
297
|
+
{ '.read' => true, '.write' => false,
|
298
|
+
"tmp" => { '.read' => true, '.write' => false }
|
299
|
+
}
|
300
|
+
)
|
301
|
+
res = ref.child(:tmp).read # => { a: 0, b: 1 }
|
302
|
+
ref.set( tmp: {d:0} ) } # => Bigbertha::Action::PermissionDeniedError
|
303
|
+
```
|
304
|
+
|
305
|
+
## Contact
|
306
|
+
|
307
|
+
Fernand Galiana
|
308
|
+
|
309
|
+
- http://github.com/derailed
|
310
|
+
- http://twitter.com/kitesurfer
|
311
|
+
- <fernand.galiana@gmail.com>
|
312
|
+
|
313
|
+
## License
|
314
|
+
|
315
|
+
Bigbertha is released under the [MIT](http://opensource.org/licenses/MIT) license.
|
316
|
+
|
317
|
+
|
318
|
+
## History
|
319
|
+
+ 0.0.1:
|
320
|
+
+ Initial drop
|
321
|
+
+ 0.0.2:
|
322
|
+
+ Clean up and doc updates
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
Bundler.require
|
4
|
+
|
5
|
+
Bundler::GemHelper.install_tasks
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
8
|
+
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
11
|
+
t.verbose = false
|
12
|
+
t.ruby_opts = "-I./spec"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Cleanup build artifacts'
|
16
|
+
task :clean do
|
17
|
+
cov = File.expand_path( File.join( %w(.. coverage) ), __FILE__ )
|
18
|
+
FileUtils.rm_r( cov ) if File.exists?( cov )
|
19
|
+
end
|
20
|
+
|
21
|
+
task default: :spec
|
data/bigbertha.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bigbertha/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bigbertha"
|
7
|
+
s.version = Bigbertha::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
|
10
|
+
s.authors = [
|
11
|
+
"Fernand Galiana"
|
12
|
+
]
|
13
|
+
|
14
|
+
s.email = ["fernand.galiana@gmail.com"]
|
15
|
+
s.homepage = "http://derailed.github.io/bigbertha"
|
16
|
+
s.summary = %q{Ruby implementation for your Firebase battery}
|
17
|
+
s.description = "Firebase is a real time backend to allow clients to share" +
|
18
|
+
"data on the web. This gem provides a ruby API implementation."
|
19
|
+
s.rubyforge_project = "bigbertha"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
|
26
|
+
s.add_dependency 'map' , '~> 6.3.0'
|
27
|
+
s.add_dependency 'typhoeus', '~> 0.6.2'
|
28
|
+
end
|