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 ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.swp
19
+ *.swo
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2-p180@em-dextras --create
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in em-dextras.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module Tyrrell
4
+ VERSION = '0.0.7'
5
+ end
@@ -0,0 +1,10 @@
1
+ require "em-dextras/spec/event_machine_probes"
2
+ require "em-dextras/spec/spec_matchers.rb"
3
+
4
+ require "eventmachine"
5
+
6
+ module EMDextras
7
+ module Spec
8
+ # Your code goes here...
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Em
2
+ module Dextras
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
data/lib/em-dextras.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "em-dextras/version"
2
+
3
+ require "em-dextras/chains"
4
+ require "em-dextras/chains/synchronous_stage"
5
+
6
+ require "eventmachine"
7
+
8
+ module EMDextras
9
+ # Your code goes here...
10
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ require './lib/em-dextras'
2
+
3
+ require 'em-dextras/spec'
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