ionian 0.7.0 → 0.8.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 Wed Jan 28 16:07:19 2015 by
106
+ Generated on Wed Feb 11 16:57:30 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>
@@ -39,7 +39,7 @@ module Ionian
39
39
  ::IO.select([self], nil, nil, timeout) ? true : false
40
40
  end
41
41
 
42
- # @return [Regexp] Regular expression used for {#read_match}.
42
+ # @return [Regexp] the regular expression used for {#read_match}.
43
43
  def expression
44
44
  @ionian_expression
45
45
  end
@@ -50,6 +50,7 @@ module Ionian
50
50
  # sequence. It is possible to use named captures in a
51
51
  # regex, which allows for convienient accessors like
52
52
  # match[:parameter].
53
+ # @param exp [Regexp, String] Match expression.
53
54
  def expression= exp
54
55
  @ionian_expression = exp
55
56
  @ionian_expression = Regexp.new "(.*?)#{expression}" if exp.is_a? String
@@ -84,8 +85,8 @@ module Ionian
84
85
  # @yieldparam match [MatchData] If there are multiple matches, the block
85
86
  # is called multiple times.
86
87
  #
87
- # @return [Array<MatchData>, nil] matches.
88
- # Nil if no data was received within the timeout period.
88
+ # @return [Array<MatchData>] matches.
89
+ # Empty array if no data was received within the timeout period.
89
90
  #
90
91
  #
91
92
  # @option kwargs [Numeric] :timeout (nil) Timeout in seconds IO::select
@@ -114,7 +115,7 @@ module Ionian
114
115
  exp = Regexp.new "(.*?)#{exp}" if exp.is_a? String
115
116
 
116
117
  unless skip_select
117
- return nil unless self.has_data? timeout: timeout
118
+ return [] unless self.has_data? timeout: timeout
118
119
  end
119
120
 
120
121
  @matches = []
@@ -165,8 +166,7 @@ module Ionian
165
166
  Thread.current.thread_variable_set :match_thread_running, true
166
167
  begin
167
168
  while not closed? do
168
- matches = read_match **kwargs
169
- matches.each { |match| notify_match_handlers match } if matches
169
+ read_match(**kwargs).each { |match| notify_match_handlers match }
170
170
  end
171
171
  rescue Exception => e
172
172
  notify_error_handlers e
@@ -176,14 +176,6 @@ module Ionian
176
176
  end
177
177
  end
178
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
-
187
179
  # Erase the data in the IO and Ionian buffers.
188
180
  # This is typically handled automatically.
189
181
  def purge
@@ -211,7 +203,7 @@ module Ionian
211
203
 
212
204
  # @deprecated Use {#register_match_handler} instead.
213
205
  def register_observer &block
214
- STDOUT.puts "WARN: Call to deprecated method #{__method__}"
206
+ STDOUT.puts "WARNING: Call to deprecated method: #{__method__}"
215
207
  register_match_handler &block
216
208
  end
217
209
 
@@ -223,7 +215,7 @@ module Ionian
223
215
 
224
216
  # @deprecated Use {#unregister_match_handler} instead.
225
217
  def unregister_observer &block
226
- STDOUT.puts "WARN: Call to deprecated method #{__method__}"
218
+ STDOUT.puts "WARNING: Call to deprecated method: #{__method__}"
227
219
  unregister_match_handler &block
228
220
  end
229
221
 
@@ -248,6 +248,7 @@ module Ionian
248
248
  # Not yet implemented.
249
249
  def ipv6_multicast_if= value
250
250
  # TODO: Implement IPv6
251
+ raise NotImplementedError
251
252
  end
252
253
 
253
254
  # Not yet implemented.
@@ -1,9 +1,10 @@
1
1
  require 'ionian/socket'
2
2
 
3
+ Thread.abort_on_exception = true
4
+
3
5
  module Ionian
4
6
 
5
- # A socket manager that wraps an {Ionian::Socket} and can perform functions
6
- # like heartbeating and auto-reconnect.
7
+ # A socket manager that performs functions like heartbeating and auto-reconnect.
7
8
  class ManagedSocket
8
9
 
9
10
  # When true, automatically reconnect if the socket closes.
@@ -16,25 +17,69 @@ module Ionian
16
17
  # @see Ionian::Socket#initialize More optional parameters.
17
18
  def initialize **kwargs
18
19
  @auto_reconnect = kwargs.delete(:auto_reconnect) || false
20
+ raise NotImplementedError, ':auto_reconnect must be set true.' unless @auto_reconnect
19
21
  @kwargs = kwargs
20
22
 
21
- @match_handlers = []
22
- @error_handlers = []
23
+ @match_handlers = []
24
+ @status_handlers = []
23
25
 
24
- create_socket
26
+ @write_queue = Queue.new
27
+ @write_pipe_rx, @write_pipe_tx = IO.pipe
28
+ @write_pipe_rx.extend Ionian::Extension::IO
25
29
  end
26
30
 
27
31
  # Close the socket.
28
32
  # Disables :auto_reconnect.
29
33
  def close
30
- @auto_reconnect = false
31
- @socket.close unless @socket.closed?
34
+ unless @closed == true
35
+ @auto_reconnect = false
36
+ @socket.close if @socket and not @socket.closed?
37
+ @write_pipe_tx.close rescue IOError
38
+ @write_pipe_rx.close rescue IOError
39
+ @write_queue = nil
40
+
41
+ @closed = true
42
+ end
43
+ end
44
+
45
+ # Start the event loop.
46
+ # Should be called after the handlers are registered.
47
+ def run
48
+ @run_thread ||= Thread.new do
49
+ while not @write_pipe_rx.closed?
50
+ begin
51
+ create_socket if (not @socket or @socket.closed?) and not @write_pipe_rx.closed?
52
+ io = ::IO.select([@write_pipe_rx, @socket.fd], nil, nil, nil).first.first
53
+
54
+ case io
55
+
56
+ when @write_pipe_rx
57
+ @write_pipe_rx.read_all
58
+ while @socket and not @write_queue.empty?
59
+ @socket.write @write_queue.shift
60
+ end
61
+
62
+ when @socket.fd
63
+ @socket.read_match
64
+
65
+ end
66
+ rescue IOError # Far-end socket closed.
67
+ @socket.close if @socket and not @socket.closed?
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ # Write data to the socket.
74
+ def write data
75
+ @write_queue << data
76
+ @write_pipe_tx.write "\n"
32
77
  end
33
78
 
34
79
  # Register a block to be called when {Ionian::Extension::IO#run_match}
35
80
  # receives matched data.
36
81
  # Method callbacks can be registered with &object.method(:method).
37
- # @return [Block] The given block.
82
+ # @return [Block] the given block.
38
83
  # @yield [MatchData, self]
39
84
  def register_match_handler &block
40
85
  @match_handlers << block unless @match_handlers.include? block
@@ -51,35 +96,19 @@ module Ionian
51
96
  block
52
97
  end
53
98
 
54
- # Register a block to be called when {Ionian::Extension::IO#run_match}
55
- # raises an error.
99
+ # Register a block to be called when there is a change in socket status.
56
100
  # Method callbacks can be registered with &object.method(:method).
57
101
  # @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
102
+ # @yield [status, self]
103
+ def register_status_handler &block
104
+ raise NotImplementedError
73
105
  end
74
106
 
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
107
+ alias_method :on_status_change, :register_status_handler
80
108
 
81
- def respond_to_missing? meth, *args
82
- @socket.respond_to? meth, *args
109
+ # Unregister a block from being called when there is a change in socket status.
110
+ def unregister_status_handler &block
111
+ raise NotImplementedError
83
112
  end
84
113
 
85
114
 
@@ -87,23 +116,39 @@ module Ionian
87
116
 
88
117
  # Initialize or reinitialize @socket.
89
118
  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
119
+ begin
120
+ @socket = Ionian::Socket.new **@kwargs
121
+
122
+ @socket.on_error &method(:socket_error_handler)
123
+ @match_handlers.each { |h| @socket.register_match_handler &h }
124
+ # @error_handlers.each { |h| @socket.register_error_handler &h }
125
+ rescue Errno::ECONNREFUSED, SystemCallError => e
126
+ if auto_reconnect
127
+ sleep @kwargs.fetch :connect_timeout, 10
128
+ retry
129
+ else
130
+ raise e
131
+ end
132
+ end
96
133
  end
97
134
 
98
135
  # {Ionian::Socket#on_error} handler for @socket.
99
136
  def socket_error_handler e, socket
100
137
  if auto_reconnect
101
- @socket.close unless @socket.closed?
138
+ @socket.close if @socket and not @socket.closed?
102
139
  create_socket
103
140
  else
104
141
  raise e unless e.is_a? EOFError or e.is_a? IOError
105
142
  end
106
143
  end
107
144
 
145
+ def notify_match_handlers match
146
+ @match_handlers.each { |h| h.call match, self }
147
+ end
148
+
149
+ def notify_error_handlers exception
150
+ @error_handlers.each { |h| h.call exception, self }
151
+ end
152
+
108
153
  end
109
154
  end
@@ -167,19 +167,27 @@ module Ionian
167
167
  end
168
168
  end
169
169
  end
170
+
171
+ # @return [IO] the file descriptor for this socket.
172
+ # For use with methods like IO.select.
173
+ def fd
174
+ @socket
175
+ end
170
176
 
171
- # Returns the regular expression used to match incoming data.
177
+ # @return [Regexp] the regular expression used to match incoming data.
172
178
  def expression
173
179
  @expression || @socket.expression
174
180
  end
175
181
 
176
182
  # Set the regular expression used to match incoming data.
183
+ # @param exp [Regexp, String] Match expression.
184
+ # @see Ionian::Extension::IO#expression=
177
185
  def expression= exp
178
186
  @expression = exp
179
187
  @socket.expression = exp if @socket
180
188
  end
181
189
 
182
- # Returns true if the socket remains open after writing data.
190
+ # @return [Boolean] True if the socket remains open after writing data.
183
191
  def persistent?
184
192
  @persistent == false || @persistent == nil ? false : true
185
193
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ionian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.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-28 00:00:00.000000000 Z
11
+ date: 2015-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '10.4'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '10.4'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: yard
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -72,42 +72,42 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 3.1.0
75
+ version: '3.1'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 3.1.0
82
+ version: '3.1'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec-its
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.0.1
89
+ version: '1.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 1.0.1
96
+ version: '1.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: fivemat
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '1.3'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '1.3'
111
111
  description: A library to simplify interaction with IO streams. This includes network
112
112
  sockets, file sockets, and serial streams like the console and RS232. Features regular
113
113
  expression matching and notification of received data.