observables 0.1.1 → 0.1.2

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.
@@ -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