rmx-firebase 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e1d4fa77899f71b7fcf8ab6349245bb008b65f4d
4
+ data.tar.gz: 2076ec5160ae4c60a402b94db77714b9796ff4cc
5
+ SHA512:
6
+ metadata.gz: 187ab0df77bf3026ff184ddf87c42b77265bc8f1592ff2f214d5412386800db64310f0a5c5a05875213e4456911b08bf0b23bde02d971024fecc354ae95ef4d0
7
+ data.tar.gz: ff8bfed7d390c6d6196d291ea86ad370f123ffe7b1b6ec79e6162d02b632bcd8d2fb5b2d67eb549e8d3e0f4bdd45d85fff1e65e6d091b4c198a7018277c09454
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ build
19
+ build*
20
+ *.bridgesupport
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test, :development do
4
+ gem 'rake'
5
+ end
6
+
7
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Joe Noon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ RMXFirebase
2
+ -----------
3
+
4
+ Work in progress firebase wrapper:
5
+
6
+ Goals:
7
+
8
+ 1. Shorter methods
9
+ 2. Simplify common access patterns
10
+ 3. Provide an API that makes it hard to leak
11
+ 4. Identity map of data snapshots in-use, for faster access
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require "bundler/gem_tasks"
2
+ if ENV['rubymotion']
3
+ $:.unshift('/Library/RubyMotion/lib')
4
+ if ENV.fetch('platform', 'ios') == 'ios'
5
+ require 'motion/project/template/ios'
6
+ elsif ENV['platform'] == 'osx'
7
+ require 'motion/project/template/osx'
8
+ else
9
+ raise "Unsupported platform #{ENV['platform']}"
10
+ end
11
+ require 'bundler'
12
+ Bundler.require
13
+
14
+ Motion::Project::App.setup do |app|
15
+ # Use `rake config' to see complete project settings.
16
+ app.name = 'rmx-firebase'
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ class AppDelegate
2
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
3
+ true
4
+ end
5
+ end
@@ -0,0 +1,178 @@
1
+ class FQuery
2
+
3
+ EVENT_TYPES_MAP = {
4
+ :child_added => FEventTypeChildAdded,
5
+ :added => FEventTypeChildAdded,
6
+ :child_moved => FEventTypeChildMoved,
7
+ :moved => FEventTypeChildMoved,
8
+ :child_changed => FEventTypeChildChanged,
9
+ :changed => FEventTypeChildChanged,
10
+ :child_removed => FEventTypeChildRemoved,
11
+ :removed => FEventTypeChildRemoved,
12
+ :value => FEventTypeValue
13
+ }
14
+
15
+ def rmx_object_desc
16
+ "#{super}:#{description}"
17
+ end
18
+
19
+ def limited(limit)
20
+ queryLimitedToNumberOfChildren(limit)
21
+ end
22
+
23
+ def starting_at(priority)
24
+ queryStartingAtPriority(priority)
25
+ end
26
+
27
+ def ending_at(priority)
28
+ queryEndingAtPriority(priority)
29
+ end
30
+
31
+ def on(_event_type, options={}, &and_then)
32
+ and_then ||= options[:completion]
33
+ raise "event handler is required" unless and_then
34
+ raise "event handler must accept one or two arguments" unless and_then.arity == 1 || and_then.arity == 2
35
+ completion = RMX.safe_block(and_then)
36
+
37
+ event_type = EVENT_TYPES_MAP[_event_type]
38
+ raise "event handler is unknown: #{_event_type.inspect}" unless event_type
39
+
40
+ _disconnect_block = options[:disconnect]
41
+ raise ":disconnect handler must not accept any arguments" if _disconnect_block && _disconnect_block.arity != 1
42
+ disconnect_block = nil
43
+ if _disconnect_block
44
+ disconnect_inner_block = RMX.safe_block(_disconnect_block)
45
+ disconnect_block = lambda do |err|
46
+ disconnect_inner_block.call(err)
47
+ end.weak!
48
+ end
49
+ handler = nil
50
+ if and_then.arity == 1
51
+ inner_block = RMX.safe_block(lambda do |snap|
52
+ datasnap = RMXFirebaseDataSnapshot.new(snap)
53
+ completion.call(datasnap)
54
+ end)
55
+ wrapped_block = lambda do |snap|
56
+ inner_block.call(snap)
57
+ end.weak!
58
+ if disconnect_block
59
+ if options[:once]
60
+ RMXFirebase::INTERNAL_QUEUE.sync do
61
+ handler = observeSingleEventOfType(event_type, withBlock:wrapped_block, withCancelBlock:disconnect_block)
62
+ end
63
+ else
64
+ RMXFirebase::INTERNAL_QUEUE.sync do
65
+ handler = observeEventType(event_type, withBlock:wrapped_block, withCancelBlock:disconnect_block)
66
+ end
67
+ end
68
+ else
69
+ if options[:once]
70
+ RMXFirebase::INTERNAL_QUEUE.sync do
71
+ handler = observeSingleEventOfType(event_type, withBlock:wrapped_block)
72
+ end
73
+ else
74
+ RMXFirebase::INTERNAL_QUEUE.sync do
75
+ handler = observeEventType(event_type, withBlock:wrapped_block)
76
+ end
77
+ end
78
+ end
79
+ else
80
+ inner_block = RMX.safe_block(lambda do |snap, prev|
81
+ datasnap = RMXFirebaseDataSnapshot.new(snap)
82
+ completion.call(datasnap, prev)
83
+ end)
84
+ wrapped_block = lambda do |snap, prev|
85
+ inner_block.call(snap, prev)
86
+ end.weak!
87
+ if disconnect_block
88
+ if options[:once]
89
+ RMXFirebase::INTERNAL_QUEUE.sync do
90
+ handler = observeSingleEventOfType(event_type, andPreviousSiblingNameWithBlock:wrapped_block, withCancelBlock:disconnect_block)
91
+ end
92
+ else
93
+ RMXFirebase::INTERNAL_QUEUE.sync do
94
+ handler = observeEventType(event_type, andPreviousSiblingNameWithBlock:wrapped_block, withCancelBlock:disconnect_block)
95
+ end
96
+ end
97
+ else
98
+ if options[:once]
99
+ RMXFirebase::INTERNAL_QUEUE.sync do
100
+ handler = observeSingleEventOfType(event_type, andPreviousSiblingNameWithBlock:wrapped_block)
101
+ end
102
+ else
103
+ RMXFirebase::INTERNAL_QUEUE.sync do
104
+ handler = observeEventType(event_type, andPreviousSiblingNameWithBlock:wrapped_block)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ unless options[:once]
110
+ @_outstanding_handlers ||= OutstandingHandlers.new(self)
111
+ @_outstanding_handlers << handler
112
+ end
113
+ handler
114
+ end
115
+
116
+ class OutstandingHandlers
117
+
118
+ RMX(self).weak_attr_accessor :scope
119
+
120
+ def initialize(_scope)
121
+ self.scope = _scope
122
+ @handlers = []
123
+ end
124
+
125
+ def <<(handler)
126
+ @handlers << handler
127
+ end
128
+
129
+ def handlers
130
+ @handlers
131
+ end
132
+
133
+ def off(handle=nil)
134
+ if s = scope
135
+ if _handle = @handlers.delete(handle)
136
+ # p s.rmx_object_desc, "remove handle", _handle
137
+ RMXFirebase::INTERNAL_QUEUE.sync do
138
+ s.removeObserverWithHandle(_handle)
139
+ end
140
+ else
141
+ _handlers = @handlers.dup
142
+ while _handlers.size > 0
143
+ _handle = _handlers.shift
144
+ off(_handle)
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ def dealloc
151
+ off
152
+ super
153
+ end
154
+ end
155
+
156
+ def once(event_type, options={}, &and_then)
157
+ on(event_type, options.merge(:once => true), &and_then)
158
+ end
159
+
160
+ def _off(handle)
161
+ if @_outstanding_handlers
162
+ @_outstanding_handlers.off(handle)
163
+ end
164
+ self
165
+ end
166
+
167
+ def off(handle)
168
+ RMXFirebase::QUEUE.barrier_async do
169
+ _off(handle)
170
+ end
171
+ self
172
+ end
173
+
174
+ def description
175
+ AFHTTPRequestSerializer.serializer.requestWithMethod("GET", URLString: "https://#{repo.repoInfo.host}#{path.toString}", parameters:queryParams.queryObject).URL.absoluteString
176
+ end
177
+
178
+ end
@@ -0,0 +1,93 @@
1
+ class Firebase
2
+
3
+ DEBUG_SETVALUE = RMX::Env['rmx_firebase_debug_setvalue'] == '1'
4
+
5
+ def rmx_object_desc
6
+ "#{super}:#{description}"
7
+ end
8
+
9
+ def [](*names)
10
+ if names.length == 0
11
+ childByAutoId
12
+ else
13
+ childByAppendingPath(names.join('/'))
14
+ end
15
+ end
16
+
17
+ def limited(limit)
18
+ queryLimitedToNumberOfChildren(limit)
19
+ end
20
+
21
+ def starting_at(priority)
22
+ queryStartingAtPriority(priority)
23
+ end
24
+
25
+ def ending_at(priority)
26
+ queryEndingAtPriority(priority)
27
+ end
28
+
29
+ def rmx_arrayToHash(array)
30
+ hash = {}
31
+ array.each_with_index do |item, i|
32
+ hash[i.to_s] = item
33
+ end
34
+ hash
35
+ end
36
+
37
+ def rmx_castValue(value, key=nil)
38
+ if value == true
39
+ elsif value == false
40
+ elsif value.is_a?(NSString)
41
+ elsif value.is_a?(NSNumber)
42
+ elsif value.nil?
43
+ p "FIREBASE_BAD_TYPE FIXED NIL: #{File.join(*[ description, key ].compact.map(&:to_s))}", "!"
44
+ value = {}
45
+ elsif value.is_a?(Array)
46
+ value = rmx_arrayToHash(value)
47
+ p "FIREBASE_BAD_TYPE FIXED ARRAY: #{File.join(*[ description, key ].compact.map(&:to_s))}: #{value.inspect} (type: #{value.className.to_s})", "!"
48
+ elsif value.is_a?(NSDictionary)
49
+ _value = value.dup
50
+ new_value = {}
51
+ _value.keys.each do |k|
52
+ new_value[k.to_s] = rmx_castValue(_value[k], k)
53
+ end
54
+ value = new_value
55
+ else
56
+ p "FIREBASE_BAD_TYPE FATAL: #{File.join(*[ description, key ].compact.map(&:to_s))}: #{value.inspect} (type: #{value.className.to_s})", "!"
57
+ end
58
+ # always return the value, corrected or not
59
+ value
60
+ end
61
+
62
+ def rmx_setValue(value, andPriority:priority)
63
+ # value = rmx_castValue(value)
64
+ setValue(value, andPriority:priority)
65
+ end
66
+ def rmx_setValue(value)
67
+ # value = rmx_castValue(value)
68
+ setValue(value)
69
+ end
70
+ def rmx_onDisconnectSetValue(value)
71
+ value = rmx_castValue(value)
72
+ onDisconnectSetValue(value)
73
+ end
74
+
75
+ alias_method 'orig_setValue', 'setValue'
76
+ alias_method 'orig_setValueAndPriority', 'setValue:andPriority'
77
+
78
+ def setValue(value, andPriority:priority)
79
+ if DEBUG_SETVALUE
80
+ p description, "setValue:andPriority", value, priority
81
+ end
82
+ value = rmx_castValue(value)
83
+ orig_setValueAndPriority(value, priority)
84
+ end
85
+ def setValue(value)
86
+ if DEBUG_SETVALUE
87
+ p description, "setValue:", value
88
+ end
89
+ value = rmx_castValue(value)
90
+ orig_setValue(value)
91
+ end
92
+
93
+ end
@@ -0,0 +1,31 @@
1
+ module RMXFirebase
2
+
3
+ QUEUE = Dispatch::Queue.new("RMXFirebase")
4
+ INTERNAL_QUEUE = Dispatch::Queue.new("RMXFirebase.internal")
5
+
6
+ DEBUG_IDENTITY_MAP = RMX::Env['rmx_firebase_debug_identity_map'] == '1'
7
+ DEBUG_MODEL_DEALLOC = RMX::Env['rmx_firebase_debug_model_dealloc'] == '1'
8
+
9
+ def self.queue_for(queueish)
10
+ if queueish == :main || queueish.nil?
11
+ Dispatch::Queue.main
12
+ elsif queueish == :async
13
+ QUEUE
14
+ else
15
+ queueish
16
+ end
17
+ end
18
+
19
+ def self.block_on_queue(queue, *args, &block)
20
+ queue = queue_for(queue)
21
+ if queue == Dispatch::Queue.main && NSThread.currentThread.isMainThread
22
+ block.call(*args)
23
+ else
24
+ queue.barrier_async do
25
+ block.call(*args)
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ Firebase.setDispatchQueue(RMXFirebase::INTERNAL_QUEUE.dispatch_object)
@@ -0,0 +1,102 @@
1
+ class RMXFirebaseBatch
2
+
3
+ include RMXCommonMethods
4
+
5
+ def self.new(*models)
6
+ _models = models.dup
7
+ _models = _models.flatten.compact
8
+ x = super()
9
+ RMXFirebase::QUEUE.barrier_async do
10
+ x.setup_models(_models)
11
+ end
12
+ x
13
+ end
14
+
15
+ def initialize
16
+ @models = []
17
+ @ready_models = []
18
+ @complete_blocks = {}
19
+ end
20
+
21
+ def setup_models(the_models)
22
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
23
+ @ready = false
24
+ @models = the_models.dup
25
+ @ready_count = 0
26
+ @pending_count = @models.size
27
+ if @models.any?
28
+ _models = @models.dup
29
+ _pairs = []
30
+ i = 0
31
+ while _models.size > 0
32
+ ii = i # strange: proc doesnt seem to close over i correctly
33
+ model = _models.shift
34
+ blk = proc do
35
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
36
+ # p "COMPLETE!", ii, model
37
+ @complete_blocks.delete(model)
38
+ @ready_models[ii] = model
39
+ @ready_count += 1
40
+ @pending_count -= 1
41
+ if @pending_count == 0
42
+ ready!
43
+ end
44
+ end
45
+ @complete_blocks[model] = blk
46
+ _pairs << [ model, blk ]
47
+ i += 1
48
+ end
49
+ RMXFirebase::QUEUE.barrier_async do
50
+ while pair = _pairs.shift
51
+ pair[0].once(RMXFirebase::QUEUE, &pair[1])
52
+ end
53
+ end
54
+ else
55
+ RMXFirebase::QUEUE.barrier_async do
56
+ ready!
57
+ end
58
+ end
59
+ end
60
+
61
+ def ready!
62
+ RMXFirebase::QUEUE.barrier_async do
63
+ @ready = true
64
+ # p "models", models.dup
65
+ # p "ready_models", ready_models.dup
66
+ RMX(self).trigger(:ready, @ready_models.dup)
67
+ end
68
+ end
69
+
70
+ def cancel!
71
+ RMXFirebase::QUEUE.barrier_async do
72
+ models_outstanding = @complete_blocks.keys.dup
73
+ while models_outstanding.size > 0
74
+ model = models_outstanding.shift
75
+ if blk = @complete_blocks[model]
76
+ @complete_blocks.delete(model)
77
+ model.cancel_block(&blk)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def ready?
84
+ !!@ready
85
+ end
86
+
87
+ def once(queue=nil, &block)
88
+ RMXFirebase::QUEUE.barrier_async do
89
+ if ready?
90
+ RMXFirebase.block_on_queue(queue, @ready_models.dup, &block)
91
+ else
92
+ RMX(self).once(:ready, :strong => true, :queue => queue, &block)
93
+ end
94
+ end
95
+ self
96
+ end
97
+
98
+ def cancel_block(&block)
99
+ RMX(self).off(:ready, &block)
100
+ end
101
+
102
+ end