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 +1 -0
- data/README.md +20 -2
- data/lib/kvo.rb +24 -3
- data/lib/kvo/version.rb +1 -1
- data/spec/kvo_spec.rb +77 -1
- metadata +24 -9
data/.gitignore
CHANGED
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}=(
|
15
|
+
def #{kvo}=(new_val)
|
12
16
|
old = @kvo_#{kvo}
|
13
|
-
@kvo_#{kvo}=
|
14
|
-
fire :#{kvo}_changed, old,
|
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
data/spec/kvo_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__),'helper')
|
2
2
|
|
3
|
-
describe '
|
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.
|
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-
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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.
|
98
|
+
rubygems_version: 1.8.24
|
84
99
|
signing_key:
|
85
100
|
specification_version: 3
|
86
101
|
summary: KVO in ruby
|