kvo 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@ pkg/*
2
2
  *.gem
3
3
  .bundle
4
4
  *.lock
5
+ tags
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Description
2
2
  ===========
3
3
 
4
- Key-Value Observing in ruby
4
+ Key-Value Observing and Binding in ruby
5
5
 
6
6
  ### Synopsis
7
7
 
@@ -9,16 +9,34 @@ Fires a [Publisher](http://atomicobject.github.com/publisher/) event whenever th
9
9
 
10
10
  ### How do I use it?
11
11
 
12
+ ```ruby
13
+ # kvo example
12
14
  class Foo
13
15
  include Kvo
14
16
  kvo_attr_accessor :bar, :baz
15
17
  end
16
-
18
+
17
19
  f = Foo.new
18
20
  f.when :bar_changed do |oldVal, newVal|
19
21
  puts "bar was changed from #{oldVal} to #{newVal}"
20
22
  end
21
23
 
24
+
25
+ # kvb example
26
+ class Baz
27
+ attr_accessor :bar
28
+ end
29
+
30
+ b = Bar.new
31
+ # b's bar will be updated whenever f's is
32
+ f.kvo_bind_attr :bar, b
33
+
34
+ # optional transforms
35
+ f.kvo_bind_attr :bar, b do |val|
36
+ val + 5
37
+ end
38
+ ```
39
+
22
40
  Authors
23
41
  =======
24
42
  * Shawn Anderson (shawn.anderson@atomicobject.com)
data/lib/kvo.rb CHANGED
@@ -3,21 +3,42 @@ module Kvo
3
3
  module ClassMethods
4
4
  def kvo_attr_accessor(*kvo_symbols)
5
5
  kvo_symbols.each do |kvo|
6
+
7
+ raise "the method #{kvo} already exists" if self.instance_methods.include? kvo
8
+ raise "the method #{kvo}= already exists" if self.instance_methods.include? "#{kvo}=".to_sym
9
+
6
10
  class_eval <<-METHODS
7
11
  can_fire :#{kvo}_changed unless published_events == :any_event_is_ok
8
12
  def #{kvo}
9
13
  @kvo_#{kvo}
10
14
  end
11
- def #{kvo}=(newVal)
15
+ def #{kvo}=(new_val)
12
16
  old = @kvo_#{kvo}
13
- @kvo_#{kvo}=newVal
14
- fire :#{kvo}_changed, old, newVal
17
+ @kvo_#{kvo}=new_val
18
+ fire :#{kvo}_changed, old, new_val
15
19
  end
16
20
  METHODS
17
21
  end
18
22
  end
19
23
  end
20
24
 
25
+ def kvo_bind_attr(attr_sym, target, opts={})
26
+ target_attr = opts[:to] || attr_sym
27
+ change_event = "#{attr_sym}_changed".to_sym
28
+
29
+ unless self.class.published_events.include? change_event
30
+ raise "#{attr_sym} is not a kvo attr; use #{self.class}.kvo_attr_accessor #{attr_sym}"
31
+ end
32
+
33
+ self.when change_event do |old, new_val|
34
+ val = new_val
35
+ # transform
36
+ val = yield(new_val) if block_given?
37
+
38
+ target.send "#{target_attr}=", val
39
+ end
40
+ end
41
+
21
42
  def self.included(receiver)
22
43
  receiver.extend Publisher
23
44
  receiver.extend ClassMethods
data/lib/kvo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kvo
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/spec/kvo_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__),'helper')
2
2
 
3
- describe 'kvo' do
3
+ describe '.kvo_attr_accessor' do
4
4
  before do
5
5
  @target = Foo.new
6
6
  @target.bar = :old
@@ -32,6 +32,21 @@ describe 'kvo' do
32
32
  @target.instance_variable_get("@bar").should be_nil
33
33
  end
34
34
 
35
+ it 'can call back a block of arity 0' do
36
+ @baz_fired = nil
37
+ @target.when :baz_changed do @baz_fired = true end
38
+ @target.baz = :something
39
+ @baz_fired.should be
40
+ end
41
+
42
+ it 'raises an error if attr setter is already defined' do
43
+ lambda{ ThingOne.kvo_attr_accessor :one }.should raise_exception(RuntimeError, /one= already exists/)
44
+ end
45
+
46
+ it 'raises an error if attr getter is already defined' do
47
+ lambda{ ThingTwo.kvo_attr_accessor :two }.should raise_exception(RuntimeError, /two already exists/)
48
+ end
49
+
35
50
  describe "inheritance" do
36
51
  before do
37
52
  @target = SubFoo.new
@@ -66,6 +81,44 @@ describe 'kvo' do
66
81
  end
67
82
  end
68
83
 
84
+ describe '#kvo_bind_attr' do
85
+ let(:peter_pan) {
86
+ peter = PeterPan.new
87
+ peter.location = "OVER THERE"
88
+ peter.flying = false
89
+ peter
90
+ }
91
+ let(:shadow) { Shadow.new }
92
+
93
+ it 'modifies attr when bound objects attr changes' do
94
+ peter_pan.kvo_bind_attr :location, shadow
95
+ peter_pan.location = "NEVERLAND"
96
+
97
+ shadow.location.should == "NEVERLAND"
98
+ end
99
+
100
+ it 'can use a different method name on target' do
101
+ peter_pan.kvo_bind_attr :location, shadow, to: :place
102
+
103
+ peter_pan.location = "NEVERLAND"
104
+
105
+ shadow.location.should be_nil
106
+ shadow.place.should == "NEVERLAND"
107
+ end
108
+
109
+ it 'can transform new value with a block' do
110
+ peter_pan.kvo_bind_attr :location, shadow do |new_value|
111
+ new_value.downcase
112
+ end
113
+ peter_pan.location = "NEVERLAND"
114
+ shadow.location.should == "neverland"
115
+ end
116
+
117
+ it 'can bind to non-kvo attrs (by making them kvo)' do
118
+ lambda{ peter_pan.kvo_bind_attr :flying, shadow}.should raise_exception(RuntimeError, /flying is not a kvo attr/)
119
+ end
120
+ end
121
+
69
122
  class Foo
70
123
  include Kvo
71
124
  kvo_attr_accessor :bar, :baz
@@ -74,3 +127,26 @@ end
74
127
  class SubFoo < Foo
75
128
  kvo_attr_accessor :qux
76
129
  end
130
+
131
+ class PeterPan
132
+ include Kvo
133
+ kvo_attr_accessor :location
134
+ attr_accessor :flying
135
+ end
136
+
137
+ class Shadow
138
+ attr_accessor :location, :place, :flying
139
+ end
140
+
141
+ class ThingOne
142
+ include Kvo
143
+ attr_writer :one
144
+ end
145
+
146
+ class ThingTwo
147
+ include Kvo
148
+ attr_reader :two
149
+ end
150
+
151
+
152
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kvo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-28 00:00:00.000000000 Z
12
+ date: 2012-06-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: publisher
16
- requirement: &2157009500 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2157009500
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rspec
27
- requirement: &2157008500 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '0'
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *2157008500
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: mocha
38
- requirement: &2157007540 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,7 +53,12 @@ dependencies:
43
53
  version: '0'
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *2157007540
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
47
62
  description: KVO in ruby.
48
63
  email:
49
64
  - shawn42@gmail.com
@@ -80,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
95
  version: '0'
81
96
  requirements: []
82
97
  rubyforge_project: kvo
83
- rubygems_version: 1.8.10
98
+ rubygems_version: 1.8.24
84
99
  signing_key:
85
100
  specification_version: 3
86
101
  summary: KVO in ruby