em-dextras 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.
- data/.gitignore +19 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Guardfile +24 -0
- data/LICENSE +22 -0
- data/README.md +37 -0
- data/Rakefile +2 -0
- data/em-dextras.gemspec +24 -0
- data/lib/em-dextras/chains/synchronous_stage.rb +14 -0
- data/lib/em-dextras/chains.rb +78 -0
- data/lib/em-dextras/spec/event_machine_probes.rb +66 -0
- data/lib/em-dextras/spec/spec_matchers.rb +73 -0
- data/lib/em-dextras/spec/version.rb +5 -0
- data/lib/em-dextras/spec.rb +10 -0
- data/lib/em-dextras/version.rb +5 -0
- data/lib/em-dextras.rb +10 -0
- data/spec/em-dextras/chains/synchronous_stage_spec.rb +40 -0
- data/spec/em-dextras/chains_spec.rb +154 -0
- data/spec/spec_helper +0 -0
- data/spec/spec_helper.rb +3 -0
- metadata +150 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2-p180@em-dextras --create
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec' do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara features specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
24
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Rafael de F. Ferreira
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Em::Dextras
|
2
|
+
Utilities to help working with EventMachine Deferrables. Includes probes for
|
3
|
+
asynchronous tests and a DSL to chain deferrables.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'em-dextras'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install em-dextras
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Documentation is currently lacking, fixing this is our number 1 priority.
|
22
|
+
|
23
|
+
The project offers:
|
24
|
+
* A DSL to structure asynchronous computations, inspired by [SoundCloud empipelines](https://github.com/soundcloud/empipelines)
|
25
|
+
and [future composition](http://code.technically.us/post/17965128229/fables-of-the-reconstruction-part-3-leibniz-saw-all)
|
26
|
+
* Methods to help test deferrable based code
|
27
|
+
- Low-level probing
|
28
|
+
- Syntatic sugar as RSpec matchers
|
29
|
+
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
1. Fork it
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
35
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
37
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/em-dextras.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/em-dextras/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Rafael de F. Ferreira"]
|
6
|
+
gem.email = ["public@rafaelferreira.net"]
|
7
|
+
gem.description = %q{Utilities to help working with EventMachine deferrables.}
|
8
|
+
gem.summary = %q{Utilities to help working with EventMachine Deferrables. Includes probes for asynchronous tests and a DSL to chain deferrables.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "em-dextras"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Em::Dextras::VERSION
|
17
|
+
|
18
|
+
gem.add_runtime_dependency("eventmachine", [">= 0.12.10"])
|
19
|
+
gem.add_development_dependency("rspec")
|
20
|
+
|
21
|
+
gem.add_development_dependency("guard")
|
22
|
+
gem.add_development_dependency("guard-rspec")
|
23
|
+
gem.add_development_dependency("rb-inotify")
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module EMDextras::Chains::SynchronousStage
|
2
|
+
def invoke(input)
|
3
|
+
raise NotImplementedError.new("You must implement #invoke.")
|
4
|
+
end
|
5
|
+
|
6
|
+
def todo(input)
|
7
|
+
begin
|
8
|
+
value = invoke(input)
|
9
|
+
EMDextras::Chains::Deferrables.succeeded value
|
10
|
+
rescue => exception
|
11
|
+
EMDextras::Chains::Deferrables.failed exception
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module EMDextras
|
2
|
+
module Chains
|
3
|
+
module Deferrables
|
4
|
+
def self.succeeded(*args)
|
5
|
+
deferrable = EventMachine::DefaultDeferrable.new
|
6
|
+
deferrable.succeed(*args)
|
7
|
+
deferrable
|
8
|
+
end
|
9
|
+
def self.failed(*args)
|
10
|
+
deferrable = EventMachine::DefaultDeferrable.new
|
11
|
+
deferrable.fail(*args)
|
12
|
+
deferrable
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
PipeSetup = Struct.new(:monitoring, :options) do
|
17
|
+
def inform_exception!(error_value, stage)
|
18
|
+
self.monitoring.inform_exception! error_value, stage
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.pipe(zero, monitoring, stages, options = {})
|
23
|
+
run_chain zero, stages, PipeSetup.new(monitoring, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.run_chain input, stages, pipe_setup
|
27
|
+
return if stages.empty?
|
28
|
+
|
29
|
+
stage, *rest = *stages
|
30
|
+
|
31
|
+
puts "Running #{stage}(#{input})" if pipe_setup.options[:debug]
|
32
|
+
|
33
|
+
if stage == :split
|
34
|
+
split_chain(input, rest, pipe_setup)
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
deferrable = call(stage, input, pipe_setup)
|
40
|
+
deferrable.callback do |value|
|
41
|
+
run_chain value, rest, pipe_setup
|
42
|
+
end
|
43
|
+
deferrable.errback do |error_value|
|
44
|
+
pipe_setup.inform_exception! error_value, stage
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def self.split_chain input, rest, pipe_setup
|
50
|
+
new_options = pipe_setup.options.clone
|
51
|
+
|
52
|
+
context = new_options[:context]
|
53
|
+
if context && context.respond_to?(:split)
|
54
|
+
new_options[:context] = context.split
|
55
|
+
end
|
56
|
+
|
57
|
+
new_pipe_setup = PipeSetup.new(pipe_setup.monitoring, new_options)
|
58
|
+
|
59
|
+
unless input.respond_to? :each
|
60
|
+
pipe_setup.inform_exception! ArgumentError.new(":split stage expects enumerable input. \"#{input}\" is not enumerable."), :split
|
61
|
+
return
|
62
|
+
end
|
63
|
+
input.each do |value|
|
64
|
+
run_chain value, rest, new_pipe_setup
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.call(stage, input, pipe_setup)
|
69
|
+
todo_method = stage.method(:todo)
|
70
|
+
case todo_method.arity
|
71
|
+
when 1
|
72
|
+
stage.todo(input)
|
73
|
+
when 2
|
74
|
+
stage.todo(input, pipe_setup.options[:context])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
# Receives two blocks as options: :action and :check.
|
3
|
+
# The :action block should trigger an asynchronous operation, or in other words,
|
4
|
+
# it should take a callback block as a parameter.
|
5
|
+
# If the :action block is not given, a default action
|
6
|
+
# is provided, that simply schedules the callback to
|
7
|
+
# be run on the next tick of the event machine.
|
8
|
+
#
|
9
|
+
# The :check block should verify some desired property (it should indicate
|
10
|
+
# a failed verification by throwing an exception). The :check block will be
|
11
|
+
# called from the callback given to :action. One way to think about it is that
|
12
|
+
# the :check block is what you'd directly pass as a callback to the action block
|
13
|
+
# were it not for the need to probe periodically.
|
14
|
+
#
|
15
|
+
# If the verification done by the :check block succeeds, this method will stop
|
16
|
+
# EventMachine and return normally. If the verification fails, it will retry after
|
17
|
+
# an interval (configurable via the :interval option). This will happen until
|
18
|
+
# a timeout expires (configurable via the :timeout option, in seconds), in
|
19
|
+
# which case the method will raise the verification exception
|
20
|
+
def probe_event_machine(options)
|
21
|
+
action = options[:action] || forwarding_action
|
22
|
+
check = options[:check]
|
23
|
+
timeout = options[:timeout] || 5
|
24
|
+
interval = options[:interval] || 0.2
|
25
|
+
debug = !!options[:debug]
|
26
|
+
|
27
|
+
probe_start_time = Time.new
|
28
|
+
|
29
|
+
exceptions = []
|
30
|
+
code = Proc.new do |arguments|
|
31
|
+
begin
|
32
|
+
puts "call to check" if debug
|
33
|
+
check.call(arguments)
|
34
|
+
puts "check succeeded, will stop event loop" if debug
|
35
|
+
EM.stop_event_loop
|
36
|
+
rescue Exception => exception
|
37
|
+
puts "check failed" if debug
|
38
|
+
exceptions << exception
|
39
|
+
if (Time.now - probe_start_time) < timeout
|
40
|
+
puts "will retry action after #{interval} seconds" if debug
|
41
|
+
EM.add_timer(interval) do
|
42
|
+
puts "retrying action" if debug
|
43
|
+
action.call(code)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
puts "timeout exceeded. stop trying" if debug
|
47
|
+
EM.stop_event_loop
|
48
|
+
raise MultipleExceptions, "Exceptions while probing:\n\t#{exceptions.map(&:message).uniq.join(";\nand exception:\t")}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
puts "initial call to action" if debug
|
54
|
+
action.call(code)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class MultipleExceptions < RuntimeError
|
59
|
+
end
|
60
|
+
|
61
|
+
def forwarding_action
|
62
|
+
return Proc.new {|callback|
|
63
|
+
EM.next_tick Proc.new { callback.call([])}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
if defined?(RSpec)
|
2
|
+
RSpec::Matchers.define :succeed_with do |expected|
|
3
|
+
match_unless_raises Exception do |actual_deferred|
|
4
|
+
resolved_value = nil
|
5
|
+
actual_deferred.callback do |value|
|
6
|
+
resolved_value = value
|
7
|
+
end
|
8
|
+
actual_deferred.errback do |error|
|
9
|
+
if error.is_a? Exception
|
10
|
+
raise error
|
11
|
+
else
|
12
|
+
raise "Callback error: #{error.inspect}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
probe_event_machine :check => (lambda do |ignored|
|
17
|
+
resolved_value.should == expected
|
18
|
+
end), :timeout => 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
RSpec::Matchers.define :be_successful do |expected|
|
23
|
+
match_unless_raises Exception do |actual_deferred|
|
24
|
+
done = false
|
25
|
+
actual_deferred.callback do
|
26
|
+
done = true
|
27
|
+
end
|
28
|
+
actual_deferred.errback do |error|
|
29
|
+
if error.is_a? Exception
|
30
|
+
raise error
|
31
|
+
else
|
32
|
+
raise "Callback error: #{error.inspect}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
probe_event_machine :check => (lambda do |ignored|
|
37
|
+
done
|
38
|
+
end), :timeout => 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
RSpec::Matchers.define :be_a_failure do |expected|
|
43
|
+
match_unless_raises Exception do |actual_deferred|
|
44
|
+
done = false
|
45
|
+
actual_deferred.callback do
|
46
|
+
raise "Expected error but was success"
|
47
|
+
end
|
48
|
+
actual_deferred.errback do |error|
|
49
|
+
done = true
|
50
|
+
end
|
51
|
+
|
52
|
+
probe_event_machine :check => (lambda do |ignored|
|
53
|
+
done
|
54
|
+
end), :timeout => 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
RSpec::Matchers.define :fail_with do |expected|
|
59
|
+
match_unless_raises Exception do |actual_deferred|
|
60
|
+
resolved_value = nil
|
61
|
+
actual_deferred.errback do |value|
|
62
|
+
resolved_value = value
|
63
|
+
end
|
64
|
+
actual_deferred.callback do |error|
|
65
|
+
raise "Should have failed, but succedded with #{error}"
|
66
|
+
end
|
67
|
+
|
68
|
+
probe_event_machine :check => (lambda do |ignored|
|
69
|
+
resolved_value.should == expected
|
70
|
+
end), :timeout => 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/em-dextras.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path('spec/spec_helper')
|
2
|
+
|
3
|
+
describe EMDextras::Chains::SynchronousStage do
|
4
|
+
class PasstroughSynchronousStage
|
5
|
+
include EMDextras::Chains::SynchronousStage
|
6
|
+
def invoke(input)
|
7
|
+
"Got #{input}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class FailingSynchronousStage
|
12
|
+
include EMDextras::Chains::SynchronousStage
|
13
|
+
def invoke(input_exception)
|
14
|
+
raise input_exception
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "success:" do
|
19
|
+
subject { PasstroughSynchronousStage.new }
|
20
|
+
|
21
|
+
it "should pass the return value of the invoke method to the next stage" do
|
22
|
+
EM.run do
|
23
|
+
deferred = subject.todo "the input"
|
24
|
+
deferred.should succeed_with "Got the input"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "failure:" do
|
30
|
+
subject { FailingSynchronousStage.new }
|
31
|
+
|
32
|
+
it "should return a failed deferred" do
|
33
|
+
EM.run do
|
34
|
+
exception = ArgumentError.new "an exception"
|
35
|
+
deferred = subject.todo exception
|
36
|
+
deferred.should fail_with exception
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EMDextras::Chains do
|
4
|
+
class ProduceStage
|
5
|
+
def initialize(result)
|
6
|
+
@result = result
|
7
|
+
end
|
8
|
+
|
9
|
+
def todo(ignored_input)
|
10
|
+
EMDextras::Chains::Deferrables.succeeded @result
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class SpyStage
|
15
|
+
def initialize(inputs)
|
16
|
+
@inputs = inputs
|
17
|
+
end
|
18
|
+
|
19
|
+
def todo(input)
|
20
|
+
@inputs << input
|
21
|
+
EMDextras::Chains::Deferrables.succeeded input
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ErrorStage
|
26
|
+
def todo(input)
|
27
|
+
EMDextras::Chains::Deferrables.failed "Failed with #{input}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class StopStage
|
32
|
+
def todo(input)
|
33
|
+
EM.stop
|
34
|
+
EMDextras::Chains::Deferrables.succeeded input
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ContextualStage
|
39
|
+
attr :context
|
40
|
+
def todo(input, context)
|
41
|
+
@context = context
|
42
|
+
EMDextras::Chains::Deferrables.succeeded input
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:monitoring) { mock.as_null_object }
|
47
|
+
|
48
|
+
it "should chain todo stages" do
|
49
|
+
EM.run do
|
50
|
+
inputs = []
|
51
|
+
|
52
|
+
EMDextras::Chains.pipe("input", monitoring, [
|
53
|
+
SpyStage.new(inputs),
|
54
|
+
SpyStage.new(inputs),
|
55
|
+
StopStage.new
|
56
|
+
])
|
57
|
+
|
58
|
+
inputs.should == ["input", "input"]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should notify monitoring of any exceptions" do
|
63
|
+
EM.run do
|
64
|
+
monitoring.should_receive(:inform_exception!) do
|
65
|
+
EM.stop
|
66
|
+
end
|
67
|
+
|
68
|
+
EM.add_timer(2) do
|
69
|
+
fail("timeout")
|
70
|
+
end
|
71
|
+
|
72
|
+
EMDextras::Chains.pipe("anything", monitoring, [ErrorStage.new]);
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should pass a 'context' object if given and the stage takes one" do
|
77
|
+
contextual_stage = ContextualStage.new
|
78
|
+
|
79
|
+
EM.run do
|
80
|
+
EMDextras::Chains.pipe("anything", monitoring, [
|
81
|
+
contextual_stage,
|
82
|
+
StopStage.new
|
83
|
+
], :context => "the context")
|
84
|
+
|
85
|
+
probe_event_machine :check => lambda {|x|
|
86
|
+
contextual_stage.context.should == "the context"
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when given a :split stage" do
|
92
|
+
context "and the input is enumberable" do
|
93
|
+
it "should invoke the next step the given number of times" do
|
94
|
+
EM.run do
|
95
|
+
final_inputs = []
|
96
|
+
|
97
|
+
EMDextras::Chains.pipe("anything", monitoring, [
|
98
|
+
ProduceStage.new([1,2,3]),
|
99
|
+
:split,
|
100
|
+
SpyStage.new(final_inputs),
|
101
|
+
StopStage.new
|
102
|
+
])
|
103
|
+
|
104
|
+
final_inputs.should =~ [1,2,3]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should split the given context" do
|
109
|
+
before = ContextualStage.new
|
110
|
+
after = ContextualStage.new
|
111
|
+
|
112
|
+
first_context = double("first context")
|
113
|
+
second_context = double("second context")
|
114
|
+
|
115
|
+
first_context.stub(:split).and_return second_context
|
116
|
+
|
117
|
+
EM.run do
|
118
|
+
EMDextras::Chains.pipe("anything", monitoring, [
|
119
|
+
before,
|
120
|
+
ProduceStage.new([1,2]),
|
121
|
+
:split,
|
122
|
+
after
|
123
|
+
], :context => first_context)
|
124
|
+
|
125
|
+
probe_event_machine :check => lambda {|x|
|
126
|
+
before.context.should == first_context
|
127
|
+
after.context.should == second_context
|
128
|
+
}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "and the input is not enumberable" do
|
134
|
+
it "will terminate the chain and report the error as an exception" do
|
135
|
+
EM.run do
|
136
|
+
monitoring.should_receive(:inform_exception!) do
|
137
|
+
EM.stop
|
138
|
+
end
|
139
|
+
|
140
|
+
EM.add_timer(2) do
|
141
|
+
fail("timeout")
|
142
|
+
end
|
143
|
+
|
144
|
+
EMDextras::Chains.pipe("anything", monitoring, [
|
145
|
+
ProduceStage.new(:not_enumberable_input),
|
146
|
+
:split,
|
147
|
+
SpyStage.new([]),
|
148
|
+
StopStage.new
|
149
|
+
])
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/spec/spec_helper
ADDED
File without changes
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-dextras
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rafael de F. Ferreira
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.12.10
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.12.10
|
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: guard
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
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: guard-rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
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
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rb-inotify
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Utilities to help working with EventMachine deferrables.
|
95
|
+
email:
|
96
|
+
- public@rafaelferreira.net
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- .rvmrc
|
103
|
+
- Gemfile
|
104
|
+
- Guardfile
|
105
|
+
- LICENSE
|
106
|
+
- README.md
|
107
|
+
- Rakefile
|
108
|
+
- em-dextras.gemspec
|
109
|
+
- lib/em-dextras.rb
|
110
|
+
- lib/em-dextras/chains.rb
|
111
|
+
- lib/em-dextras/chains/synchronous_stage.rb
|
112
|
+
- lib/em-dextras/spec.rb
|
113
|
+
- lib/em-dextras/spec/event_machine_probes.rb
|
114
|
+
- lib/em-dextras/spec/spec_matchers.rb
|
115
|
+
- lib/em-dextras/spec/version.rb
|
116
|
+
- lib/em-dextras/version.rb
|
117
|
+
- spec/em-dextras/chains/synchronous_stage_spec.rb
|
118
|
+
- spec/em-dextras/chains_spec.rb
|
119
|
+
- spec/spec_helper
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
homepage: ''
|
122
|
+
licenses: []
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ! '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 1.8.25
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: Utilities to help working with EventMachine Deferrables. Includes probes
|
145
|
+
for asynchronous tests and a DSL to chain deferrables.
|
146
|
+
test_files:
|
147
|
+
- spec/em-dextras/chains/synchronous_stage_spec.rb
|
148
|
+
- spec/em-dextras/chains_spec.rb
|
149
|
+
- spec/spec_helper
|
150
|
+
- spec/spec_helper.rb
|