observables 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,15 @@
1
- module Observables
2
- class Array < ::Array
3
- include ArrayWatcher
4
- def initialize(*args)
5
- super(*args)
6
- end
7
- end
8
-
9
- class Hash < ::Hash
10
- include HashWatcher
11
- def initialize(*args)
12
- super(*args)
13
- end
14
- end
1
+ module Observables
2
+ class Array < ::Array
3
+ include ArrayWatcher
4
+ def initialize(*args)
5
+ super(*args)
6
+ end
7
+ end
8
+
9
+ class Hash < ::Hash
10
+ include HashWatcher
11
+ def initialize(*args)
12
+ super(*args)
13
+ end
14
+ end
15
15
  end
@@ -1,5 +1,5 @@
1
- class ::Array
2
- def make_observable
3
- class << self; include Observables::ArrayWatcher; end unless observable?
4
- end
1
+ class ::Array
2
+ def make_observable
3
+ class << self; include Observables::ArrayWatcher; end unless observable?
4
+ end
5
5
  end
@@ -1,5 +1,5 @@
1
- class ::Hash
2
- def make_observable
3
- class << self; include Observables::HashWatcher; end unless observable?
4
- end
1
+ class ::Hash
2
+ def make_observable
3
+ class << self; include Observables::HashWatcher; end unless observable?
4
+ end
5
5
  end
@@ -1,10 +1,10 @@
1
- class ::Object
2
- def can_be_observable?
3
- respond_to?(:make_observable)
4
- end
5
-
6
- def observable?
7
- kind_of?(Observables::Base)
8
- end
9
-
1
+ class ::Object
2
+ def can_be_observable?
3
+ respond_to?(:make_observable)
4
+ end
5
+
6
+ def observable?
7
+ kind_of?(Observables::Base)
8
+ end
9
+
10
10
  end
@@ -1,40 +1,40 @@
1
- module Observables
2
- module HashWatcher
3
- include Observables::Base
4
-
5
- MODIFIER_METHODS = :replace, :merge!, :update
6
- REMOVE_METHODS = :clear, :delete, :delete_if, :reject!, :shift
7
-
8
- #[]= can either be an add method or a modifier method depending on
9
- #if the previous key exists
10
- def []=(key,val)
11
- change_type = keys.include?(key) ? :modified : :added
12
- changes = changes_for(change_type,:[]=,key,val)
13
- changing(change_type,:trigger=>:[]=, :changes=>changes) {super}
14
- end
15
- alias :store :[]=
16
-
17
- override_mutators :modified=>MODIFIER_METHODS,
18
- :removed=>REMOVE_METHODS
19
-
20
- def changes_for(change_type, trigger_method, *args, &block)
21
- prev = self.dup
22
- if change_type == :added
23
- lambda {{:added=>[args]}}
24
- elsif change_type == :removed
25
- case trigger_method
26
- when :clear then lambda{{:removed=>prev.to_a}}
27
- when :delete then lambda{{:removed=>[[args[0],prev[args[0]]]]}}
28
- when :delete_if, :reject! then lambda{{:removed=>prev.select(&block)}}
29
- when :shift then lambda { {:removed=>[prev.keys[0],prev.values[0]]}}
30
- end
31
- else
32
- case trigger_method
33
- when :[]= then lambda{{:removed=>[[args[0],prev[args[0]]]],:added=>[args]}}
34
- when :replace then lambda{{:removed=>prev.to_a, :added=>args[0].to_a}}
35
- when :merge!, :update then lambda{{:removed=>prev.select{|k,_|args[0].keys.include?(k)},:added=>args[0].to_a}}
36
- end
37
- end
38
- end
39
- end
1
+ module Observables
2
+ module HashWatcher
3
+ include Observables::Base
4
+
5
+ MODIFIER_METHODS = :replace, :merge!, :update
6
+ REMOVE_METHODS = :clear, :delete, :delete_if, :reject!, :shift
7
+
8
+ #[]= can either be an add method or a modifier method depending on
9
+ #if the previous key exists
10
+ def []=(key,val)
11
+ change_type = keys.include?(key) ? :modified : :added
12
+ changes = changes_for(change_type,:[]=,key,val)
13
+ changing(change_type,:trigger=>:[]=, :changes=>changes) {super}
14
+ end
15
+ alias :store :[]=
16
+
17
+ override_mutators :modified=>MODIFIER_METHODS,
18
+ :removed=>REMOVE_METHODS
19
+
20
+ def changes_for(change_type, trigger_method, *args, &block)
21
+ prev = self.dup
22
+ if change_type == :added
23
+ lambda {{:added=>[args]}}
24
+ elsif change_type == :removed
25
+ case trigger_method
26
+ when :clear then lambda{{:removed=>prev.to_a}}
27
+ when :delete then lambda{{:removed=>[[args[0],prev[args[0]]]]}}
28
+ when :delete_if, :reject! then lambda{{:removed=>prev.select(&block)}}
29
+ when :shift then lambda { {:removed=>[prev.keys[0],prev.values[0]]}}
30
+ end
31
+ else
32
+ case trigger_method
33
+ when :[]= then lambda{{:removed=>[[args[0],prev[args[0]]]],:added=>[args]}}
34
+ when :replace then lambda{{:removed=>prev.to_a, :added=>args[0].to_a}}
35
+ when :merge!, :update then lambda{{:removed=>prev.select{|k,_|args[0].keys.include?(k)},:added=>args[0].to_a}}
36
+ end
37
+ end
38
+ end
39
+ end
40
40
  end
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
2
- module Observables
3
- Version = '0.1.1'
4
- end
1
+ # encoding: UTF-8
2
+ module Observables
3
+ Version = '0.1.2'
4
+ end
@@ -1,21 +1,21 @@
1
- require "test_helper"
2
-
3
- class TestExtensions < Test::Unit::TestCase
4
- context "Array" do
5
- context "#make_observable" do
6
-
7
- should "detect an observable array" do
8
- x, y = [], [].tap{|a|a.make_observable}
9
- assert_equal false, x.observable?
10
- assert y.observable?
11
- end
12
-
13
- should "make an instance of an array observable" do
14
- x = []
15
- assert_equal false, x.observable?
16
- x.make_observable
17
- assert x.observable?
18
- end
19
- end
20
- end
1
+ require "test_helper"
2
+
3
+ class TestExtensions < Test::Unit::TestCase
4
+ context "Array" do
5
+ context "#make_observable" do
6
+
7
+ should "detect an observable array" do
8
+ x, y = [], [].tap{|a|a.make_observable}
9
+ assert_equal false, x.observable?
10
+ assert y.observable?
11
+ end
12
+
13
+ should "make an instance of an array observable" do
14
+ x = []
15
+ assert_equal false, x.observable?
16
+ x.make_observable
17
+ assert x.observable?
18
+ end
19
+ end
20
+ end
21
21
  end
@@ -1,9 +1,9 @@
1
- require 'test_helper'
2
-
3
- class TestObservables < Test::Unit::TestCase
4
- context "including observables" do
5
- should "include something or other" do
6
- assert_equal defined?(Observables), "constant"
7
- end
8
- end
9
- end
1
+ require 'test_helper'
2
+
3
+ class TestObservables < Test::Unit::TestCase
4
+ context "including observables" do
5
+ should "include something or other" do
6
+ assert_equal defined?(Observables), "constant"
7
+ end
8
+ end
9
+ end
@@ -1,137 +1,137 @@
1
- require "test_helper"
2
-
3
- class TestArrayWatcher < Test::Unit::TestCase
4
- context "An array which has included Observables::ArrayWatcher" do
5
- setup do
6
- @ary = Array.new([1,2,3]).tap do |a|
7
- a.make_observable
8
- end
9
- end
10
-
11
- should "notify observers of any change that adds elements to itself" do
12
- before_methods, after_methods = [],[]
13
- method_list = Observables::ArrayWatcher::ADD_METHODS
14
- @ary.subscribe(/before_added/){|_,args|before_methods<<args[:trigger]}
15
- @ary.subscribe(/after_added/) {|_,args|after_methods<<args[:trigger]}
16
- method_list.each do |method|
17
- @ary.send(method,*args_for(method))
18
- end
19
-
20
- assert_equal method_list, before_methods
21
- assert_equal method_list, after_methods
22
- end
23
-
24
- should "notify observers of any change that modifies elements" do
25
- before_methods, after_methods = [],[]
26
- method_list = Observables::ArrayWatcher::MODIFIER_METHODS
27
- @ary.subscribe(/before_modified/){|_,args|before_methods<<args[:trigger]}
28
- @ary.subscribe(/after_modified/) {|_,args|after_methods<<args[:trigger]}
29
- method_list.each do |method|
30
- args = args_for(method)
31
- args ? @ary.send(method,*args) : @ary.send(method)
32
- end
33
- assert_equal method_list, before_methods
34
- assert_equal method_list, after_methods
35
- end
36
-
37
- should "notify observers of any change that removes elements" do
38
- before_methods, after_methods = [],[]
39
- method_list = Observables::ArrayWatcher::REMOVE_METHODS
40
- @ary.subscribe(/before_removed/){|_,args|before_methods<<args[:trigger]}
41
- @ary.subscribe(/after_removed/) {|_,args|after_methods<<args[:trigger]}
42
- method_list.each do |method|
43
- args = args_for(method)
44
- args ? @ary.send(method,*args) : @ary.send(method)
45
- end
46
- assert_equal method_list, before_methods
47
- assert_equal method_list, after_methods
48
- end
49
-
50
- context "Calling #changes on the event args" do
51
- should "calculate changes for #<<" do
52
- assert_equal [9],get_changes(@ary){ @ary << 9}[:added]
53
- end
54
- should "calculate changes for #push, #unshift" do
55
- [:push,:unshift].each do|method|
56
- ary = @ary.dup
57
- assert_equal [1,2,3],get_changes(ary){ary.send(method,1,2,3)}[:added]
58
- end
59
- end
60
- should "calculate changes for #concat" do
61
- assert_equal [1,2,3],get_changes(@ary){@ary.concat([1,2,3])}[:added]
62
- end
63
- should "calculate changes for insert" do
64
- assert_equal [3,4,5],get_changes(@ary){@ary.insert(2,3,4,5)}[:added]
65
- end
66
- should "calculate changes for delete" do
67
- assert_equal [2],get_changes(@ary){@ary.delete(2)}[:removed]
68
- end
69
- should "calculate changes for delete_at" do
70
- assert_equal [2],get_changes(@ary){@ary.delete_at(1)}[:removed]
71
- end
72
- should "calculate changes for delete_if, reject!" do
73
- [:delete_if, :reject!].each do |method|
74
- ary = @ary.dup
75
- assert_equal [2], get_changes(ary){ary.send(method){|i|i%2==0}}[:removed]
76
- end
77
- end
78
- should "calculate changes for pop" do
79
- assert_equal [3], get_changes(@ary){@ary.pop}[:removed]
80
- end
81
- should "calculate changes for shift" do
82
- assert_equal [1], get_changes(@ary){@ary.shift}[:removed]
83
- end
84
- should "calculate changes for clear" do
85
- assert_equal [1,2,3], get_changes(@ary){@ary.clear}[:removed]
86
- end
87
- should "calculate changes for compact!" do
88
- @ary = [1,2,nil,3,nil,4].tap{|a|a.make_observable}
89
- assert_equal [nil], get_changes(@ary){@ary.compact!}[:removed]
90
- end
91
- should "calculate changes for slice!" do
92
- assert_equal [2,3], get_changes(@ary){@ary.slice!(1,2)}[:removed]
93
- end
94
- should "calculate changes for uniq!" do
95
- @ary = [1,2,2,3,3,4,4,5].tap{|a|a.make_observable}
96
- assert_equal [], get_changes(@ary){@ary.uniq!}[:removed]
97
- end
98
- should "calculate changes for replace" do
99
- assert_equal({:removed=>@ary.dup,:added=>[4,5,6,7]}, get_changes(@ary){@ary.replace([4,5,6,7])})
100
- end
101
- should "calculate changes for []=" do
102
- assert_equal [6,7,8,9], get_changes(@ary){@ary[3,4]=[6,7,8,9]}[:added]
103
- end
104
- should "calculated changes for []= when []= is a modification method" do
105
- assert_equal({:removed=>[1],:added=>[9]},get_changes(@ary){@ary[0]=9})
106
- end
107
- should "return the original array as changes for other modification methods of array" do
108
- [:collect!, :map!, :flatten!, :reverse!, :sort!].each do |method|
109
- ary = @ary.dup
110
- assert_equal({:removed=>ary.dup, :added=>ary.dup.tap{|a|a.send(method)}}, get_changes(ary){ary.send(method)})
111
- end
112
- end
113
- should "return the original array as changes for fill" do
114
- assert_equal({:removed=>@ary.dup, :added=>@ary.dup.fill("*")}, get_changes(@ary){@ary.fill("*")})
115
- end
116
- end
117
- end
118
-
119
- def args_for(method)
120
- case method
121
- when :<<, :push, :unshift, :delete, :delete_at then [1]
122
- when :concat, :replace then [[1,2]]
123
- when :fill then ["*"]
124
- when :insert, :"[]=", :slice! then [1,1]
125
- when :flatten!, :collect!, :map!, :reverse!, :sort!,
126
- :clear, :compact!, :pop, :reject!, :uniq!, :delete_if, :shift then nil
127
- end
128
- end
129
-
130
- def get_changes(ary)
131
- changes = []
132
- sub = ary.subscribe(/after/){|_,args|changes << args.changes}
133
- yield
134
- ary.unsubscribe(sub)
135
- changes.pop
136
- end
1
+ require "test_helper"
2
+
3
+ class TestArrayWatcher < Test::Unit::TestCase
4
+ context "An array which has included Observables::ArrayWatcher" do
5
+ setup do
6
+ @ary = Array.new([1,2,3]).tap do |a|
7
+ a.make_observable
8
+ end
9
+ end
10
+
11
+ should "notify observers of any change that adds elements to itself" do
12
+ before_methods, after_methods = [],[]
13
+ method_list = Observables::ArrayWatcher::ADD_METHODS
14
+ @ary.subscribe(/before_added/){|_,args|before_methods<<args[:trigger]}
15
+ @ary.subscribe(/after_added/) {|_,args|after_methods<<args[:trigger]}
16
+ method_list.each do |method|
17
+ @ary.send(method,*args_for(method))
18
+ end
19
+
20
+ assert_equal method_list, before_methods
21
+ assert_equal method_list, after_methods
22
+ end
23
+
24
+ should "notify observers of any change that modifies elements" do
25
+ before_methods, after_methods = [],[]
26
+ method_list = Observables::ArrayWatcher::MODIFIER_METHODS
27
+ @ary.subscribe(/before_modified/){|_,args|before_methods<<args[:trigger]}
28
+ @ary.subscribe(/after_modified/) {|_,args|after_methods<<args[:trigger]}
29
+ method_list.each do |method|
30
+ args = args_for(method)
31
+ args ? @ary.send(method,*args) : @ary.send(method)
32
+ end
33
+ assert_equal method_list, before_methods
34
+ assert_equal method_list, after_methods
35
+ end
36
+
37
+ should "notify observers of any change that removes elements" do
38
+ before_methods, after_methods = [],[]
39
+ method_list = Observables::ArrayWatcher::REMOVE_METHODS
40
+ @ary.subscribe(/before_removed/){|_,args|before_methods<<args[:trigger]}
41
+ @ary.subscribe(/after_removed/) {|_,args|after_methods<<args[:trigger]}
42
+ method_list.each do |method|
43
+ args = args_for(method)
44
+ args ? @ary.send(method,*args) : @ary.send(method)
45
+ end
46
+ assert_equal method_list, before_methods
47
+ assert_equal method_list, after_methods
48
+ end
49
+
50
+ context "Calling #changes on the event args" do
51
+ should "calculate changes for #<<" do
52
+ assert_equal [9],get_changes(@ary){ @ary << 9}[:added]
53
+ end
54
+ should "calculate changes for #push, #unshift" do
55
+ [:push,:unshift].each do|method|
56
+ ary = @ary.dup
57
+ assert_equal [1,2,3],get_changes(ary){ary.send(method,1,2,3)}[:added]
58
+ end
59
+ end
60
+ should "calculate changes for #concat" do
61
+ assert_equal [1,2,3],get_changes(@ary){@ary.concat([1,2,3])}[:added]
62
+ end
63
+ should "calculate changes for insert" do
64
+ assert_equal [3,4,5],get_changes(@ary){@ary.insert(2,3,4,5)}[:added]
65
+ end
66
+ should "calculate changes for delete" do
67
+ assert_equal [2],get_changes(@ary){@ary.delete(2)}[:removed]
68
+ end
69
+ should "calculate changes for delete_at" do
70
+ assert_equal [2],get_changes(@ary){@ary.delete_at(1)}[:removed]
71
+ end
72
+ should "calculate changes for delete_if, reject!" do
73
+ [:delete_if, :reject!].each do |method|
74
+ ary = @ary.dup
75
+ assert_equal [2], get_changes(ary){ary.send(method){|i|i%2==0}}[:removed]
76
+ end
77
+ end
78
+ should "calculate changes for pop" do
79
+ assert_equal [3], get_changes(@ary){@ary.pop}[:removed]
80
+ end
81
+ should "calculate changes for shift" do
82
+ assert_equal [1], get_changes(@ary){@ary.shift}[:removed]
83
+ end
84
+ should "calculate changes for clear" do
85
+ assert_equal [1,2,3], get_changes(@ary){@ary.clear}[:removed]
86
+ end
87
+ should "calculate changes for compact!" do
88
+ @ary = [1,2,nil,3,nil,4].tap{|a|a.make_observable}
89
+ assert_equal [nil], get_changes(@ary){@ary.compact!}[:removed]
90
+ end
91
+ should "calculate changes for slice!" do
92
+ assert_equal [2,3], get_changes(@ary){@ary.slice!(1,2)}[:removed]
93
+ end
94
+ should "calculate changes for uniq!" do
95
+ @ary = [1,2,2,3,3,4,4,5].tap{|a|a.make_observable}
96
+ assert_equal [], get_changes(@ary){@ary.uniq!}[:removed]
97
+ end
98
+ should "calculate changes for replace" do
99
+ assert_equal({:removed=>@ary.dup,:added=>[4,5,6,7]}, get_changes(@ary){@ary.replace([4,5,6,7])})
100
+ end
101
+ should "calculate changes for []=" do
102
+ assert_equal [6,7,8,9], get_changes(@ary){@ary[3,4]=[6,7,8,9]}[:added]
103
+ end
104
+ should "calculated changes for []= when []= is a modification method" do
105
+ assert_equal({:removed=>[1],:added=>[9]},get_changes(@ary){@ary[0]=9})
106
+ end
107
+ should "return the original array as changes for other modification methods of array" do
108
+ [:collect!, :map!, :flatten!, :reverse!, :sort!].each do |method|
109
+ ary = @ary.dup
110
+ assert_equal({:removed=>ary.dup, :added=>ary.dup.tap{|a|a.send(method)}}, get_changes(ary){ary.send(method)})
111
+ end
112
+ end
113
+ should "return the original array as changes for fill" do
114
+ assert_equal({:removed=>@ary.dup, :added=>@ary.dup.fill("*")}, get_changes(@ary){@ary.fill("*")})
115
+ end
116
+ end
117
+ end
118
+
119
+ def args_for(method)
120
+ case method
121
+ when :<<, :push, :unshift, :delete, :delete_at then [1]
122
+ when :concat, :replace then [[1,2]]
123
+ when :fill then ["*"]
124
+ when :insert, :"[]=", :slice! then [1,1]
125
+ when :flatten!, :collect!, :map!, :reverse!, :sort!,
126
+ :clear, :compact!, :pop, :reject!, :uniq!, :delete_if, :shift then nil
127
+ end
128
+ end
129
+
130
+ def get_changes(ary)
131
+ changes = []
132
+ sub = ary.subscribe(/after/){|_,args|changes << args.changes}
133
+ yield
134
+ ary.unsubscribe(sub)
135
+ changes.pop
136
+ end
137
137
  end