zmqmachine 0.3.0
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/.bnsignore +20 -0
- data/History.txt +21 -0
- data/README.rdoc +85 -0
- data/Rakefile +21 -0
- data/examples/fake_ftp.rb +242 -0
- data/examples/one_handed_ping_pong.rb +74 -0
- data/examples/ping_pong.rb +86 -0
- data/examples/pub_sub.rb +195 -0
- data/examples/throttled_ping_pong.rb +103 -0
- data/lib/zm/address.rb +70 -0
- data/lib/zm/deferrable.rb +209 -0
- data/lib/zm/exceptions.rb +45 -0
- data/lib/zm/message.rb +52 -0
- data/lib/zm/reactor.rb +458 -0
- data/lib/zm/sockets/base.rb +216 -0
- data/lib/zm/sockets/pair.rb +87 -0
- data/lib/zm/sockets/pub.rb +80 -0
- data/lib/zm/sockets/rep.rb +96 -0
- data/lib/zm/sockets/req.rb +96 -0
- data/lib/zm/sockets/sub.rb +83 -0
- data/lib/zm/sockets/xrep.rb +86 -0
- data/lib/zm/sockets/xreq.rb +86 -0
- data/lib/zm/sockets.rb +4 -0
- data/lib/zm/timers.rb +220 -0
- data/lib/zmqmachine.rb +76 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/zmqmachine_spec.rb +6 -0
- data/version.txt +1 -0
- data/zmqmachine.gemspec +48 -0
- metadata +133 -0
data/lib/zm/timers.rb
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Author:: Chuck Remes
|
4
|
+
# Homepage:: http://github.com/chuckremes/zmqmachine
|
5
|
+
# Date:: 20100602
|
6
|
+
#
|
7
|
+
#----------------------------------------------------------------------------
|
8
|
+
#
|
9
|
+
# Copyright (C) 2010 by Chuck Remes. All Rights Reserved.
|
10
|
+
# Email: cremes at mac dot com
|
11
|
+
#
|
12
|
+
# (The MIT License)
|
13
|
+
#
|
14
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
15
|
+
# a copy of this software and associated documentation files (the
|
16
|
+
# 'Software'), to deal in the Software without restriction, including
|
17
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
18
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
19
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
20
|
+
# the following conditions:
|
21
|
+
#
|
22
|
+
# The above copyright notice and this permission notice shall be
|
23
|
+
# included in all copies or substantial portions of the Software.
|
24
|
+
#
|
25
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
26
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
27
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
28
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
29
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
30
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
31
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
32
|
+
#
|
33
|
+
#---------------------------------------------------------------------------
|
34
|
+
#
|
35
|
+
#
|
36
|
+
|
37
|
+
module ZMQMachine
|
38
|
+
|
39
|
+
# Manages the addition and cancellation of all timers. Each #Reactor
|
40
|
+
# maintains its own set of timers; the timer belongs to the
|
41
|
+
# reactor context.
|
42
|
+
#
|
43
|
+
# This should never be instantiated directly
|
44
|
+
# by user code. A timer must be known to the #Reactor in which it
|
45
|
+
# is running, so use the #Reactor#oneshot_timer and
|
46
|
+
# #Reactor#periodical_timer convenience methods. It ensures that
|
47
|
+
# new timers are installed in the correct #Reactor.
|
48
|
+
#
|
49
|
+
class Timers
|
50
|
+
def initialize
|
51
|
+
@timers = SortedSet.new
|
52
|
+
end
|
53
|
+
|
54
|
+
# Adds a non-periodical, one-shot timer in order of
|
55
|
+
# first-to-fire to last-to-fire.
|
56
|
+
#
|
57
|
+
# Returns nil unless a +timer_proc+ or +blk+ are
|
58
|
+
# provided. There is no point to an empty timer that
|
59
|
+
# does nothing when fired.
|
60
|
+
#
|
61
|
+
def add_oneshot delay, timer_proc = nil, &blk
|
62
|
+
blk ||= timer_proc
|
63
|
+
return nil unless blk
|
64
|
+
|
65
|
+
timer = Timer.new self, delay, false, blk
|
66
|
+
@timers.add timer
|
67
|
+
timer
|
68
|
+
end
|
69
|
+
|
70
|
+
# Adds a periodical timer in order of
|
71
|
+
# first-to-fire to last-to-fire.
|
72
|
+
#
|
73
|
+
# Returns nil unless a +timer_proc+ or +blk+ are
|
74
|
+
# provided. There is no point to an empty timer that
|
75
|
+
# does nothing when fired.
|
76
|
+
#
|
77
|
+
def add_periodical delay, timer_proc = nil, &blk
|
78
|
+
blk ||= timer_proc
|
79
|
+
return nil unless blk
|
80
|
+
|
81
|
+
timer = Timer.new self, delay, true, blk
|
82
|
+
@timers.add timer
|
83
|
+
timer
|
84
|
+
end
|
85
|
+
|
86
|
+
# Cancel the +timer+.
|
87
|
+
#
|
88
|
+
# Returns +true+ when cancellation succeeds.
|
89
|
+
# Returns +false+ when it fails to find the
|
90
|
+
# given +timer+.
|
91
|
+
#
|
92
|
+
def cancel timer
|
93
|
+
@timers.delete(timer) ? true : false
|
94
|
+
end
|
95
|
+
|
96
|
+
# A convenience method that loops through all known timers
|
97
|
+
# and fires all of the expired timers.
|
98
|
+
#
|
99
|
+
#--
|
100
|
+
# Internally the list is sorted whenever a timer is added or
|
101
|
+
# deleted. It stops processing this list when the next timer
|
102
|
+
# is not yet expired; it knows all subsequent timers are not
|
103
|
+
# expired too.
|
104
|
+
#
|
105
|
+
def fire_expired
|
106
|
+
# all time is expected as milliseconds
|
107
|
+
now = Timers.now
|
108
|
+
save = []
|
109
|
+
|
110
|
+
# timers should be sorted by expiration time
|
111
|
+
@timers.delete_if do |timer|
|
112
|
+
break unless timer.expired?(now)
|
113
|
+
timer.fire
|
114
|
+
save << timer if timer.periodical?
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
# reinstate the periodicals; necessary to do in two steps
|
119
|
+
# since changing the timer.fire_time inside the loop would
|
120
|
+
# not retain proper ordering in the sorted set; re-adding it
|
121
|
+
# ensures the timer is in sorted order
|
122
|
+
save.each { |timer| @timers.add timer }
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns the current time using the following algo:
|
126
|
+
#
|
127
|
+
# (Time.now.to_f * 1000).to_i
|
128
|
+
#
|
129
|
+
# Added as a class method so that it can be overridden by a user
|
130
|
+
# who wants to provide their own time source. For example, a user
|
131
|
+
# could use a third-party gem that provides a better performing
|
132
|
+
# time source.
|
133
|
+
#
|
134
|
+
def self.now
|
135
|
+
(Time.now.to_f * 1000).to_i
|
136
|
+
end
|
137
|
+
|
138
|
+
# Convert Timers.now to a number usable by the Time class.
|
139
|
+
#
|
140
|
+
def self.now_converted
|
141
|
+
now / 1000.0
|
142
|
+
end
|
143
|
+
end # class Timers
|
144
|
+
|
145
|
+
|
146
|
+
# Used to track the specific expiration time and execution
|
147
|
+
# code for each timer.
|
148
|
+
#
|
149
|
+
# This should never be instantiated directly
|
150
|
+
# by user code. A timer must be known to the #Reactor in which it
|
151
|
+
# is running, so use the #Reactor#oneshot_timer and
|
152
|
+
# #Reactor#periodical_timer convenience methods. It ensures that
|
153
|
+
# new timers are installed in the correct #Reactor.
|
154
|
+
#
|
155
|
+
class Timer
|
156
|
+
include Comparable
|
157
|
+
|
158
|
+
attr_reader :fire_time
|
159
|
+
|
160
|
+
# +time+ is in milliseconds
|
161
|
+
def initialize timers, delay, periodical, timer_proc = nil, &blk
|
162
|
+
@timers = timers
|
163
|
+
@delay = delay.to_i
|
164
|
+
@periodical = periodical
|
165
|
+
@timer_proc = timer_proc || blk
|
166
|
+
schedule_firing_time
|
167
|
+
end
|
168
|
+
|
169
|
+
# Executes the callback.
|
170
|
+
#
|
171
|
+
# Returns +true+ when the timer is a one-shot;
|
172
|
+
# Returns +false+ when the timer is periodical and has rescheduled
|
173
|
+
# itself.
|
174
|
+
#
|
175
|
+
def fire
|
176
|
+
@timer_proc.call
|
177
|
+
|
178
|
+
schedule_firing_time if @periodical
|
179
|
+
end
|
180
|
+
|
181
|
+
def cancel
|
182
|
+
@timers.cancel self
|
183
|
+
end
|
184
|
+
|
185
|
+
def <=>(other)
|
186
|
+
self.fire_time <=> other.fire_time
|
187
|
+
end
|
188
|
+
|
189
|
+
def expired? time
|
190
|
+
time ||= now
|
191
|
+
time > @fire_time
|
192
|
+
end
|
193
|
+
|
194
|
+
def periodical?
|
195
|
+
@periodical
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
# calculate the time when this should fire; note that
|
202
|
+
# the use of #now grabs the current time and adds the
|
203
|
+
# delay on top. When this timer is late in firing (due
|
204
|
+
# to a blocking operation or other blocker preventing
|
205
|
+
# this from running on time) then we will see the next
|
206
|
+
# scheduled firing time slowly drift.
|
207
|
+
# e.g. Fire at time 10 + delay 5 = 15
|
208
|
+
# timer late, fires at 17
|
209
|
+
# next timer to fire at, 17 + delay 5 = 22
|
210
|
+
# had it not been late, it would fire at 20
|
211
|
+
def schedule_firing_time
|
212
|
+
@fire_time = now + @delay
|
213
|
+
end
|
214
|
+
|
215
|
+
def now
|
216
|
+
Timers.now
|
217
|
+
end
|
218
|
+
end # class Timer
|
219
|
+
|
220
|
+
end # module ZMQMachine
|
data/lib/zmqmachine.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
module ZMQMachine
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
# :startdoc:
|
8
|
+
|
9
|
+
# Returns the version string for the library.
|
10
|
+
#
|
11
|
+
def self.version
|
12
|
+
@version ||= File.read(path('version.txt')).strip
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the library path for the module. If any arguments are given,
|
16
|
+
# they will be joined to the end of the libray path using
|
17
|
+
# <tt>File.join</tt>.
|
18
|
+
#
|
19
|
+
def self.libpath( *args, &block )
|
20
|
+
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
21
|
+
if block
|
22
|
+
begin
|
23
|
+
$LOAD_PATH.unshift LIBPATH
|
24
|
+
rv = block.call
|
25
|
+
ensure
|
26
|
+
$LOAD_PATH.shift
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return rv
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the lpath for the module. If any arguments are given,
|
33
|
+
# they will be joined to the end of the path using
|
34
|
+
# <tt>File.join</tt>.
|
35
|
+
#
|
36
|
+
def self.path( *args, &block )
|
37
|
+
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
38
|
+
if block
|
39
|
+
begin
|
40
|
+
$LOAD_PATH.unshift PATH
|
41
|
+
rv = block.call
|
42
|
+
ensure
|
43
|
+
$LOAD_PATH.shift
|
44
|
+
end
|
45
|
+
end
|
46
|
+
return rv
|
47
|
+
end
|
48
|
+
|
49
|
+
# Utility method used to require all files ending in .rb that lie in the
|
50
|
+
# directory below this file that has the same name as the filename passed
|
51
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
52
|
+
# the _filename_ does not have to be equivalent to the directory.
|
53
|
+
#
|
54
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
55
|
+
dir ||= ::File.basename(fname, '.*')
|
56
|
+
search_me = ::File.expand_path(
|
57
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
58
|
+
|
59
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
60
|
+
end
|
61
|
+
|
62
|
+
end # module ZMQMachine
|
63
|
+
|
64
|
+
require 'singleton'
|
65
|
+
require 'set'
|
66
|
+
require 'ffi-rzmq'
|
67
|
+
|
68
|
+
# the order of files is important
|
69
|
+
%w(address exceptions timers deferrable reactor message sockets).each do |file|
|
70
|
+
require ZMQMachine.libpath(['zm', file])
|
71
|
+
end
|
72
|
+
|
73
|
+
ZMQMachine.require_all_libs_relative_to(__FILE__)
|
74
|
+
|
75
|
+
# save some typing
|
76
|
+
ZM = ZMQMachine
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(
|
3
|
+
File.join(File.dirname(__FILE__), %w[.. lib zmqmachine]))
|
4
|
+
|
5
|
+
Spec::Runner.configure do |config|
|
6
|
+
# == Mock Framework
|
7
|
+
#
|
8
|
+
# RSpec uses it's own mocking framework by default. If you prefer to
|
9
|
+
# use mocha, flexmock or RR, uncomment the appropriate line:
|
10
|
+
#
|
11
|
+
# config.mock_with :mocha
|
12
|
+
# config.mock_with :flexmock
|
13
|
+
# config.mock_with :rr
|
14
|
+
end
|
15
|
+
|
data/version.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/zmqmachine.gemspec
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{zmqmachine}
|
5
|
+
s.version = "0.3.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Chuck Remes"]
|
9
|
+
s.date = %q{2010-08-15}
|
10
|
+
s.description = %q{ZMQMachine is another Ruby implementation of the reactor pattern but this
|
11
|
+
time using 0mq sockets rather than POSIX sockets.
|
12
|
+
|
13
|
+
Unlike the great Eventmachine ruby project and the Python Twisted
|
14
|
+
project which work with POSIX sockets, ZMQMachine is inherently threaded. The
|
15
|
+
0mq sockets backing the reactor use a thread pool for performing
|
16
|
+
their work so already it is different from most other reactors. Also, a
|
17
|
+
single program may create multiple reactor instances which runs in
|
18
|
+
its own thread. All activity within the reactor is single-threaded
|
19
|
+
and asynchronous.
|
20
|
+
|
21
|
+
It is possible to extend the 0mq library to "poll" normal file
|
22
|
+
descriptors. This isn't on my roadmap but patches are accepted.}
|
23
|
+
s.email = %q{cremes@mac.com}
|
24
|
+
s.extra_rdoc_files = ["History.txt", "README.rdoc", "version.txt"]
|
25
|
+
s.files = [".bnsignore", "History.txt", "README.rdoc", "Rakefile", "examples/fake_ftp.rb", "examples/one_handed_ping_pong.rb", "examples/ping_pong.rb", "examples/pub_sub.rb", "examples/throttled_ping_pong.rb", "lib/zm/address.rb", "lib/zm/deferrable.rb", "lib/zm/exceptions.rb", "lib/zm/message.rb", "lib/zm/reactor.rb", "lib/zm/sockets.rb", "lib/zm/sockets/base.rb", "lib/zm/sockets/pair.rb", "lib/zm/sockets/pub.rb", "lib/zm/sockets/rep.rb", "lib/zm/sockets/req.rb", "lib/zm/sockets/sub.rb", "lib/zm/sockets/xrep.rb", "lib/zm/sockets/xreq.rb", "lib/zm/timers.rb", "lib/zmqmachine.rb", "spec/spec_helper.rb", "spec/zmqmachine_spec.rb", "version.txt", "zmqmachine.gemspec"]
|
26
|
+
s.homepage = %q{http://github.com/chuckremes/zmqmachine}
|
27
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
28
|
+
s.require_paths = ["lib"]
|
29
|
+
s.rubyforge_project = %q{zmqmachine}
|
30
|
+
s.rubygems_version = %q{1.3.6}
|
31
|
+
s.summary = %q{ZMQMachine is another Ruby implementation of the reactor pattern but this time using 0mq sockets rather than POSIX sockets}
|
32
|
+
|
33
|
+
if s.respond_to? :specification_version then
|
34
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
35
|
+
s.specification_version = 3
|
36
|
+
|
37
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
38
|
+
s.add_runtime_dependency(%q<ffi-rzmq>, [">= 0.5.0"])
|
39
|
+
s.add_development_dependency(%q<bones>, [">= 3.4.3"])
|
40
|
+
else
|
41
|
+
s.add_dependency(%q<ffi-rzmq>, [">= 0.5.0"])
|
42
|
+
s.add_dependency(%q<bones>, [">= 3.4.3"])
|
43
|
+
end
|
44
|
+
else
|
45
|
+
s.add_dependency(%q<ffi-rzmq>, [">= 0.5.0"])
|
46
|
+
s.add_dependency(%q<bones>, [">= 3.4.3"])
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zmqmachine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Chuck Remes
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-08-15 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: ffi-rzmq
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 5
|
30
|
+
- 0
|
31
|
+
version: 0.5.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: bones
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 3
|
43
|
+
- 4
|
44
|
+
- 3
|
45
|
+
version: 3.4.3
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
description: |-
|
49
|
+
ZMQMachine is another Ruby implementation of the reactor pattern but this
|
50
|
+
time using 0mq sockets rather than POSIX sockets.
|
51
|
+
|
52
|
+
Unlike the great Eventmachine ruby project and the Python Twisted
|
53
|
+
project which work with POSIX sockets, ZMQMachine is inherently threaded. The
|
54
|
+
0mq sockets backing the reactor use a thread pool for performing
|
55
|
+
their work so already it is different from most other reactors. Also, a
|
56
|
+
single program may create multiple reactor instances which runs in
|
57
|
+
its own thread. All activity within the reactor is single-threaded
|
58
|
+
and asynchronous.
|
59
|
+
|
60
|
+
It is possible to extend the 0mq library to "poll" normal file
|
61
|
+
descriptors. This isn't on my roadmap but patches are accepted.
|
62
|
+
email: cremes@mac.com
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
extra_rdoc_files:
|
68
|
+
- History.txt
|
69
|
+
- README.rdoc
|
70
|
+
- version.txt
|
71
|
+
files:
|
72
|
+
- .bnsignore
|
73
|
+
- History.txt
|
74
|
+
- README.rdoc
|
75
|
+
- Rakefile
|
76
|
+
- examples/fake_ftp.rb
|
77
|
+
- examples/one_handed_ping_pong.rb
|
78
|
+
- examples/ping_pong.rb
|
79
|
+
- examples/pub_sub.rb
|
80
|
+
- examples/throttled_ping_pong.rb
|
81
|
+
- lib/zm/address.rb
|
82
|
+
- lib/zm/deferrable.rb
|
83
|
+
- lib/zm/exceptions.rb
|
84
|
+
- lib/zm/message.rb
|
85
|
+
- lib/zm/reactor.rb
|
86
|
+
- lib/zm/sockets.rb
|
87
|
+
- lib/zm/sockets/base.rb
|
88
|
+
- lib/zm/sockets/pair.rb
|
89
|
+
- lib/zm/sockets/pub.rb
|
90
|
+
- lib/zm/sockets/rep.rb
|
91
|
+
- lib/zm/sockets/req.rb
|
92
|
+
- lib/zm/sockets/sub.rb
|
93
|
+
- lib/zm/sockets/xrep.rb
|
94
|
+
- lib/zm/sockets/xreq.rb
|
95
|
+
- lib/zm/timers.rb
|
96
|
+
- lib/zmqmachine.rb
|
97
|
+
- spec/spec_helper.rb
|
98
|
+
- spec/zmqmachine_spec.rb
|
99
|
+
- version.txt
|
100
|
+
- zmqmachine.gemspec
|
101
|
+
has_rdoc: true
|
102
|
+
homepage: http://github.com/chuckremes/zmqmachine
|
103
|
+
licenses: []
|
104
|
+
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options:
|
107
|
+
- --main
|
108
|
+
- README.rdoc
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
version: "0"
|
125
|
+
requirements: []
|
126
|
+
|
127
|
+
rubyforge_project: zmqmachine
|
128
|
+
rubygems_version: 1.3.6
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: ZMQMachine is another Ruby implementation of the reactor pattern but this time using 0mq sockets rather than POSIX sockets
|
132
|
+
test_files: []
|
133
|
+
|