bigbertha 0.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.
- 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
|