ionian 0.6.12 → 0.7.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.
@@ -103,7 +103,7 @@
103
103
  </div>
104
104
 
105
105
  <div id="footer">
106
- Generated on Mon Jan 26 21:45:48 2015 by
106
+ Generated on Wed Jan 28 16:07:19 2015 by
107
107
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
108
  0.8.7.6 (ruby-2.1.5).
109
109
  </div>
@@ -1,6 +1,7 @@
1
1
  require 'ionian/extension/io'
2
2
  require 'ionian/extension/socket'
3
3
  require 'ionian/socket'
4
+ require 'ionian/managed_socket'
4
5
  require 'ionian/server'
5
6
 
6
7
  # A library to simplify interaction with IO streams.
@@ -39,7 +39,7 @@ module Ionian
39
39
  ::IO.select([self], nil, nil, timeout) ? true : false
40
40
  end
41
41
 
42
- # Returns the regular expression used for {#read_match}.
42
+ # @return [Regexp] Regular expression used for {#read_match}.
43
43
  def expression
44
44
  @ionian_expression
45
45
  end
@@ -84,8 +84,8 @@ module Ionian
84
84
  # @yieldparam match [MatchData] If there are multiple matches, the block
85
85
  # is called multiple times.
86
86
  #
87
- # @return [Array<MatchData>, nil] Returns an array of matches.
88
- # Returns nil if no data was received within the timeout period.
87
+ # @return [Array<MatchData>, nil] matches.
88
+ # Nil if no data was received within the timeout period.
89
89
  #
90
90
  #
91
91
  # @option kwargs [Numeric] :timeout (nil) Timeout in seconds IO::select
@@ -114,16 +114,23 @@ module Ionian
114
114
  exp = Regexp.new "(.*?)#{exp}" if exp.is_a? String
115
115
 
116
116
  unless skip_select
117
- return nil unless ::IO.select [self], nil, nil, timeout
117
+ return nil unless self.has_data? timeout: timeout
118
118
  end
119
119
 
120
- # Read data from the IO buffer until it's empty.
121
- @ionian_buf << read_all
122
-
123
120
  @matches = []
124
121
 
122
+ # TODO: Implement an option for number of bytes or timeout to throw away
123
+ # data if no match is found.
124
+ Timeout.timeout(timeout) do
125
+ loop do
126
+ # Read data from the IO buffer until it's empty.
127
+ @ionian_buf << read_all
128
+ break if @ionian_buf =~ exp
129
+ end
130
+ end
131
+
125
132
  while @ionian_buf =~ exp
126
- @matches << $~ # Match data.
133
+ @matches << $~ # Match data.
127
134
  @ionian_buf = $' # Leave post match data in the buffer.
128
135
  end
129
136
 
@@ -155,6 +162,7 @@ module Ionian
155
162
  # This method SHOULD NOT be used if {#read_match} is used.
156
163
  def run_match **kwargs
157
164
  @run_match_thread ||= Thread.new do
165
+ Thread.current.thread_variable_set :match_thread_running, true
158
166
  begin
159
167
  while not closed? do
160
168
  matches = read_match **kwargs
@@ -168,6 +176,14 @@ module Ionian
168
176
  end
169
177
  end
170
178
 
179
+ def run_match_is_running?
180
+ return true if \
181
+ @run_match_thread and
182
+ @run_match_thread.thread_variable_get(:match_thread_running)
183
+
184
+ false
185
+ end
186
+
171
187
  # Erase the data in the IO and Ionian buffers.
172
188
  # This is typically handled automatically.
173
189
  def purge
@@ -195,6 +211,7 @@ module Ionian
195
211
 
196
212
  # @deprecated Use {#register_match_handler} instead.
197
213
  def register_observer &block
214
+ STDOUT.puts "WARN: Call to deprecated method #{__method__}"
198
215
  register_match_handler &block
199
216
  end
200
217
 
@@ -206,6 +223,7 @@ module Ionian
206
223
 
207
224
  # @deprecated Use {#unregister_match_handler} instead.
208
225
  def unregister_observer &block
226
+ STDOUT.puts "WARN: Call to deprecated method #{__method__}"
209
227
  unregister_match_handler &block
210
228
  end
211
229
 
@@ -55,13 +55,11 @@ module Ionian
55
55
  # immediately and try to deliver any data in the send buffer if value
56
56
  # is true.
57
57
  #
58
- # Args:
59
- # Time: Time in seconds to remain open before discarding data and
60
- # sending a RST packet.
58
+ # @param time [Fixnum] Time in seconds to remain open before discarding
59
+ # data and sending a RST packet.
60
+ #
61
61
  # ( SO_LINGER )
62
62
  def linger= enable, time: 60
63
- # TODO: Passing a kwarg doesn't work here because of the
64
- # assignment operator. Causes parser error.
65
63
  param = (!!enable && enable != 0) ? 1 : 0
66
64
  self.setsockopt ::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [param, time.to_i].pack('ii')
67
65
  end
@@ -231,49 +229,51 @@ module Ionian
231
229
 
232
230
  # Not yet implemented.
233
231
  def ipv6_add_membership
234
- # TODO: Implement
235
- false
232
+ # TODO: Implement IPv6
233
+ raise NotImplementedError
236
234
  end
237
235
 
238
236
  # Not yet implemented.
239
237
  def ipv6_drop_membership
240
- # TODO: Implement
241
- false
238
+ # TODO: Implement IPv6
239
+ raise NotImplementedError
242
240
  end
243
241
 
244
242
  # Not yet implemented.
245
243
  def ipv6_multicast_if
246
- # TODO: Implement
247
- false
244
+ # TODO: Implement IPv6
245
+ raise NotImplementedError
248
246
  end
249
247
 
250
248
  # Not yet implemented.
251
249
  def ipv6_multicast_if= value
252
- # TODO: Implement
250
+ # TODO: Implement IPv6
253
251
  end
254
252
 
255
253
  # Not yet implemented.
256
254
  def ipv6_multicast_hops
257
- # TODO: Implement
258
- false
255
+ # TODO: Implement IPv6
256
+ raise NotImplementedError
259
257
  end
260
258
 
261
259
  # Not yet implemented.
262
260
  def ipv6_multicast_hops= value
263
- # TODO: Implement
261
+ # TODO: Implement IPv6
262
+ raise NotImplementedError
264
263
  end
265
264
 
266
265
  # Not yet implemented.
267
266
  def ipv6_multicast_loop
268
- # TODO: Implement
269
- false
267
+ # TODO: Implement IPv6
268
+ raise NotImplementedError
270
269
  end
271
270
 
272
271
  alias_method :ipv6_multicast_loop?, :ipv6_multicast_loop
273
272
 
274
273
  # Not yet implemented.
275
274
  def ipv6_multicast_loop= value
276
- # TODO: Implement
275
+ # TODO: Implement IPv6
276
+ raise NotImplementedError
277
277
  end
278
278
 
279
279
 
@@ -0,0 +1,109 @@
1
+ require 'ionian/socket'
2
+
3
+ module Ionian
4
+
5
+ # A socket manager that wraps an {Ionian::Socket} and can perform functions
6
+ # like heartbeating and auto-reconnect.
7
+ class ManagedSocket
8
+
9
+ # When true, automatically reconnect if the socket closes.
10
+ attr_reader :auto_reconnect
11
+
12
+ # @option kwargs [Boolean] :auto_reconnect (false) Automatically reconnect
13
+ # if the socket closes. Must call {#close} to break the auto-reconnect
14
+ # loop.
15
+ #
16
+ # @see Ionian::Socket#initialize More optional parameters.
17
+ def initialize **kwargs
18
+ @auto_reconnect = kwargs.delete(:auto_reconnect) || false
19
+ @kwargs = kwargs
20
+
21
+ @match_handlers = []
22
+ @error_handlers = []
23
+
24
+ create_socket
25
+ end
26
+
27
+ # Close the socket.
28
+ # Disables :auto_reconnect.
29
+ def close
30
+ @auto_reconnect = false
31
+ @socket.close unless @socket.closed?
32
+ end
33
+
34
+ # Register a block to be called when {Ionian::Extension::IO#run_match}
35
+ # receives matched data.
36
+ # Method callbacks can be registered with &object.method(:method).
37
+ # @return [Block] The given block.
38
+ # @yield [MatchData, self]
39
+ def register_match_handler &block
40
+ @match_handlers << block unless @match_handlers.include? block
41
+ @socket.register_match_handler &block if @socket
42
+ block
43
+ end
44
+
45
+ alias_method :on_match, :register_match_handler
46
+
47
+ # Unregister a block from being called when matched data is received.
48
+ def unregister_match_handler &block
49
+ @match_handlers.delete_if { |o| o == block }
50
+ @socket.unregister_match_handler &block if @socket
51
+ block
52
+ end
53
+
54
+ # Register a block to be called when {Ionian::Extension::IO#run_match}
55
+ # raises an error.
56
+ # Method callbacks can be registered with &object.method(:method).
57
+ # @return [Block] a reference to the given block.
58
+ # @yield [Exception, self]
59
+ def register_error_handler &block
60
+ @error_handlers << block unless @error_handlers.include? block
61
+ @socket.register_error_handler &block if @socket
62
+ block
63
+ end
64
+
65
+ alias_method :on_error, :register_error_handler
66
+
67
+ # Unregister a block from being called when a {Ionian::IO#run_match} error
68
+ # is raised.
69
+ def unregister_error_handler &block
70
+ @error_handlers.delete_if { |o| o == block }
71
+ @socket.unregister_error_handler &block if @socket
72
+ block
73
+ end
74
+
75
+ # Pass unhandled methods to @socket.
76
+ # @see Ionian::Socket
77
+ def method_missing meth, *args, &block
78
+ @socket.__send__ meth, *args, &block
79
+ end
80
+
81
+ def respond_to_missing? meth, *args
82
+ @socket.respond_to? meth, *args
83
+ end
84
+
85
+
86
+ private
87
+
88
+ # Initialize or reinitialize @socket.
89
+ def create_socket
90
+ @socket = Ionian::Socket.new **@kwargs
91
+ @socket.on_error &method(:socket_error_handler)
92
+ @match_handlers.each { |h| @socket.register_match_handler &h }
93
+ @error_handlers.each { |h| @socket.register_error_handler &h }
94
+
95
+ @socket.run_match
96
+ end
97
+
98
+ # {Ionian::Socket#on_error} handler for @socket.
99
+ def socket_error_handler e, socket
100
+ if auto_reconnect
101
+ @socket.close unless @socket.closed?
102
+ create_socket
103
+ else
104
+ raise e unless e.is_a? EOFError or e.is_a? IOError
105
+ end
106
+ end
107
+
108
+ end
109
+ end
@@ -1,3 +1,4 @@
1
+ require 'timeout'
1
2
  require 'ionian/extension/socket'
2
3
 
3
4
  module Ionian
@@ -19,6 +20,17 @@ module Ionian
19
20
  attr_reader :protocol
20
21
  alias_method :protocol?, :protocol
21
22
 
23
+ # @return [Ionian::Socket] a broadcast socket.
24
+ #
25
+ # @option kwargs [Fixnum] :port Port to broadcast on.
26
+ # @option kwargs [String] :address ('255.255.255.255') Address to broadcast on.
27
+ #
28
+ # @see #initialize Full list of socket options.
29
+ def self.create_broadcast_socket **kwargs
30
+ kwargs[:host] = kwargs.delete(:address) || '255.255.255.255'
31
+ kwargs[:broadcast] = true
32
+ new **kwargs
33
+ end
22
34
 
23
35
  # Creates a new socket or wraps an existing socket.
24
36
  #
@@ -76,7 +88,8 @@ module Ionian
76
88
  def initialize existing_socket = nil, **kwargs, &block
77
89
  @socket = existing_socket
78
90
 
79
- @ionian_listeners = []
91
+ @ionian_match_handlers = []
92
+ @ionian_error_handlers = []
80
93
 
81
94
  @expression = kwargs.fetch :expression, nil
82
95
 
@@ -192,31 +205,64 @@ module Ionian
192
205
  matches
193
206
  end
194
207
 
195
- # Register a block to be called when #run_match receives matched data.
208
+ # Register a block to be called when {Ionian::Extension::IO#run_match}
209
+ # receives matched data.
196
210
  # Method callbacks can be registered with &object.method(:method).
197
- # Returns a reference to the given block.
198
- # block = ionian_socket.register_observer { ... }
199
- def register_observer &block
200
- @ionian_listeners << block unless @ionian_listeners.include? block
201
- @socket.register_observer &block if @socket
211
+ # @return [Block] The given block.
212
+ # @yield [MatchData, self]
213
+ def register_match_handler &block
214
+ @ionian_match_handlers << block unless @ionian_match_handlers.include? block
215
+ @socket.register_match_handler &block if @socket
202
216
  block
203
217
  end
204
218
 
205
- alias_method :on_match, :register_observer
219
+ alias_method :on_match, :register_match_handler
220
+
221
+ # @deprecated Use {#register_match_handler} instead.
222
+ def register_observer &block
223
+ STDOUT.puts "WARN: Call to deprecated method #{__method__}"
224
+ register_match_handler &block
225
+ end
206
226
 
207
227
  # Unregister a block from being called when matched data is received.
228
+ def unregister_match_handler &block
229
+ @ionian_match_handlers.delete_if { |o| o == block }
230
+ @socket.unregister_match_handler &block if @socket
231
+ block
232
+ end
233
+
234
+ # @deprecated Use {#unregister_match_handler} instead.
208
235
  def unregister_observer &block
209
- @ionian_listeners.delete_if { |o| o == block }
210
- @socket.unregister_observer &block if @socket
236
+ STDOUT.puts "WARN: Call to deprecated method #{__method__}"
237
+ unregister_match_handler &block
238
+ end
239
+
240
+ # Register a block to be called when {Ionian::Extension::IO#run_match}
241
+ # raises an error.
242
+ # Method callbacks can be registered with &object.method(:method).
243
+ # @return [Block] a reference to the given block.
244
+ # @yield [Exception, self]
245
+ def register_error_handler &block
246
+ @ionian_error_handlers << block unless @ionian_error_handlers.include? block
247
+ @socket.register_error_handler &block if @socket
248
+ block
249
+ end
250
+
251
+ alias_method :on_error, :register_error_handler
252
+
253
+ # Unregister a block from being called when a {Ionian::IO#run_match} error
254
+ # is raised.
255
+ def unregister_error_handler &block
256
+ @ionian_error_handlers.delete_if { |o| o == block }
257
+ @socket.unregister_error_handler &block if @socket
211
258
  block
212
259
  end
213
260
 
214
261
  ### Methods Forwarded To @socket ###
215
262
 
216
- # Returns true if there is data in the receive buffer.
217
- # Args:
218
- # Timeout: Number of seconds to wait for data until
219
- # giving up. Set to nil for blocking.
263
+ # @return [Boolean] True if there is data in the receive buffer.
264
+ # @option kwargs [Fixnum, nil] :timeout (0) Number of seconds to wait for
265
+ # data until giving up. Set to nil for blocking.
220
266
  def has_data? **kwargs
221
267
  return false unless @socket
222
268
  @socket.has_data? kwargs
@@ -240,8 +286,8 @@ module Ionian
240
286
  self.write string.map{ |s| s.chomp }.join("\n") + "\n"
241
287
  end
242
288
 
243
- # Writes the given string to the socket. Returns the number of
244
- # bytes written.
289
+ # Writes the given string to the socket.
290
+ # @return [Fixnum] Number of bytes written.
245
291
  def write string
246
292
  create_socket unless @persistent
247
293
 
@@ -317,8 +363,9 @@ module Ionian
317
363
 
318
364
  @socket.expression = @expression if @expression
319
365
 
320
- # Register listeners.
321
- @ionian_listeners.each { |proc| @socket.on_match &proc }
366
+ # Register handlers.
367
+ @ionian_match_handlers.each { |proc| @socket.on_match &proc }
368
+ @ionian_error_handlers.each { |proc| @socket.on_error &proc }
322
369
 
323
370
  initialize_socket_methods
324
371
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ionian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.12
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McLain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-26 00:00:00.000000000 Z
11
+ date: 2015-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -121,6 +121,7 @@ files:
121
121
  - doc/Ionian/Extension.html
122
122
  - doc/Ionian/Extension/IO.html
123
123
  - doc/Ionian/Extension/Socket.html
124
+ - doc/Ionian/ManagedSocket.html
124
125
  - doc/Ionian/Server.html
125
126
  - doc/Ionian/Socket.html
126
127
  - doc/_index.html
@@ -141,6 +142,7 @@ files:
141
142
  - lib/ionian.rb
142
143
  - lib/ionian/extension/io.rb
143
144
  - lib/ionian/extension/socket.rb
145
+ - lib/ionian/managed_socket.rb
144
146
  - lib/ionian/server.rb
145
147
  - lib/ionian/socket.rb
146
148
  - license.txt
@@ -164,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
166
  version: '0'
165
167
  requirements: []
166
168
  rubyforge_project:
167
- rubygems_version: 2.4.5
169
+ rubygems_version: 2.4.4
168
170
  signing_key:
169
171
  specification_version: 4
170
172
  summary: Regular expression matching and notification for IO streams.