rrx 0.0.1

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.
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Reactive::Observable do
4
+ include Lets
5
+
6
+ context 'timer(2000).push(timer(5000))' do
7
+ before do
8
+ pending
9
+ o1 = Reactive::Observable.timer(2000)
10
+ o2 = Reactive::Observable.timer(5000)
11
+ @s = o1.push(o2)
12
+ subscribe(@s)
13
+ end
14
+
15
+ it 'does not fire before first timer' do
16
+ observer[:on_next].should_not_receive(:call)
17
+ advance_by(1000)
18
+ end
19
+
20
+ it 'fires once after first timer runs' do
21
+ observer[:on_next].should_receive(:call).with(0)
22
+ advance_by(2001)
23
+ end
24
+
25
+ it 'fires once after first but before the pushed one' do
26
+ observer[:on_next].should_receive(:call).with(0)
27
+ advance_by(4001)
28
+ end
29
+
30
+ it 'fires twice once both timers have run' do
31
+ observer[:on_next].should_receive(:call).exactly(:twice).with(0)
32
+ advance_by(7001)
33
+ end
34
+
35
+ it 'doesn\'t fire any more after both timers have run' do
36
+ observer[:on_next].should_receive(:call).exactly(:twice).with(0)
37
+ advance_by(20001)
38
+ end
39
+
40
+ end
41
+
42
+ context 'interval(100).push(interval(222))' do
43
+ before do
44
+ o1 = Reactive::Observable.interval(100)
45
+ o2 = Reactive::Observable.interval(222)
46
+ @s = o1.push(o2)
47
+ @s.subscribe(observer)
48
+ end
49
+
50
+ it 'doesn\'t fire on partial interval' do
51
+ observer[:on_next].should_not_receive(:call)
52
+ advance_by(99)
53
+ end
54
+
55
+ it 'fires once when first interval passed' do
56
+ observer[:on_next].should_receive(:call).with(0)
57
+ advance_by(101)
58
+ end
59
+
60
+ it 'fires for pushed interval, but not for original interval' do
61
+ observer[:on_next].should_receive(:call).exactly(:twice).with(anything)
62
+ advance_by(230)
63
+ end
64
+ end
65
+
66
+
67
+ context 'when garbage collected' do
68
+ before do
69
+ o1 = Reactive::Observable.interval(100)
70
+ o2 = Reactive::Observable.interval(222)
71
+ @s = o1.push(o2)
72
+ @s.subscribe(observer)
73
+ remove_instance_variable(:@s)
74
+ ObjectSpace.garbage_collect
75
+ end
76
+ it 'unsubscribes' do
77
+ scheduler.advance_by(230)
78
+ end
79
+ end
80
+
81
+
82
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Reactive::Observable do
4
+ include Lets
5
+
6
+ context '#skip(3) on list(4..0)' do
7
+
8
+ before do
9
+ @s = Reactive::Observable.from_array([4,3,2,1,0]).skip(3)
10
+ end
11
+
12
+ #TODO send_call..with should accept arguments for each time. in this case 1, 0
13
+ it {
14
+ observer[:on_complete] = ->() {}
15
+ should send_call.exactly(2).times.with(kind_of(Fixnum)).to(observer, :on_next)
16
+ }
17
+ it {
18
+ observer[:on_next] = ->(v) {}
19
+ should send_call.with(no_args).to(observer, :on_complete)
20
+ }
21
+
22
+ after do
23
+ @s.subscribe(observer)
24
+ end
25
+
26
+
27
+ end
28
+
29
+
30
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Reactive::Observable do
4
+ include Lets
5
+
6
+ context '#timer(2000)' do
7
+ before do
8
+ @s = Reactive::Observable.timer(2000)
9
+ @s.subscribe(observer)
10
+ end
11
+
12
+ #TODO shared example?
13
+ it 'doesn\'t fire on subscribe' do
14
+ observer[:on_next].should_not_receive(:call)
15
+ end
16
+
17
+ it "doesn't fire before timer" do
18
+ observer[:on_next].should_not_receive(:call)
19
+ end
20
+
21
+ context 'timer has passed' do
22
+ advance_by(2001, ignore: :on_complete) {
23
+ should send_call.with(0).to(observer, :on_next)
24
+ }
25
+ advance_by(2001, ignore: :on_next) {
26
+ should send_call.to(observer, :on_complete)
27
+ }
28
+ end
29
+
30
+ context "timer x2 has passed" do
31
+ advance_by(4001, ignore: :on_complete) {
32
+ should send_call.with(0).to(observer, :on_next)
33
+ }
34
+ advance_by(4001, ignore: :on_next) {
35
+ should send_call.to(observer, :on_complete)
36
+ }
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,177 @@
1
+ require 'rrx'
2
+
3
+
4
+ class VirtualScheduler
5
+ attr_accessor :now
6
+
7
+ def initialize
8
+ restart
9
+ end
10
+
11
+ def schedule_periodic(at, action, wrapper = Reactive::Disposable::Wrapper.new)
12
+ return unless wrapper
13
+ callback = lambda do
14
+ new_at = action.()
15
+ if new_at #defined ~
16
+ schedule_periodic(new_at, action, wrapper)
17
+ else
18
+ wrapper.unwrap
19
+ end
20
+ end
21
+ wrapper.target = schedule_once(at, callback)
22
+ end
23
+
24
+ def schedule_once(at, action)
25
+ add_action(@now + at, action)
26
+ Reactive::Disposable::Closure.new { remove_action(action) }
27
+ end
28
+
29
+ def add_action(at, action)
30
+ @actions << [at, action]
31
+ end
32
+
33
+ def remove_action(action)
34
+ @actions.reject! {|at_ac| at_ac[1] == action }
35
+ end
36
+
37
+ def sort_actions
38
+ @actions.sort_by! {|at_ac| at_ac[0] }
39
+ end
40
+
41
+ def advance_by(ms)
42
+ max = @now + ms
43
+ while true
44
+ sort_actions
45
+ t, action = @actions[0]
46
+ break if t.nil?
47
+ break if t > max
48
+ @now = t
49
+ remove_action(action)
50
+ action.call
51
+ end
52
+ @now = max
53
+ end
54
+
55
+ def restart
56
+ @actions = []
57
+ @now = 0
58
+ end
59
+
60
+ end
61
+
62
+ class SendMessage
63
+ def initialize(method)
64
+ @method = method
65
+ end
66
+
67
+ def with(args)
68
+ @with = args
69
+ self
70
+ end
71
+
72
+ def exactly(times)
73
+ @exactly = times
74
+ self
75
+ end
76
+
77
+ def times
78
+ self
79
+ end
80
+
81
+ def to(object, attr)
82
+ @target = object[attr]
83
+ @name = attr
84
+ m = @target.should_receive(@method)
85
+ m = m.exactly(@exactly).times if @exactly
86
+ m.with(@with) if @with
87
+ self
88
+ end
89
+
90
+ def matches?(that)
91
+ true
92
+ end
93
+
94
+ def description
95
+ "call #{@name}#{ " with #{@with}" if @with }#{ " #{@exactly} times" if @exactly}"
96
+ end
97
+
98
+ end
99
+
100
+ def send_call()
101
+ SendMessage.new(:call)
102
+ end
103
+
104
+
105
+ #def error
106
+ # @error ||= []
107
+ #end
108
+
109
+ def restart
110
+ scheduler.restart
111
+ end
112
+
113
+ def advance_and_check_event_counts(events)
114
+ events.each {|event| advance_and_check_event_count(*event) }
115
+ end
116
+
117
+ def advance_and_check_event_count(advance_by = nil, e_nxt = 0, e_complete = 0, e_error = 0, opts= {})
118
+ [[:next_size, e_nxt], [:complete_size, e_complete], [:error_size, e_error]].each do |base, chg|
119
+ it do
120
+ expect {
121
+ instance_eval(&opts[:proc]) if opts[:proc]
122
+ scheduler.advance_by(advance_by)
123
+ }.to change(self, base).by(chg)
124
+ end
125
+ end
126
+ #[nxt.size, error.size, complete.size].should == [e_nxt, e_error, e_complete]
127
+ end
128
+
129
+ def next_size
130
+ nxt.size
131
+ end
132
+ def error_size
133
+ error.size
134
+ end
135
+ def complete_size
136
+ complete.size
137
+ end
138
+
139
+
140
+
141
+ def subscribe(observable)
142
+ observable.subscribe(
143
+ :on_next => ->(v) { nxt << v; },
144
+ :on_complete => ->() { complete << 1 },
145
+ :on_error => ->(e) { error << e }
146
+ )
147
+ end
148
+
149
+
150
+ def advance_by(ms, options = {}, &block)
151
+ if block
152
+ case options[:ignore]
153
+ when :on_next, :on_error
154
+ before { observer[options[:ignore]] = ->(v) {} }
155
+ when :on_complete
156
+ before { observer[:on_complete] = ->() {} }
157
+ end
158
+ after {
159
+ scheduler.advance_by(ms)
160
+ }
161
+ it &block
162
+ else
163
+ scheduler.advance_by(ms)
164
+ end
165
+ end
166
+
167
+ module Lets
168
+ def self.included(context)
169
+ context.let(:scheduler) { VirtualScheduler.new }
170
+ #context.let(:observer) { {on_next: "Double (next)", on_error: double('error'), on_complete: double('complete') } }
171
+ context.let(:observer) { {on_next: double('next'), on_error: double('error'), on_complete: double('complete') } }
172
+
173
+ context.before do
174
+ Reactive::Observable::Base.any_instance.stub(:scheduler).and_return(scheduler)
175
+ end
176
+ end
177
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rrx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Daniel Davis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: eventmachine
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: active_support
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: ! 'Reactive Extensions provide an enumerable-like interface to process
79
+ temporal data(events) with the eash usually reserved for structural Enumerables '
80
+ email:
81
+ - shoefish@gmail.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - examples/all.rb
92
+ - lib/Reactive/observable.rb
93
+ - lib/Reactive/observable/base.rb
94
+ - lib/Reactive/observable/composite.rb
95
+ - lib/Reactive/observable/double_wrapper.rb
96
+ - lib/Reactive/observable/empty.rb
97
+ - lib/Reactive/observable/first.rb
98
+ - lib/Reactive/observable/from_proc.rb
99
+ - lib/Reactive/observable/generate.rb
100
+ - lib/Reactive/observable/grep.rb
101
+ - lib/Reactive/observable/map.rb
102
+ - lib/Reactive/observable/merge.rb
103
+ - lib/Reactive/observable/push.rb
104
+ - lib/Reactive/observable/skip.rb
105
+ - lib/Reactive/observable/wrapper.rb
106
+ - lib/Reactive/observer.rb
107
+ - lib/Reactive/scheduler.rb
108
+ - lib/Reactive/version.rb
109
+ - lib/rrx.rb
110
+ - rrx.gemspec
111
+ - spec/observable/count_spec.rb
112
+ - spec/observable/first_spec.rb
113
+ - spec/observable/interval_spec.rb
114
+ - spec/observable/push_spec.rb
115
+ - spec/observable/skip_spec.rb
116
+ - spec/observable/timer_spec.rb
117
+ - spec/spec_helper.rb
118
+ homepage: https://github.com/emirikol/rrx
119
+ licenses: []
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 1.8.24
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: Ruby Reactive Extensions
142
+ test_files:
143
+ - spec/observable/count_spec.rb
144
+ - spec/observable/first_spec.rb
145
+ - spec/observable/interval_spec.rb
146
+ - spec/observable/push_spec.rb
147
+ - spec/observable/skip_spec.rb
148
+ - spec/observable/timer_spec.rb
149
+ - spec/spec_helper.rb