motion_bindable 0.0.6 → 0.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f463cb26ed789a3715bf0d6527bd87356dc7112f
4
- data.tar.gz: 97b54d01d66b4f65fc5debbda78e2ecfbe9d430f
3
+ metadata.gz: 22f69831469c0aae59f8af6aa599f586276bd23c
4
+ data.tar.gz: 61181ef1e9254eb8378bc229eacc396851480867
5
5
  SHA512:
6
- metadata.gz: 157772a475b474b87df0e0060f6ead78d9f98b3e13f53c457ffaf9c1cd7e8725d6be891dc196aa37d606b14a89f64922b28b729534863fe16f9dd6ec45911a7f
7
- data.tar.gz: 27f4376256b12d9ef4e2d6be2266c5bf4e2f426a210ec53a9e5ce81bd6371c06bbbb464e52cfffab285f98c6cde0797791bc97565e71659265135f89216d0e3f
6
+ metadata.gz: 9581949f1fe049307b10aeb65e26ac65976662c1e5ad51e18c741ebe46340774c5d6296ac41a417ee17a7f2ef1bb957c5075eb590c586b674b1978957aac5283
7
+ data.tar.gz: 1f28ee9528235b42e9e4282e116e5fa54a279fad178f32977a6e34ffec35e4c78ff590faff1a763d9532170c4fc04ac483190d438abb0fbd35a46c5a51dba772
data/Gemfile CHANGED
@@ -4,3 +4,4 @@ gem 'rake'
4
4
  # Add your dependencies here:
5
5
  gem 'webstub'
6
6
  gem 'motion-stump'
7
+ gem 'bubble-wrap', '~> 1.4.0'
data/Gemfile.lock CHANGED
@@ -1,6 +1,7 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
+ bubble-wrap (1.4.0)
4
5
  motion-stump (0.3.0)
5
6
  rake (10.1.0)
6
7
  webstub (1.0.1)
@@ -9,6 +10,7 @@ PLATFORMS
9
10
  ruby
10
11
 
11
12
  DEPENDENCIES
13
+ bubble-wrap (~> 1.4.0)
12
14
  motion-stump
13
15
  rake
14
16
  webstub
@@ -15,7 +15,9 @@ module MotionBindable
15
15
 
16
16
  def bind_attributes(attrs, object = self)
17
17
  attrs.each_pair do |k, v|
18
- if v.is_a?(Hash) then bind_attributes(v, object.send(k))
18
+ case v
19
+ when Hash then bind_attributes(v, object.send(k))
20
+ when Array then v.each { |v| bind strategy_for(v).new(object, k).bind(v) }
19
21
  else bind strategy_for(v).new(object, k).bind(v)
20
22
  end
21
23
  end
@@ -27,25 +29,20 @@ module MotionBindable
27
29
  self
28
30
  end
29
31
 
32
+ def unbind_all
33
+ @bindings.each { |b| b.unbind }
34
+ @bindings = []
35
+ end
36
+
30
37
  def refresh
31
38
  @bindings.each { |b| b.refresh }
32
39
  self
33
40
  end
34
41
 
35
- private
36
-
37
42
  def strategy_for(reference)
38
43
  Strategy.find_by_reference(reference)
39
44
  end
40
45
 
41
- def underscore(str)
42
- str.gsub(/::/, '/')
43
- .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
44
- .gsub(/([a-z\d])([A-Z])/,'\1_\2')
45
- .tr("-", "_")
46
- .downcase
47
- end
48
-
49
46
  end
50
47
 
51
48
  end
@@ -20,9 +20,9 @@ module MotionBindable
20
20
  attr_accessor :object
21
21
  attr_accessor :bound
22
22
 
23
- def initialize(object, attribute)
24
- @attribute = attribute.to_sym
25
- self.object = WeakRef.new(object)
23
+ def initialize(object, attr_name)
24
+ @attr_name = attr_name.to_sym
25
+ self.object = object
26
26
  end
27
27
 
28
28
  def bind(bound)
@@ -32,6 +32,9 @@ module MotionBindable
32
32
  self
33
33
  end
34
34
 
35
+ def unbind
36
+ end
37
+
35
38
  # You can either choose to just override `#refresh` for objects that can't
36
39
  # be bound with callbacks. Or override `#on_bind` for objects that can be
37
40
  # bound with a callback.
@@ -41,11 +44,11 @@ module MotionBindable
41
44
  end
42
45
 
43
46
  def attribute
44
- object.send(@attribute)
47
+ object.send(@attr_name)
45
48
  end
46
49
 
47
50
  def attribute=(value)
48
- object.send(:"#{@attribute.to_s}=", value)
51
+ object.send(:"#{@attr_name.to_s}=", value)
49
52
  end
50
53
 
51
54
  end
@@ -1,3 +1,3 @@
1
1
  module MotionBindable
2
- VERSION = "0.0.6"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -2,28 +2,37 @@ module MotionBindable::Strategies
2
2
 
3
3
  class UITextField < ::MotionBindable::Strategy
4
4
 
5
+ include BW::KVO
6
+
5
7
  def on_bind
6
- update_attribute
8
+ refresh
9
+
10
+ # Observe the bound object
7
11
  NSNotificationCenter.defaultCenter.addObserver(
8
- self,
9
- selector: :on_change,
10
- name: UITextFieldTextDidChangeNotification,
11
- object: bound
12
+ self, selector: :on_bound_change,
13
+ name: UITextFieldTextDidChangeNotification, object: bound
12
14
  )
13
- end
14
15
 
15
- def on_change
16
- update_attribute
16
+ # Observe the attribute
17
+ observe(object, @attr_name) { |_, _| on_object_change }
17
18
  end
18
19
 
19
- alias_method :refresh, :on_change
20
+ def on_bound_change
21
+ self.attribute = bound.text
22
+ end
20
23
 
21
- private
24
+ def on_object_change
25
+ @bound.text = attribute
26
+ end
22
27
 
23
- def update_attribute
24
- self.attribute = bound.text
28
+ def unbind
29
+ App.notification_center.unobserve(@bound_observer)
30
+ unobserve(object, @attr_name)
25
31
  end
26
32
 
33
+ # Text field takes precedence
34
+ alias_method :refresh, :on_bound_change
35
+
27
36
  end
28
37
 
29
38
  end
@@ -17,4 +17,6 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'bubble-wrap', '~> 1.4.0'
20
22
  end
@@ -11,50 +11,77 @@ describe 'MotionBindable::Bindable' do
11
11
 
12
12
  before do
13
13
  @object = FakeBindable.new
14
- @bound = Object.new
14
+ @object.nested = FakeBindable.new
15
15
  @object.stub!(:strategy_for) { |_| FakeStrategy }
16
- @strategy = FakeStrategy.new(@object, :attribute)
16
+ @bound = Object.new
17
+ FakeStrategy.stub!(:new) { |_, _| @strategy }
17
18
  end
18
19
 
19
20
  describe '#bind_attributes' do
20
- before do
21
- @object.nested = FakeBindable.new
22
- end
23
21
 
24
- it 'accepts nested attributes' do
25
- FakeStrategy.stub!(:bind) do |attribute|
26
- @attribute = attribute
22
+ context 'un-nested' do
23
+ before do
24
+ @strategy = FakeStrategy.new(@object, :attribute)
27
25
  end
28
26
 
29
- @object.bind_attributes({
30
- attribute: @bound,
31
- nested: {
32
- attribute: @bound
33
- }
34
- })
27
+ it 'accepts an array of objects' do
28
+ @attributes = []
29
+ @strategy.stub!(:bind) { |attribute| @attributes << attribute }
30
+ @bound2 = Object.new
31
+ @object.bind_attributes(attribute: [@bound, @bound2])
32
+ @attributes.length.should.equal 2
33
+ end
35
34
 
36
- @attribute.should.equal @object.nested.attribute
35
+ it 'passes the strategy to bind' do
36
+ @called = false
37
+ @object.stub!(:bind) { |_| @called = true }
38
+ @object.bind_attributes({ attribute: @bound })
39
+ @called.should.equal true
40
+ end
37
41
  end
38
42
 
39
- it 'passes the strategy to bind' do
40
- @called = false
41
- @object.stub!(:bind) { |_| @called = true }
42
- @object.bind_attributes({ attribute: @bound })
43
- @called.should.equal true
43
+ context 'nested' do
44
+ before do
45
+ @strategy = FakeStrategy.new(@object.nested, :attribute)
46
+ end
47
+
48
+ it 'accepts nested attributes' do
49
+ @strategy.stub!(:bind) { |bound| @bounded = bound }
50
+ @object.bind_attributes nested: { attribute: @bound }
51
+ @bounded.should.equal @bound
52
+ end
44
53
  end
45
54
 
46
55
  end
47
56
 
48
57
  describe '#bind' do
58
+ before do
59
+ @strategy = FakeStrategy.new(@object, :attribute)
60
+ @strategy.bind(@bound)
61
+ end
62
+
49
63
  it 'should be chainable' do
50
64
  @object.bind(@strategy).should.equal @object
51
65
  end
52
66
  end
53
67
 
54
- describe '#refresh' do
55
- it 'should be chainable' do
56
- @object.bind(@strategy)
57
- @object.refresh.should.equal @object
68
+ describe '#unbind_all' do
69
+ before do
70
+ @strategy1 = FakeStrategy.new(@object, :attribute)
71
+ @strategy1.bind(@bound)
72
+ @object.bind(@strategy1)
73
+
74
+ @strategy2 = FakeStrategy.new(@object.nested, :attribute)
75
+ @strategy2.bind(@bound)
76
+ @object.bind(@strategy2)
77
+ end
78
+
79
+ it 'should send unbind to all strategies' do
80
+ @called = 0
81
+ @strategy1.stub!(:unbind) { @called += 1 }
82
+ @strategy2.stub!(:unbind) { @called += 1 }
83
+ @object.unbind_all
84
+ @called.should.equal 2
58
85
  end
59
86
  end
60
87
 
@@ -62,6 +62,12 @@ describe 'MotionBindable::Strategy' do
62
62
  end
63
63
  end
64
64
 
65
+ describe '#unbind' do
66
+ it 'should respond' do
67
+ @strategy.respond_to?(:unbind).should.equal true
68
+ end
69
+ end
70
+
65
71
  end
66
72
 
67
73
  end
@@ -1,7 +1,10 @@
1
1
  class FakeModel
2
2
  include MotionBindable::Bindable
3
- attr_accessor :attribute
4
3
  attr_accessor :nested
4
+ attr_accessor :attribute
5
+ def attribute
6
+ @attribute
7
+ end
5
8
  end
6
9
 
7
10
  describe 'MotionBindable::Strategies::UITextField' do
@@ -24,14 +27,11 @@ describe 'MotionBindable::Strategies::UITextField' do
24
27
  end
25
28
 
26
29
  context 'text set and then bound' do
27
-
28
30
  before do
29
31
  @text_field.text = 'Just testing.'
30
32
  @object.bind_attributes({
31
33
  attribute: @text_field,
32
- nested: {
33
- attribute: @text_field
34
- }
34
+ nested: { attribute: @text_field }
35
35
  })
36
36
  end
37
37
 
@@ -48,9 +48,10 @@ describe 'MotionBindable::Strategies::UITextField' do
48
48
  before do
49
49
  @text_field.text = 'Updated.'
50
50
  NSNotificationCenter.defaultCenter.postNotificationName(
51
- UITextFieldTextDidChangeNotification,
52
- object: @text_field
51
+ UITextFieldTextDidChangeNotification, object: @text_field
53
52
  )
53
+ # BW puts observer cb's into this queue
54
+ NSOperationQueue.mainQueue.waitUntilAllOperationsAreFinished
54
55
  end
55
56
 
56
57
  it 'should update the root attribute' do
@@ -60,12 +61,20 @@ describe 'MotionBindable::Strategies::UITextField' do
60
61
  it 'should update the nested attribute' do
61
62
  @object.nested.attribute.should.equal 'Updated.'
62
63
  end
64
+ end
65
+
66
+ context 'bound attribute is updated' do
67
+ before do
68
+ @object.attribute = 'Reverse'
69
+ end
63
70
 
71
+ it 'should update the text field' do
72
+ @text_field.text.should.equal 'Reverse'
73
+ end
64
74
  end
65
75
 
66
76
  end
67
77
 
68
78
  end
69
79
 
70
-
71
80
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion_bindable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Kot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-19 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2013-12-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bubble-wrap
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.0
13
27
  description: A simple data binding library for RubyMotion.
14
28
  email:
15
29
  - nk@nathankot.com