ezmq 0.1.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,27 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'ezmq'
3
+ gem.version = '0.1.1'
4
+ gem.licenses = 'MIT'
5
+ gem.authors = ['Chris Olstrom']
6
+ gem.email = 'chris@olstrom.com'
7
+ gem.homepage = 'https://github.com/colstrom/ezmq'
8
+ gem.summary = 'Effortless ZMQ'
9
+ gem.description = 'Syntactic sugar around FFI bindings for ZMQ, to stop C from seeping into your Ruby.'
10
+
11
+ gem.files = `git ls-files`.split("\n")
12
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
14
+ gem.require_paths = ['lib']
15
+
16
+ gem.add_runtime_dependency 'ffi-rzmq', '~> 2.0'
17
+
18
+ gem.add_development_dependency 'rake'
19
+ gem.add_development_dependency 'rubocop'
20
+ gem.add_development_dependency 'flog'
21
+ gem.add_development_dependency 'flay'
22
+ gem.add_development_dependency 'roodi'
23
+ gem.add_development_dependency 'reek'
24
+ gem.add_development_dependency 'churn'
25
+ gem.add_development_dependency 'yard'
26
+ gem.add_development_dependency 'inch'
27
+ end
@@ -0,0 +1,227 @@
1
+ require 'ffi-rzmq'
2
+
3
+ # Syntactic sugar for 0MQ, because Ruby shouldn't feel like C.
4
+ module EZMQ
5
+ # Wrapper class to simplify 0MQ sockets.
6
+ class Socket
7
+ attr_accessor :context, :socket, :encode, :decode
8
+
9
+ # Creates a 0MQ socket.
10
+ #
11
+ # @param [Symbol] mode the mode of the socket. `:bind` or `:connect`
12
+ # @param [Object] type the type of socket to use.
13
+ # @param [Hash] options optional parameters.
14
+ #
15
+ # @option options [ZMQ::Context] context a context to use for this socket
16
+ # (one will be created if not provided).
17
+ # @option options [lambda] encode how to encode messages. Default unaltered.
18
+ # @option options [lambda] decode how to decode messages. Default unaltered.
19
+ # @option options [String] address specifies protocol, address and port (if
20
+ # needed). Default is 'tcp://127.0.0.1:5555'
21
+ #
22
+ # @return [Socket] a new instance of Socket.
23
+ #
24
+ def initialize(mode, type, **options)
25
+ fail ArgumentError unless [:bind, :connect].include? mode
26
+ @context = options[:context] || ZMQ::Context.new
27
+ @socket = @context.socket type
28
+ @encode = options[:encode] || -> m { m }
29
+ @decode = options[:decode] || -> m { m }
30
+ method(mode).call address: options[:address] || 'tcp://127.0.0.1:5555'
31
+ end
32
+
33
+ # Receive a message from the socket.
34
+ #
35
+ # @note This method blocks until a message arrives.
36
+ #
37
+ # @param [lambda] decode how to decode the message.
38
+ #
39
+ # @return [void] the decoded message.
40
+ #
41
+ def receive(decode: @decode)
42
+ message = ''
43
+ @socket.recv_string message
44
+ decode.call message
45
+ end
46
+
47
+ # Sends a message on the socket.
48
+ #
49
+ # @note If `message` is not a String, `encode` must convert it to one.
50
+ #
51
+ # @param [String] message the message to send.
52
+ # @param [lambda] encode how to encode the message.
53
+ #
54
+ # @return [Fixnum] the size of the message.
55
+ #
56
+ def send(message = '', encode: @encode)
57
+ @socket.send_string encode.call message
58
+ end
59
+
60
+ # Binds the socket to the given address.
61
+ #
62
+ # @note 'localhost' does not always work as expected. Prefer '127.0.0.1'
63
+ #
64
+ # @param [String] address specifies protocol, address and port (if needed).
65
+ # Default is 'tcp://127.0.0.1:5555'
66
+ #
67
+ # @return [Boolean] was binding successful?
68
+ #
69
+ def bind(address: 'tcp://127.0.0.1:5555')
70
+ @socket.bind(address) == 0 ? true : false
71
+ end
72
+
73
+ # Connects the socket to the given address.
74
+ #
75
+ # @param [String] address specifies protocol, address and port (if needed).
76
+ # Default is 'tcp://127.0.0.1:5555'
77
+ #
78
+ # @return [Boolean] was connection successful?
79
+ #
80
+ def connect(address: 'tcp://127.0.0.1:5555')
81
+ @socket.connect(address) == 0 ? true : false
82
+ end
83
+ end
84
+
85
+ # Reply socket that listens for and replies to requests.
86
+ class Server < EZMQ::Socket
87
+ attr_accessor :provides
88
+
89
+ # Creates a new Server socket.
90
+ #
91
+ # @param [lambda] provides the service provided by this server.
92
+ # @param [Hash] options optional parameters
93
+ #
94
+ # @see EZMQ::Socket EZMQ::Socket for a list of optional parameters.
95
+ #
96
+ # @return [Server] a new instance of Server
97
+ #
98
+ def initialize(provides: -> m { m }, **options)
99
+ @provides = provides
100
+ super :bind, ZMQ::REP, options
101
+ end
102
+
103
+ # By default, waits to receive a message, calls @action with it, replies
104
+ # with the result, then loops.
105
+ #
106
+ # @param [lambda] handler how requests are handled.
107
+ #
108
+ # @return [void] the return from handler.
109
+ #
110
+ def listen(handler: -> { send @provides.call(receive) })
111
+ loop { handler.call }
112
+ end
113
+ end
114
+
115
+ # Request socket that sends messages and receives replies.
116
+ class Client < EZMQ::Socket
117
+ # Creates a new Client socket.
118
+ #
119
+ # @param [Hash] options optional parameters
120
+ #
121
+ # @see EZMQ::Socket EZMQ::Socket for a list of optional parameters.
122
+ #
123
+ # @return [Client] a new instance of Client.
124
+ #
125
+ def initialize(**options)
126
+ super :connect, ZMQ::REQ, options
127
+ end
128
+
129
+ # Sends a message and waits to receive a response.
130
+ #
131
+ # @param [String] message the message to send.
132
+ # @param [lambda] encode how to encode the message.
133
+ # @param [lambda] decode how to decode the message.
134
+ #
135
+ # @return [void] the decoded response message.
136
+ #
137
+ def request(message = '', encode: @encode, decode: @decode)
138
+ send message, encode: encode
139
+ receive decode: decode
140
+ end
141
+ end
142
+
143
+ # Publish socket that broadcasts messages with an optional topic.
144
+ class Publisher < EZMQ::Socket
145
+ # Creates a new Publisher socket.
146
+ #
147
+ # @param [Hash] options optional parameters
148
+ #
149
+ # @see EZMQ::Socket EZMQ::Socket for a list of optional parameters.
150
+ #
151
+ # @return [Publisher] a new instance of Publisher.
152
+ #
153
+ def initialize(**options)
154
+ super :bind, ZMQ::PUB, options
155
+ end
156
+
157
+ # Sends a message on the socket, with an optional topic.
158
+ #
159
+ # @param [String] message the message to send.
160
+ # @param [String] topic an optional topic for the message.
161
+ # @param [lambda] encode how to encode the message.
162
+ #
163
+ # @return [Fixnum] the size of the message.
164
+ #
165
+ def send(message = '', topic: '', encode: @encode)
166
+ @socket.send_string "#{ topic } #{ encode.call message }"
167
+ end
168
+ end
169
+
170
+ # Subscribe socket that listens for messages with an optional topic.
171
+ class Subscriber < EZMQ::Socket
172
+ attr_accessor :action
173
+
174
+ # Creates a new Subscriber socket.
175
+ #
176
+ # @param [lambda] action the action to perform when a message is received.
177
+ # @param [Hash] options optional parameters
178
+ #
179
+ # @option options [String] topic a topic to subscribe to.
180
+ #
181
+ # @see EZMQ::Socket EZMQ::Socket for a list of optional parameters.
182
+ #
183
+ # @return [Publisher] a new instance of Publisher.
184
+ #
185
+ def initialize(action: -> m { m }, **options)
186
+ @action = action
187
+ super :connect, ZMQ::SUB, options
188
+ subscribe options[:topic] if options[:topic]
189
+ end
190
+
191
+ # Establishes a new message filter on the socket.
192
+ #
193
+ # @note By default, a Subscriber filters all incoming messages. Without
194
+ # calling subscribe at least once, no messages will be accepted. If topic
195
+ # was provided, #initialize calls #subscribe automatically.
196
+ #
197
+ # @param [String] topic a topic to subscribe to. Messages matching this
198
+ # prefix will be accepted.
199
+ #
200
+ # @return [Boolean] was subscription successful?
201
+ #
202
+ def subscribe(topic)
203
+ @socket.setsockopt(ZMQ::SUBSCRIBE, topic) == 0 ? true : false
204
+ end
205
+
206
+ # Removes a message filter (as set with subscribe) from the socket.
207
+ #
208
+ # @param [String] topic the topic to unsubscribe from. If multiple filters
209
+ # with the same topic are set, this will only remove one.
210
+ #
211
+ # @return [Boolean] was unsubscription successful?
212
+ #
213
+ def unsubscribe(topic)
214
+ @socket.setsockopt(ZMQ::UNSUBSCRIBE, topic) == 0 ? true : false
215
+ end
216
+
217
+ # By default, waits for a message and calls @action with the message.
218
+ #
219
+ # @param [lambda] handler how requests are handled.
220
+ #
221
+ # @return [void] the return from handler.
222
+ #
223
+ def listen(handler: -> { @action.call(receive) })
224
+ loop { handler.call }
225
+ end
226
+ end
227
+ end
metadata ADDED
@@ -0,0 +1,212 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ezmq
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Olstrom
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi-rzmq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: flog
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: flay
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: roodi
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: reek
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: churn
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yard
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: inch
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Syntactic sugar around FFI bindings for ZMQ, to stop C from seeping into
154
+ your Ruby.
155
+ email: chris@olstrom.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - .gitignore
161
+ - Gemfile
162
+ - LICENSE
163
+ - README.md
164
+ - Rakefile
165
+ - doc/EZMQ.html
166
+ - doc/EZMQ/Client.html
167
+ - doc/EZMQ/Publisher.html
168
+ - doc/EZMQ/Server.html
169
+ - doc/EZMQ/Socket.html
170
+ - doc/EZMQ/Subscriber.html
171
+ - doc/_index.html
172
+ - doc/class_list.html
173
+ - doc/css/common.css
174
+ - doc/css/full_list.css
175
+ - doc/css/style.css
176
+ - doc/file.README.html
177
+ - doc/file_list.html
178
+ - doc/frames.html
179
+ - doc/index.html
180
+ - doc/js/app.js
181
+ - doc/js/full_list.js
182
+ - doc/js/jquery.js
183
+ - doc/method_list.html
184
+ - doc/top-level-namespace.html
185
+ - ezmq.gemspec
186
+ - lib/ezmq.rb
187
+ homepage: https://github.com/colstrom/ezmq
188
+ licenses:
189
+ - MIT
190
+ metadata: {}
191
+ post_install_message:
192
+ rdoc_options: []
193
+ require_paths:
194
+ - lib
195
+ required_ruby_version: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - '>='
198
+ - !ruby/object:Gem::Version
199
+ version: '0'
200
+ required_rubygems_version: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - '>='
203
+ - !ruby/object:Gem::Version
204
+ version: '0'
205
+ requirements: []
206
+ rubyforge_project:
207
+ rubygems_version: 2.0.14
208
+ signing_key:
209
+ specification_version: 4
210
+ summary: Effortless ZMQ
211
+ test_files: []
212
+ has_rdoc: