rmx-firebase 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,202 @@
1
+ class RMXFirebaseModel
2
+
3
+ include RMXCommonMethods
4
+
5
+ attr_accessor :opts
6
+
7
+ attr_reader :api, :root
8
+
9
+ def self.new(opts=nil)
10
+ x = super
11
+ RMXFirebase::QUEUE.barrier_async do
12
+ x.internal_setup
13
+ end
14
+ x
15
+ end
16
+
17
+ def initialize(opts=nil)
18
+ @opts = opts
19
+ @dependencies_cancelled = {}
20
+ @dependencies_ready = {}
21
+ @dependencies = {}
22
+ end
23
+
24
+ def dealloc
25
+ if RMXFirebase::DEBUG_MODEL_DEALLOC
26
+ p " - dealloc!"
27
+ end
28
+ super
29
+ end
30
+
31
+ def ready?
32
+ !!@ready
33
+ end
34
+
35
+ def cancelled?
36
+ !!@cancelled
37
+ end
38
+
39
+ def finished?
40
+ ready? || cancelled?
41
+ end
42
+
43
+ def ready!
44
+ RMXFirebase::QUEUE.barrier_async do
45
+ # p "ready!"
46
+ @ready = true
47
+ RMX(self).trigger(:ready, self)
48
+ RMX(self).trigger(:finished, self)
49
+ end
50
+ end
51
+
52
+ def cancelled!
53
+ RMXFirebase::QUEUE.barrier_async do
54
+ @cancelled = true
55
+ RMX(self).trigger(:cancelled, self)
56
+ RMX(self).trigger(:finished, self)
57
+ end
58
+ end
59
+
60
+ # override
61
+ def setup
62
+ end
63
+
64
+ def internal_setup
65
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
66
+ @api = RMXFirebaseCoordinator.new
67
+ RMX(@api).on(:finished, :queue => RMXFirebase::QUEUE) do
68
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
69
+ check_ready
70
+ end
71
+ RMX(self).on(:cancelled, :exclusive => [ :ready, :finished ], :queue => :async)
72
+ setup
73
+ end
74
+
75
+ def check_ready
76
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
77
+ # p "check_ready cancelled?", @api.cancelled?, dependencies_cancelled.size
78
+ # p "check_ready ready?", @api.ready?, dependencies_ready.size, dependencies.size
79
+ if @api.cancelled? || @dependencies_cancelled.size > 0
80
+ cancelled!
81
+ elsif @api.ready? && @dependencies_ready.size == @dependencies.size
82
+ ready!
83
+ end
84
+ end
85
+
86
+ def watch(name, ref, opts={}, &block)
87
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
88
+ RMX(self).ivar(name, @api.watch(name, ref, opts, &block))
89
+ end
90
+
91
+ # add another model as a dependency and ivar,
92
+ # which will affect ready. should be done before ready has
93
+ # has a chance to be triggered. the user can add an
94
+ # attr_reader for easy access if desired.
95
+ #
96
+ # Book
97
+ # attr_reader :author
98
+ # model.watch(:root, ref) do |data|
99
+ # model.depend(:author, Author.get(data[:author_id]))
100
+ # end
101
+ # ...
102
+ # book = Book.get(1)
103
+ # book.attr("name") #=> "My Book"
104
+ # book.author.attr("name") #=> "Joe Noon"
105
+ def depend(name, model)
106
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
107
+ @dependencies[name] = model
108
+ RMX(self).ivar(name, model)
109
+ track_dependency_state(model)
110
+ RMX(model).on(:finished, :queue => RMXFirebase::QUEUE) do |_model|
111
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
112
+ track_dependency_state(_model)
113
+ check_ready
114
+ end
115
+ end
116
+
117
+ def track_dependency_state(model)
118
+ RMX(self).require_queue!(RMXFirebase::QUEUE, __FILE__, __LINE__) if RMX::DEBUG_QUEUES
119
+ if model.ready?
120
+ @dependencies_ready[model] = true
121
+ @dependencies_cancelled.delete(model)
122
+ elsif model.cancelled?
123
+ @dependencies_cancelled[model] = true
124
+ @dependencies_ready.delete(model)
125
+ end
126
+ end
127
+
128
+ def always_async(&block)
129
+ always(:async, &block)
130
+ end
131
+
132
+ def always(queue=nil, &block)
133
+ return false if cancelled?
134
+ if ready?
135
+ RMXFirebase.block_on_queue(queue, self, &block)
136
+ end
137
+ RMX(self).on(:ready, :queue => queue, &block)
138
+ end
139
+
140
+ def once(queue=nil, &block)
141
+ RMXFirebase::QUEUE.barrier_async do
142
+ if ready? || cancelled?
143
+ RMXFirebase.block_on_queue(queue, self, &block)
144
+ else
145
+ RMX(self).once(:ready, :strong => true, :queue => queue, &block)
146
+ end
147
+ end
148
+ self
149
+ end
150
+
151
+ def cancel_block(&block)
152
+ RMX(self).off(:ready, &block)
153
+ RMX(self).off(:cancelled, &block)
154
+ RMX(self).off(:finished, &block)
155
+ end
156
+
157
+ def attr(keypath)
158
+ root.attr(keypath)
159
+ end
160
+
161
+ def hasValue?
162
+ root.hasValue?
163
+ end
164
+
165
+ def toValue
166
+ root.toValue
167
+ end
168
+
169
+ def self.create(&block)
170
+ x = new
171
+ block.call(x)
172
+ x
173
+ end
174
+
175
+ # this is the method you should call
176
+ def self.get(opts=nil)
177
+ if opts && existing = identity_map[[ className, opts ]]
178
+ if RMXFirebase::DEBUG_IDENTITY_MAP
179
+ p "HIT!", className, opts, existing.retainCount
180
+ end
181
+ return existing
182
+ else
183
+ if RMXFirebase::DEBUG_IDENTITY_MAP
184
+ p "MISS!", className, opts
185
+ end
186
+ res = new(opts)
187
+ if opts
188
+ identity_map[[ className, opts ]] = res
189
+ end
190
+ res
191
+ end
192
+ end
193
+
194
+ Dispatch.once do
195
+ @@identity_map = RMXSynchronizedStrongToWeakHash.new
196
+ end
197
+
198
+ def self.identity_map
199
+ @@identity_map
200
+ end
201
+
202
+ end
@@ -0,0 +1,43 @@
1
+ class RMXFirebaseTableViewCell < RMXTableViewCell
2
+
3
+ extend RMXFirebaseHandleModel
4
+
5
+ def prepareForReuse
6
+ if @data
7
+ @data_unbinder.call if @data_unbinder
8
+ @data_unbinder = nil
9
+ end
10
+ @data = nil
11
+ reset
12
+ end
13
+
14
+ def reset
15
+ end
16
+
17
+ def changed
18
+ end
19
+
20
+ def data=(val)
21
+ return @data if val == @data
22
+ @data = val
23
+ if @data
24
+ unless @data.ready?
25
+ raise "#{className} tried to use a model that is not ready: #{@data.inspect}"
26
+ end
27
+ @data_unbinder = @data.always do |m|
28
+ next unless m == @data
29
+ changed
30
+ end
31
+ end
32
+ @data
33
+ end
34
+
35
+ def model
36
+ @data
37
+ end
38
+
39
+ def model=(val)
40
+ self.data = val
41
+ end
42
+
43
+ end
@@ -0,0 +1,38 @@
1
+ class RMXFirebaseView < RMXView
2
+
3
+ extend RMXFirebaseHandleModel
4
+
5
+ def reset
6
+ end
7
+
8
+ def changed
9
+ end
10
+
11
+ def model
12
+ @model
13
+ end
14
+
15
+ def model=(val)
16
+ return @model if @model == val
17
+ if @model
18
+ @model_unbinder.call if @model_unbinder
19
+ @model_unbinder = nil
20
+ end
21
+ @model = val
22
+ reset
23
+ if @model
24
+ unless @model.ready?
25
+ raise "#{className} tried to use a model that is not ready: #{@model.rmx_object_desc}"
26
+ end
27
+ @model_unbinder = @model.always do |m|
28
+ unless m == @model
29
+ p "model.always", "m", m, "@model", @model
30
+ end
31
+ next unless m == @model
32
+ changed
33
+ end
34
+ end
35
+ @model
36
+ end
37
+
38
+ end
@@ -0,0 +1,46 @@
1
+ class RMXFirebaseViewController < RMXViewController
2
+
3
+ extend RMXFirebaseHandleModel
4
+
5
+ def viewDidLoad
6
+ s = super
7
+ if @pending_changed
8
+ @pending_changed = nil
9
+ if @model
10
+ changed
11
+ end
12
+ end
13
+ s
14
+ end
15
+
16
+ def changed
17
+ end
18
+
19
+ def model
20
+ @model
21
+ end
22
+
23
+ def model=(val)
24
+ return @model if @model == val
25
+ if @model
26
+ @model_unbinder.call if @model_unbinder
27
+ @model_unbinder = nil
28
+ end
29
+ @model = val
30
+ if @model
31
+ unless @model.ready?
32
+ raise "#{className} tried to use a model that is not ready: #{@model.inspect}"
33
+ end
34
+ @model_unbinder = @model.always do |m|
35
+ next unless m == @model
36
+ if isViewLoaded
37
+ changed
38
+ else
39
+ @pending_changed = true
40
+ end
41
+ end
42
+ end
43
+ @model
44
+ end
45
+
46
+ end
@@ -0,0 +1,3 @@
1
+ class RMXFirebase
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,26 @@
1
+ require "rmx-firebase/version"
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "This file must be required within a RubyMotion project Rakefile."
5
+ end
6
+
7
+ Motion::Project::App.setup do |app|
8
+ index = app.files.rindex { |x| x.index("/RMX") }
9
+ %w(
10
+ Firebase+RMXFirebase
11
+ FQuery+RMXFirebase
12
+ RMXFirebase
13
+ RMXFirebaseDataSnapshot
14
+ RMXFirebaseListener
15
+ RMXFirebaseCoordinator
16
+ RMXFirebaseModel
17
+ RMXFirebaseBatch
18
+ RMXFirebaseCollection
19
+ RMXFirebaseHandleModel
20
+ RMXFirebaseTableViewCell
21
+ RMXFirebaseView
22
+ RMXFirebaseViewController
23
+ ).each_with_index do |x, i|
24
+ app.files.insert(index + 1 + i, File.join(File.dirname(__FILE__), "motion/#{x}.rb"))
25
+ end
26
+ end
Binary file
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rmx-firebase/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "rmx-firebase"
8
+ gem.version = RMXFirebase::VERSION
9
+ gem.authors = ["Joe Noon"]
10
+ gem.email = ["joenoon@gmail.com"]
11
+ gem.description = %q{Experimental rubymotion wrapper for firebase}
12
+ gem.summary = %q{Experimental rubymotion wrapper for firebase}
13
+ gem.homepage = "https://github.com/joenoon/rmx-firebase"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ gem.add_dependency "rmx", "~> 0.5.2"
20
+ end
@@ -0,0 +1,146 @@
1
+ class Bacon::Context
2
+ def after_modifications(collection, &block)
3
+ wait(0.5) do
4
+ collection.once do |snaps|
5
+ snap_names = snaps.map(&:name)
6
+ puts "snap_names: #{snap_names.inspect}\n\n"
7
+ RMX.block_on_main_q(block, snap_names)
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ describe "RMXFirebaseCollection" do
14
+
15
+ before do
16
+ Firebase.goOffline
17
+ $firebase = Firebase.alloc.initWithUrl("https://rmext.firebaseio.local/")
18
+ @ref = $firebase["collection_test"]
19
+ @letters = {
20
+ "a" => 10,
21
+ "b" => 20,
22
+ "c" => 30,
23
+ "d" => 40,
24
+ "e" => 50,
25
+ "f" => 60,
26
+ "g" => 70,
27
+ "h" => 80,
28
+ "i" => 90,
29
+ "j" => 100,
30
+ "k" => 110,
31
+ "l" => 120,
32
+ "m" => 130,
33
+ "n" => 140,
34
+ "o" => 150,
35
+ "p" => 160,
36
+ "q" => 170,
37
+ "r" => 180,
38
+ "s" => 190,
39
+ "t" => 200,
40
+ "u" => 210,
41
+ "v" => 220,
42
+ "w" => 230,
43
+ "x" => 240,
44
+ "y" => 250,
45
+ "z" => 260
46
+ }
47
+ end
48
+
49
+ describe "a collection" do
50
+
51
+ before do
52
+ @col = RMXFirebaseCollection.new(@ref)
53
+ @ref.setValue({})
54
+ @letters.each_pair do |k, pri|
55
+ p "SET", k, pri
56
+ @ref[k].setValue(pri, andPriority:pri)
57
+ end
58
+ end
59
+
60
+ it "can move c after v" do
61
+ @ref["c"].setPriority(@letters["v"] + 1)
62
+ after_modifications(@col) do |snap_names|
63
+ snap_names.index("c").should == snap_names.index("v") + 1
64
+ end
65
+ end
66
+
67
+ it "can move c after z" do
68
+ @ref["c"].setPriority(@letters["z"] + 1)
69
+ after_modifications(@col) do |snap_names|
70
+ snap_names.index("c").should == snap_names.index("z") + 1
71
+ end
72
+ end
73
+
74
+ it "can move c after everything" do
75
+ @ref["c"].setPriority(10000)
76
+ after_modifications(@col) do |snap_names|
77
+ snap_names.last.should == "c"
78
+ end
79
+ end
80
+
81
+ it "can move v before f" do
82
+ @ref["v"].setPriority(@letters["f"] - 1)
83
+ after_modifications(@col) do |snap_names|
84
+ snap_names.index("v").should == snap_names.index("f") - 1
85
+ end
86
+ end
87
+
88
+ it "can move c before everything" do
89
+ @ref["c"].setPriority(-10000)
90
+ after_modifications(@col) do |snap_names|
91
+ snap_names.first.should == "c"
92
+ end
93
+ end
94
+
95
+ it "add a new value before everything" do
96
+ @ref["new"].setValue(".", andPriority:-10000)
97
+ after_modifications(@col) do |snap_names|
98
+ snap_names.first.should == "new"
99
+ end
100
+ end
101
+
102
+ it "add a new value after everything" do
103
+ @ref["new"].setValue(".", andPriority:10000)
104
+ after_modifications(@col) do |snap_names|
105
+ snap_names.last.should == "new"
106
+ end
107
+ end
108
+
109
+ it "add a new value after j" do
110
+ @ref["new"].setValue(".", andPriority:(@letters["j"] + 1))
111
+ after_modifications(@col) do |snap_names|
112
+ snap_names.index("new").should == snap_names.index("j") + 1
113
+ end
114
+ end
115
+
116
+ it "add a new value before j" do
117
+ @ref["new"].setValue(".", andPriority:(@letters["j"] - 1))
118
+ after_modifications(@col) do |snap_names|
119
+ snap_names.index("new").should == snap_names.index("j") - 1
120
+ end
121
+ end
122
+
123
+ it "remove a" do
124
+ @ref["a"].removeValue
125
+ after_modifications(@col) do |snap_names|
126
+ snap_names.first.should == "b"
127
+ end
128
+ end
129
+
130
+ it "remove z" do
131
+ @ref["z"].removeValue
132
+ after_modifications(@col) do |snap_names|
133
+ snap_names.last.should == "y"
134
+ end
135
+ end
136
+
137
+ it "remove j" do
138
+ @ref["j"].removeValue
139
+ after_modifications(@col) do |snap_names|
140
+ snap_names[snap_names.index("i") + 1].should == "k"
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rmx-firebase
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Joe Noon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rmx
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.2
27
+ description: Experimental rubymotion wrapper for firebase
28
+ email:
29
+ - joenoon@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - LICENSE.txt
37
+ - README.md
38
+ - Rakefile
39
+ - app/app_delegate.rb
40
+ - lib/motion/FQuery+RMXFirebase.rb
41
+ - lib/motion/Firebase+RMXFirebase.rb
42
+ - lib/motion/RMXFirebase.rb
43
+ - lib/motion/RMXFirebaseBatch.rb
44
+ - lib/motion/RMXFirebaseCollection.rb
45
+ - lib/motion/RMXFirebaseCoordinator.rb
46
+ - lib/motion/RMXFirebaseDataSnapshot.rb
47
+ - lib/motion/RMXFirebaseHandleModel.rb
48
+ - lib/motion/RMXFirebaseListener.rb
49
+ - lib/motion/RMXFirebaseModel.rb
50
+ - lib/motion/RMXFirebaseTableViewCell.rb
51
+ - lib/motion/RMXFirebaseView.rb
52
+ - lib/motion/RMXFirebaseViewController.rb
53
+ - lib/rmx-firebase.rb
54
+ - lib/rmx-firebase/version.rb
55
+ - resources/Default-568h@2x.png
56
+ - rmx-firebase.gemspec
57
+ - spec/collection_spec.rb
58
+ homepage: https://github.com/joenoon/rmx-firebase
59
+ licenses: []
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.0.14
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Experimental rubymotion wrapper for firebase
81
+ test_files:
82
+ - spec/collection_spec.rb