em-sequence 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ gem "hash-utils", ">= 0.10.0"
5
+ gem "eventmachine", ">= 0.12.10"
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ eventmachine (0.12.10)
5
+ git (1.2.5)
6
+ hash-utils (0.10.0)
7
+ jeweler (1.5.2)
8
+ bundler (~> 1.0.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ rake (0.8.7)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ bundler (~> 1.0.0)
18
+ eventmachine (>= 0.12.10)
19
+ hash-utils (>= 0.10.0)
20
+ jeweler (~> 1.5.2)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ EventMachine Sequencer
2
+ ======================
3
+
4
+ **em-sequence** provides third approach to [EventMachine][4] lightweight
5
+ concurrency. Runs declared methods and blocks in sequence, each in one
6
+ tick. So allows calls chaining with keeping the EventMachine multiplexing
7
+ facility on.
8
+
9
+ See an example. For first, define some (of sure, slightly non-sense) calculator class:
10
+
11
+ class Calculator
12
+ def some_method(var, &block)
13
+ block.call(1, var)
14
+ end
15
+
16
+ def other_method(x, y, &block)
17
+ block.call(x + y)
18
+ end
19
+
20
+ def another_method(z, &block)
21
+ block.call(z ** 2)
22
+ end
23
+ end
24
+
25
+ And then declare and run multiplexed code:
26
+
27
+ EM::run do
28
+ EM::Sequence::new(Calculator::new).declare {
29
+
30
+ # variable declaration
31
+ variable :var, 3
32
+
33
+ # method call declaration
34
+ some_method(:var) { [:x, :y] } # | TICK 1
35
+ # V
36
+ # inline block declaration and definition
37
+ block(:x, :y) do |x, y| # | TICK 2
38
+ {:x => x + 1, :y => y + 1} # |
39
+ end # V
40
+
41
+ # some other methods
42
+ other_method(:x, :y) { :x } # V TICK 3
43
+ another_method(:x) # V TICK 4
44
+
45
+ }.run! do |result| # | TICK 5
46
+ puts result.inspect # |
47
+ end # V
48
+ end
49
+
50
+ It will print out the number `36`. It's the same as linear
51
+ non-multiplexed (and non-callbacked calculator):
52
+
53
+ # variable declaration # | TICK 1
54
+ calc = Calculator::new # |
55
+ var = 3 # |
56
+ # |
57
+ # method call declaration # |
58
+ x, y = calc.some_method(var) # |
59
+ # |
60
+ # inline block declaration and definition # |
61
+ x += 1 # |
62
+ y += 1 # |
63
+ # |
64
+ # some other methods # |
65
+ x = calc.other_method(x, y) # |
66
+ result = calc.another_method(x) # |
67
+ # |
68
+ puts result.inspect # V
69
+
70
+
71
+ Contributing
72
+ ------------
73
+
74
+ 1. Fork it.
75
+ 2. Create a branch (`git checkout -b 20101220-my-change`).
76
+ 3. Commit your changes (`git commit -am "Added something"`).
77
+ 4. Push to the branch (`git push origin 20101220-my-change`).
78
+ 5. Create an [Issue][2] with a link to your branch.
79
+ 6. Enjoy a refreshing Diet Coke and wait.
80
+
81
+ Copyright
82
+ ---------
83
+
84
+ Copyright © 2011 [Martin Kozák][3]. See `LICENSE.txt` for
85
+ further details.
86
+
87
+ [2]: http://github.com/martinkozak/em-sequence/issues
88
+ [3]: http://www.martinkozak.net/
89
+ [4]: http://rubyeventmachine.com/
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+ require 'rake'
12
+
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = "em-sequence"
17
+ gem.homepage = "https://github.com/martinkozak/em-sequence"
18
+ gem.license = "MIT"
19
+ gem.summary = "Third approach to EventMachine lightweight concurrency. Runs declared methods and blocks in sequence, each in one tick. So allows calls chaining with keeping the EventMachine multiplexing facility on."
20
+ gem.email = "martinkozak@martinkozak.net"
21
+ gem.authors = ["Martin Kozák"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/rdoctask'
30
+ Rake::RDocTask.new do |rdoc|
31
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
32
+
33
+ rdoc.rdoc_dir = 'rdoc'
34
+ rdoc.title = "qrpc #{version}"
35
+ rdoc.rdoc_files.include('README*')
36
+ rdoc.rdoc_files.include('lib/**/*.rb')
37
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{em-sequence}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Martin Kozák"]
12
+ s.date = %q{2011-02-23}
13
+ s.email = %q{martinkozak@martinkozak.net}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE.txt",
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "LICENSE.txt",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "em-sequence.gemspec",
27
+ "lib/em-sequence.rb",
28
+ "lib/em-sequence/block.rb",
29
+ "lib/em-sequence/method.rb",
30
+ "test.rb"
31
+ ]
32
+ s.homepage = %q{https://github.com/martinkozak/em-sequence}
33
+ s.licenses = ["MIT"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.5.2}
36
+ s.summary = %q{Third approach to EventMachine lightweight concurrency. Runs declared methods and blocks in sequence, each in one tick. So allows calls chaining with keeping the EventMachine multiplexing facility on.}
37
+
38
+ if s.respond_to? :specification_version then
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<hash-utils>, [">= 0.10.0"])
43
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
44
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
45
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
46
+ else
47
+ s.add_dependency(%q<hash-utils>, [">= 0.10.0"])
48
+ s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
49
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
50
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
51
+ end
52
+ else
53
+ s.add_dependency(%q<hash-utils>, [">= 0.10.0"])
54
+ s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
55
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
56
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
57
+ end
58
+ end
59
+
@@ -0,0 +1,167 @@
1
+ # encoding: utf-8
2
+ # (c) 2011 Martin Kozák
3
+
4
+ require 'eventmachine'
5
+ require 'hash-utils/hash'
6
+ require 'em-sequence/block'
7
+ require 'em-sequence/method'
8
+
9
+ ##
10
+ # Main EventMachine module.
11
+ # @see
12
+ #
13
+
14
+ module EM
15
+
16
+ ##
17
+ # EventMachine sequence runner.
18
+ #
19
+
20
+ class Sequence
21
+
22
+ ##
23
+ # Holds target instance of the sequencer.
24
+ # @return [Object]
25
+ #
26
+
27
+ attr_accessor :target
28
+ @target
29
+
30
+ ##
31
+ # Holds required calls stack. (So in fact sequence itself.)
32
+ # @return [Array]
33
+ #
34
+
35
+ attr_accessor :stack
36
+ @stack
37
+
38
+ ##
39
+ # Holds array of variables available and defined during
40
+ # sequence run.
41
+ #
42
+ # @return [Hash]
43
+ #
44
+
45
+ attr_accessor :vars
46
+ @vars
47
+
48
+ ##
49
+ # Returns last run sequence item result.
50
+ # @return Object
51
+ #
52
+
53
+ attr_accessor :last
54
+ @last
55
+
56
+ ##
57
+ # Constructor.
58
+ # @param [Object] target target instance for the sequence
59
+
60
+ def initialize(target)
61
+ @target = target
62
+ @stack = [ ]
63
+ @vars = { }
64
+ end
65
+
66
+ ##
67
+ # Handles method definitions in sequence declaration.
68
+ #
69
+ # @param [Symbol] name method name
70
+ # @param [Array] args input variables specification
71
+ # @param [Proc] block block which should return array of
72
+ # returned variables names
73
+ #
74
+
75
+ def method_missing(name, *args, &block)
76
+ @stack << Method::new(@target, name, args, block)
77
+ end
78
+
79
+ ##
80
+ # Receives the sequence declaration.
81
+ #
82
+ # @example
83
+ # bar.declare do
84
+ #
85
+ # # variable declaration
86
+ # variable :var, 3
87
+ #
88
+ # # method call declaration
89
+ # some_method(:var) { [:x, :y] }
90
+ #
91
+ # # inline block declaration and definition
92
+ # block(:x, :y) do |x, y|
93
+ # {:x => x + 1, :y => y + 1}
94
+ # end
95
+ #
96
+ # # some other methods
97
+ # other_method(:x, :y) { :x }
98
+ # another_method(:x)
99
+ #
100
+ # end
101
+ #
102
+ # @param [Proc] block sequence declaration
103
+ # @return [Sequence] itself
104
+ #
105
+
106
+ def declare(&block)
107
+ self.instance_eval(&block)
108
+ return self
109
+ end
110
+
111
+ alias :decl :declare
112
+
113
+ ##
114
+ # Declares variable.
115
+ #
116
+ # @param [Symbol] name name of the variable
117
+ # @param [Object] value value of the variable
118
+ #
119
+
120
+ def variable(name, value)
121
+ @vars[name] = value
122
+ end
123
+
124
+ alias :var :variable
125
+
126
+ ##
127
+ # Declares block.
128
+ #
129
+ # Given block must return Hash with variable names and values.
130
+ # If block is last item of the sequence, return value will be
131
+ # used as return value of the sequence.
132
+ #
133
+ # @param [Array] args array of arguments
134
+ # @param [Proc] block body of block
135
+
136
+ def block(*args, &block)
137
+ @stack << Block::new(block, args)
138
+ end
139
+
140
+ alias :b :block
141
+ alias :blk :block
142
+
143
+ ##
144
+ # Runs the sequence.
145
+ #
146
+ # @param [Proc] callback callback for giving back result of lat
147
+ # item of the sequence
148
+ #
149
+
150
+ def run!(&callback)
151
+ worker = Proc::new do
152
+ if not @stack.empty?
153
+ @stack.shift.call(@vars) do |result, returning|
154
+ @vars.merge! result
155
+ @last = returning
156
+
157
+ EM::next_tick { worker.call() }
158
+ end
159
+ elsif not callback.nil?
160
+ EM::next_tick { callback.call(@last) }
161
+ end
162
+ end
163
+
164
+ worker.call()
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+ # (c) 2011 Martin Kozák
3
+
4
+ ##
5
+ # Main EventMachine module.
6
+ # @see
7
+ #
8
+
9
+ module EM
10
+
11
+ ##
12
+ # EventMachine sequence runner.
13
+ #
14
+
15
+ class Sequence
16
+
17
+ ##
18
+ # Block caller sequence item.
19
+ #
20
+
21
+ class Block
22
+
23
+ ##
24
+ # Holds body of the block.
25
+ # @return [Proc]
26
+ #
27
+
28
+ attr_accessor :body
29
+ @body
30
+
31
+ ##
32
+ # Input variables specification.
33
+ # @return [Array]
34
+ #
35
+
36
+ attr_accessor :args
37
+ @args
38
+
39
+ ##
40
+ # Constructor.
41
+ #
42
+ # @param [Proc] body body of the block
43
+ # @param [Array] args input variables specification
44
+ #
45
+
46
+ def initialize(body, args)
47
+ @body = body
48
+ @args = args
49
+ end
50
+
51
+ ##
52
+ # Calls the block.
53
+ #
54
+ # @param [Hash] vars data hash with current variables state
55
+ # @param [Proc] block block for giving back the call result
56
+ #
57
+
58
+ def call(vars, &block)
59
+ call_args = vars.values_at(*@args)
60
+ result = @body.call(*call_args)
61
+ block.call(result, result)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,106 @@
1
+ # encoding: utf-8
2
+ # (c) 2011 Martin Kozák
3
+
4
+ ##
5
+ # Main EventMachine module.
6
+ # @see
7
+ #
8
+
9
+ module EM
10
+
11
+ ##
12
+ # EventMachine sequence runner.
13
+ #
14
+
15
+ class Sequence
16
+
17
+ ##
18
+ # Method caller sequence item.
19
+ #
20
+
21
+ class Method
22
+
23
+ ##
24
+ # Holds method target object.
25
+ # @return [Object]
26
+ #
27
+
28
+ attr_accessor :target
29
+ @target
30
+
31
+ ##
32
+ # Holds method name.
33
+ # @return [Symbol]
34
+ #
35
+
36
+ attr_accessor :name
37
+ @name
38
+
39
+ ##
40
+ # Input variables specification.
41
+ # @return [Array]
42
+ #
43
+
44
+ attr_accessor :args
45
+ @args
46
+
47
+ ##
48
+ # Block which returns returned variables specification.
49
+ # @return [Proc]
50
+ #
51
+
52
+ attr_accessor :metablock
53
+ @metablock
54
+
55
+ ##
56
+ # Constructor.
57
+ #
58
+ # @param [Object] target target (parent) object instance of the call
59
+ # @param [Symbol] name method name
60
+ # @param [Array] args input variables specification
61
+ # @param [Proc] metablock returning variables specification block
62
+ #
63
+
64
+ def initialize(target, name, args, metablock)
65
+ @target = target
66
+ @name = name
67
+ @args = args
68
+ @metablock = metablock
69
+ end
70
+
71
+ ##
72
+ # Calls the method.
73
+ #
74
+ # @param [Hash] vars data hash with current variables state
75
+ # @param [Proc] block block for giving back the call result
76
+ #
77
+
78
+ def call(vars, &block)
79
+ call_args = vars.values_at(*@args)
80
+ @target.send(@name, *call_args) do |*returns|
81
+ result = Hash::combine(self.meta, returns)
82
+ block.call(result, returns.first)
83
+ end
84
+ end
85
+
86
+
87
+ protected
88
+
89
+ ##
90
+ # Returns returned values metainformations from metablock.
91
+ #
92
+
93
+ def meta
94
+ @meta = @metablock.call() \
95
+ if @meta.nil? and (not @metablock.nil?)
96
+ @meta = [@meta] \
97
+ if @meta and (not @meta.kind_of? Array)
98
+ @meta = [ ] \
99
+ if @meta.nil?
100
+
101
+ return @meta
102
+ end
103
+ end
104
+ end
105
+ end
106
+
data/test.rb ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+ # (c) 2011 Martin Kozák
4
+
5
+ $:.push("./lib")
6
+
7
+ require 'eventmachine'
8
+ require 'hash-utils/hash'
9
+ require 'em-sequence'
10
+ require 'riot'
11
+
12
+ test = nil
13
+
14
+
15
+ class Calculator
16
+ def some_method(var, &block)
17
+ block.call(1, var)
18
+ end
19
+
20
+ def other_method(x, y, &block)
21
+ block.call(x + y)
22
+ end
23
+
24
+ def another_method(z, &block)
25
+ block.call(z ** 2)
26
+ end
27
+ end
28
+
29
+ EM::run do
30
+ EM::Sequence::new(Calculator::new).declare {
31
+ # variable declaration
32
+ variable :var, 3
33
+
34
+ # method call declaration
35
+ some_method(:var) { [:x, :y] } # | TICK 1
36
+ # V
37
+ # inline block declaration and definition
38
+ block(:x, :y) do |x, y| # | TICK 2
39
+ {:x => x + 1, :y => y + 1} # |
40
+ end # V
41
+
42
+ # some other methods
43
+ other_method(:x, :y) { :x } # V TICK 3
44
+ another_method(:x) # V TICK 4
45
+ }.run! do |result|
46
+ test = result
47
+ EM::stop
48
+ end
49
+ end
50
+
51
+ context "Sequencer" do
52
+ setup { test }
53
+ asserts("complex sequence") { topic == 36 }
54
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-sequence
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - "Martin Koz\xC3\xA1k"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-23 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: hash-utils
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.10.0
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: eventmachine
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.12.10
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: bundler
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: jeweler
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 1.5.2
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
60
+ description:
61
+ email: martinkozak@martinkozak.net
62
+ executables: []
63
+
64
+ extensions: []
65
+
66
+ extra_rdoc_files:
67
+ - LICENSE.txt
68
+ - README.md
69
+ files:
70
+ - .document
71
+ - Gemfile
72
+ - Gemfile.lock
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - VERSION
77
+ - em-sequence.gemspec
78
+ - lib/em-sequence.rb
79
+ - lib/em-sequence/block.rb
80
+ - lib/em-sequence/method.rb
81
+ - test.rb
82
+ has_rdoc: true
83
+ homepage: https://github.com/martinkozak/em-sequence
84
+ licenses:
85
+ - MIT
86
+ post_install_message:
87
+ rdoc_options: []
88
+
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 2904173045210286528
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: "0"
106
+ requirements: []
107
+
108
+ rubyforge_project:
109
+ rubygems_version: 1.5.2
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Third approach to EventMachine lightweight concurrency. Runs declared methods and blocks in sequence, each in one tick. So allows calls chaining with keeping the EventMachine multiplexing facility on.
113
+ test_files: []
114
+