ionian 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6bcea8e76124f692dbb73310c5eb10545318c838
4
- data.tar.gz: 85c23350aa38dcce18ccbb9df3ac7fd32e1d6f05
3
+ metadata.gz: 81979c2c40c6fa759df1c49a2d5226edfb46ba18
4
+ data.tar.gz: 76e21b58efbdce773066a8f20c23f1a422df43e5
5
5
  SHA512:
6
- metadata.gz: f1c181e45023688d2b978c396a488e1614dbecc7d5b4b7e790cfed11db794d2df1de267510a20c3fbc83922853f166c20823bdf7a6260bb5a58060d23929f1c7
7
- data.tar.gz: 90d906bd4f2ca67bde0f4bb1dea8bdcc305ef9a6d85af1eea56bc3a5c58ff96bf87ed56e336214601facdd4b9195d057fb35b09c95a51ef59b36920e4298f3c7
6
+ metadata.gz: 239b709e5a1f3f112f238d01054d8e31d0b5f983ae4ef0093025f92573038f689ef1aa7f8425546afb7e53d8a8aac7e6d6d259a31bd38e023e3b78d433a06500
7
+ data.tar.gz: d8b5ab66d8ae1d31f0aa5d6046198eb34404e15af7711abce4ec09f43b1cecfcf16a0e0c71f31dee609ea8978081ad5369c1bd94787146f23de644f91c0bd5d9
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
6
 
7
- <title>module Ionian::Socket - RDoc Documentation</title>
7
+ <title>class Ionian::Socket - RDoc Documentation</title>
8
8
 
9
9
  <link href="../fonts.css" rel="stylesheet">
10
10
  <link href="../rdoc.css" rel="stylesheet">
@@ -21,7 +21,7 @@
21
21
  <script src="../js/darkfish.js"></script>
22
22
 
23
23
 
24
- <body id="top" role="document" class="module">
24
+ <body id="top" role="document" class="class">
25
25
  <nav role="navigation">
26
26
  <div id="project-navigation">
27
27
  <div id="home-section" role="banner" class="nav-section">
@@ -58,7 +58,14 @@
58
58
 
59
59
  <div id="class-metadata">
60
60
 
61
-
61
+ <div id="parent-class-section" class="nav-section">
62
+ <h3>Parent</h3>
63
+
64
+
65
+ <p class="link">Object
66
+
67
+ </div>
68
+
62
69
 
63
70
  <div id="extends-section" class="nav-section">
64
71
  <h3>Extended With Modules</h3>
@@ -66,7 +73,7 @@
66
73
  <ul class="link-list">
67
74
 
68
75
 
69
- <li><a class="extend" href="IO.html">Ionian::IO</a>
76
+ <li><a class="extend" href="Extension/Socket.html">Ionian::Extension::Socket</a>
70
77
 
71
78
 
72
79
  </ul>
@@ -78,13 +85,25 @@
78
85
 
79
86
  <ul class="link-list" role="directory">
80
87
 
81
- <li ><a href="#method-c-extended">::extended</a>
88
+ <li ><a href="#method-c-new">::new</a>
89
+
90
+ <li ><a href="#method-i-3C-3C">#&lt;&lt;</a>
91
+
92
+ <li ><a href="#method-i-closed-3F">#closed?</a>
93
+
94
+ <li ><a href="#method-i-cmd">#cmd</a>
95
+
96
+ <li ><a href="#method-i-flush">#flush</a>
97
+
98
+ <li ><a href="#method-i-has_data-3F">#has_data?</a>
82
99
 
83
- <li ><a href="#method-i-initialize_ionian_socket">#initialize_ionian_socket</a>
100
+ <li ><a href="#method-i-persistent-3F">#persistent?</a>
84
101
 
85
- <li ><a href="#method-i-no_delay">#no_delay</a>
102
+ <li ><a href="#method-i-protocol-3F">#protocol?</a>
86
103
 
87
- <li ><a href="#method-i-no_delay-3D">#no_delay=</a>
104
+ <li ><a href="#method-i-puts">#puts</a>
105
+
106
+ <li ><a href="#method-i-write">#write</a>
88
107
 
89
108
  </ul>
90
109
  </div>
@@ -92,21 +111,13 @@
92
111
  </div>
93
112
  </nav>
94
113
 
95
- <main role="main" aria-labelledby="module-Ionian::Socket">
96
- <h1 id="module-Ionian::Socket" class="module">
97
- module Ionian::Socket
114
+ <main role="main" aria-labelledby="class-Ionian::Socket">
115
+ <h1 id="class-Ionian::Socket" class="class">
116
+ class Ionian::Socket
98
117
  </h1>
99
118
 
100
119
  <section class="description">
101
120
 
102
- <p>A mixin for <a href="Socket.html">Socket</a> objects.</p>
103
-
104
- <p>This module was designed to be extended by instantiated objects that
105
- implement the standard library <a href="Socket.html">Socket</a> class.
106
- my_socket.extend <a href="Socket.html">Ionian::Socket</a></p>
107
-
108
- <p>Extending this module also extends <a href="IO.html">Ionian::IO</a>.</p>
109
-
110
121
  </section>
111
122
 
112
123
 
@@ -128,11 +139,11 @@ my_socket.extend <a href="Socket.html">Ionian::Socket</a></p>
128
139
  </header>
129
140
 
130
141
 
131
- <div id="method-c-extended" class="method-detail ">
142
+ <div id="method-c-new" class="method-detail ">
132
143
 
133
144
  <div class="method-heading">
134
- <span class="method-name">extended</span><span
135
- class="method-args">(obj)</span>
145
+ <span class="method-name">new</span><span
146
+ class="method-args">(**kvargs)</span>
136
147
 
137
148
  <span class="method-click-advice">click to toggle source</span>
138
149
 
@@ -141,16 +152,28 @@ my_socket.extend <a href="Socket.html">Ionian::Socket</a></p>
141
152
 
142
153
  <div class="method-description">
143
154
 
144
- <p>Called automaticallly when the object is extended with extend.</p>
155
+ <p>TODO NOTES</p>
156
+
157
+ <p>Always lazily instiantiate @socket, even when persistent? May not work with
158
+ forwarding method calls. Oh! Unless the forwarded methods check for @socket
159
+ to exist. Will persistent methods have to check for the socket not to be
160
+ closed as well?</p>
145
161
 
146
162
 
147
163
 
148
164
 
149
- <div class="method-source-code" id="extended-source">
165
+ <div class="method-source-code" id="new-source">
150
166
  <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 15</span>
151
- <span class="ruby-keyword">def</span> <span class="ruby-keyword">self</span>.<span class="ruby-identifier">extended</span>(<span class="ruby-identifier">obj</span>)
152
- <span class="ruby-identifier">obj</span>.<span class="ruby-identifier">extend</span> <span class="ruby-constant">Ionian</span><span class="ruby-operator">::</span><span class="ruby-constant">IO</span>
153
- <span class="ruby-identifier">obj</span>.<span class="ruby-identifier">initialize_ionian_socket</span>
167
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-operator">**</span><span class="ruby-identifier">kvargs</span>)
168
+ <span class="ruby-ivar">@socket</span> = <span class="ruby-keyword">nil</span>
169
+
170
+ <span class="ruby-ivar">@host</span> = <span class="ruby-identifier">kvargs</span>.<span class="ruby-identifier">fetch</span> <span class="ruby-value">:host</span>
171
+ <span class="ruby-ivar">@port</span> = <span class="ruby-identifier">kvargs</span>.<span class="ruby-identifier">fetch</span> <span class="ruby-value">:port</span>, <span class="ruby-value">23</span>
172
+ <span class="ruby-ivar">@expression</span> = <span class="ruby-identifier">kvargs</span>.<span class="ruby-identifier">fetch</span> <span class="ruby-value">:expression</span>, <span class="ruby-keyword">nil</span>
173
+ <span class="ruby-ivar">@protocol</span> = <span class="ruby-identifier">kvargs</span>.<span class="ruby-identifier">fetch</span> <span class="ruby-value">:protocol</span>, <span class="ruby-value">:tcp</span>
174
+ <span class="ruby-ivar">@persistent</span> = <span class="ruby-identifier">kvargs</span>.<span class="ruby-identifier">fetch</span> <span class="ruby-value">:persistent</span>, <span class="ruby-keyword">true</span>
175
+
176
+ <span class="ruby-identifier">create_socket</span> <span class="ruby-keyword">if</span> <span class="ruby-ivar">@persistent</span>
154
177
  <span class="ruby-keyword">end</span></pre>
155
178
  </div>
156
179
 
@@ -170,10 +193,38 @@ my_socket.extend <a href="Socket.html">Ionian::Socket</a></p>
170
193
  </header>
171
194
 
172
195
 
173
- <div id="method-i-initialize_ionian_socket" class="method-detail ">
196
+ <div id="method-i-3C-3C" class="method-detail method-alias">
197
+
198
+ <div class="method-heading">
199
+ <span class="method-name">&lt;&lt;</span><span
200
+ class="method-args">(string)</span>
201
+
202
+ </div>
203
+
204
+
205
+ <div class="method-description">
206
+
207
+
208
+
209
+
210
+
211
+
212
+ </div>
213
+
214
+
215
+
216
+
217
+ <div class="aliases">
218
+ Alias for: <a href="Socket.html#method-i-write">write</a>
219
+ </div>
220
+
221
+ </div>
222
+
223
+
224
+ <div id="method-i-closed-3F" class="method-detail ">
174
225
 
175
226
  <div class="method-heading">
176
- <span class="method-name">initialize_ionian_socket</span><span
227
+ <span class="method-name">closed?</span><span
177
228
  class="method-args">()</span>
178
229
 
179
230
  <span class="method-click-advice">click to toggle source</span>
@@ -183,14 +234,58 @@ my_socket.extend <a href="Socket.html">Ionian::Socket</a></p>
183
234
 
184
235
  <div class="method-description">
185
236
 
237
+ <p>Returns true if the socket is closed.</p>
238
+
239
+
240
+
241
+
242
+ <div class="method-source-code" id="closed-3F-source">
243
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 65</span>
244
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">closed?</span>
245
+ <span class="ruby-keyword">return</span> <span class="ruby-keyword">true</span> <span class="ruby-keyword">unless</span> <span class="ruby-ivar">@socket</span>
246
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">closed?</span>
247
+ <span class="ruby-keyword">end</span></pre>
248
+ </div>
249
+
250
+ </div>
251
+
252
+
253
+
254
+
255
+ </div>
256
+
257
+
258
+ <div id="method-i-cmd" class="method-detail ">
259
+
260
+ <div class="method-heading">
261
+ <span class="method-name">cmd</span><span
262
+ class="method-args">(string, **kvargs) { |match| ... }</span>
263
+
264
+ <span class="method-click-advice">click to toggle source</span>
186
265
 
266
+ </div>
267
+
268
+
269
+ <div class="method-description">
270
+
271
+ <p>Send a command (data) to the socket. Returns received matches. Block yields
272
+ received match. See <a
273
+ href="Extension/IO.html#method-i-read_match">Ionian::Extension::IO#read_match</a></p>
187
274
 
188
275
 
189
276
 
190
277
 
191
- <div class="method-source-code" id="initialize_ionian_socket-source">
192
- <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 20</span>
193
- <span class="ruby-keyword">def</span> <span class="ruby-identifier">initialize_ionian_socket</span>
278
+ <div class="method-source-code" id="cmd-source">
279
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 41</span>
280
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">cmd</span>(<span class="ruby-identifier">string</span>, <span class="ruby-operator">**</span><span class="ruby-identifier">kvargs</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)
281
+ <span class="ruby-identifier">create_socket</span> <span class="ruby-keyword">unless</span> <span class="ruby-ivar">@persistent</span>
282
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">write</span> <span class="ruby-identifier">string</span>
283
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">flush</span>
284
+
285
+ <span class="ruby-identifier">matches</span> = <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">read_match</span>(<span class="ruby-identifier">kvargs</span>) {<span class="ruby-operator">|</span><span class="ruby-identifier">match</span><span class="ruby-operator">|</span> <span class="ruby-keyword">yield</span> <span class="ruby-identifier">match</span> <span class="ruby-keyword">if</span> <span class="ruby-identifier">block_given?</span>}
286
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">close</span> <span class="ruby-keyword">unless</span> <span class="ruby-ivar">@persistent</span>
287
+
288
+ <span class="ruby-identifier">matches</span>
194
289
  <span class="ruby-keyword">end</span></pre>
195
290
  </div>
196
291
 
@@ -202,10 +297,10 @@ my_socket.extend <a href="Socket.html">Ionian::Socket</a></p>
202
297
  </div>
203
298
 
204
299
 
205
- <div id="method-i-no_delay" class="method-detail ">
300
+ <div id="method-i-flush" class="method-detail ">
206
301
 
207
302
  <div class="method-heading">
208
- <span class="method-name">no_delay</span><span
303
+ <span class="method-name">flush</span><span
209
304
  class="method-args">()</span>
210
305
 
211
306
  <span class="method-click-advice">click to toggle source</span>
@@ -215,17 +310,16 @@ my_socket.extend <a href="Socket.html">Ionian::Socket</a></p>
215
310
 
216
311
  <div class="method-description">
217
312
 
218
- <p>Returns true if the TCP_NODELAY flag is enabled (Nagle disabled). Otherwise
219
- false.</p>
313
+ <p>Flushes buffered data to the operating system. This method has no effect on
314
+ non-persistent sockets.</p>
220
315
 
221
316
 
222
317
 
223
318
 
224
- <div class="method-source-code" id="no_delay-source">
225
- <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 25</span>
226
- <span class="ruby-keyword">def</span> <span class="ruby-identifier">no_delay</span>
227
- <span class="ruby-identifier">nagle_disabled</span> = <span class="ruby-keyword">self</span>.<span class="ruby-identifier">getsockopt</span>(<span class="ruby-operator">::</span><span class="ruby-constant">Socket</span><span class="ruby-operator">::</span><span class="ruby-constant">IPPROTO_TCP</span>, <span class="ruby-operator">::</span><span class="ruby-constant">Socket</span><span class="ruby-operator">::</span><span class="ruby-constant">TCP_NODELAY</span>).<span class="ruby-identifier">data</span>.<span class="ruby-identifier">ord</span>
228
- <span class="ruby-identifier">nagle_disabled</span> <span class="ruby-operator">&gt;</span> <span class="ruby-value">0</span> <span class="ruby-operator">?</span> <span class="ruby-keyword">true</span> <span class="ruby-operator">:</span> <span class="ruby-keyword">false</span>
319
+ <div class="method-source-code" id="flush-source">
320
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 72</span>
321
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">flush</span>
322
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">flush</span> <span class="ruby-keyword">if</span> <span class="ruby-ivar">@persistent</span>
229
323
  <span class="ruby-keyword">end</span></pre>
230
324
  </div>
231
325
 
@@ -237,11 +331,11 @@ false.</p>
237
331
  </div>
238
332
 
239
333
 
240
- <div id="method-i-no_delay-3D" class="method-detail ">
334
+ <div id="method-i-has_data-3F" class="method-detail ">
241
335
 
242
336
  <div class="method-heading">
243
- <span class="method-name">no_delay=</span><span
244
- class="method-args">(value)</span>
337
+ <span class="method-name">has_data?</span><span
338
+ class="method-args">(**kvargs)</span>
245
339
 
246
340
  <span class="method-click-advice">click to toggle source</span>
247
341
 
@@ -250,17 +344,19 @@ false.</p>
250
344
 
251
345
  <div class="method-description">
252
346
 
253
- <p>Setting to true enables the TCP_NODELAY flag (disables Nagle). Setting to
254
- false disables the flag (enables Nagle).</p>
347
+ <p>Returns true if there is data in the receive buffer. Args:</p>
348
+
349
+ <pre>Timeout: Number of seconds to wait for data until
350
+ giving up. Set to nil for blocking.</pre>
255
351
 
256
352
 
257
353
 
258
354
 
259
- <div class="method-source-code" id="no_delay-3D-source">
260
- <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 32</span>
261
- <span class="ruby-keyword">def</span> <span class="ruby-identifier">no_delay=</span>(<span class="ruby-identifier">value</span>)
262
- <span class="ruby-identifier">disable_nagle</span> = <span class="ruby-identifier">value</span> <span class="ruby-operator">?</span> <span class="ruby-value">1</span> <span class="ruby-operator">:</span> <span class="ruby-value">0</span>
263
- <span class="ruby-keyword">self</span>.<span class="ruby-identifier">setsockopt</span> <span class="ruby-operator">::</span><span class="ruby-constant">Socket</span><span class="ruby-operator">::</span><span class="ruby-constant">IPPROTO_TCP</span>, <span class="ruby-operator">::</span><span class="ruby-constant">Socket</span><span class="ruby-operator">::</span><span class="ruby-constant">TCP_NODELAY</span>, <span class="ruby-identifier">disable_nagle</span>
355
+ <div class="method-source-code" id="has_data-3F-source">
356
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 59</span>
357
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">has_data?</span>(<span class="ruby-operator">**</span><span class="ruby-identifier">kvargs</span>)
358
+ <span class="ruby-keyword">return</span> <span class="ruby-keyword">false</span> <span class="ruby-keyword">unless</span> <span class="ruby-ivar">@socket</span>
359
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">has_data?</span> <span class="ruby-identifier">kvargs</span>
264
360
  <span class="ruby-keyword">end</span></pre>
265
361
  </div>
266
362
 
@@ -269,6 +365,155 @@ false disables the flag (enables Nagle).</p>
269
365
 
270
366
 
271
367
 
368
+ </div>
369
+
370
+
371
+ <div id="method-i-persistent-3F" class="method-detail ">
372
+
373
+ <div class="method-heading">
374
+ <span class="method-name">persistent?</span><span
375
+ class="method-args">()</span>
376
+
377
+ <span class="method-click-advice">click to toggle source</span>
378
+
379
+ </div>
380
+
381
+
382
+ <div class="method-description">
383
+
384
+ <p>Returns true if the socket remains open after writing data.</p>
385
+
386
+
387
+
388
+
389
+ <div class="method-source-code" id="persistent-3F-source">
390
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 34</span>
391
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">persistent?</span>
392
+ <span class="ruby-ivar">@persistent</span> <span class="ruby-operator">==</span> <span class="ruby-keyword">false</span> <span class="ruby-operator">||</span> <span class="ruby-ivar">@persistent</span> <span class="ruby-operator">==</span> <span class="ruby-keyword">nil</span> <span class="ruby-operator">?</span> <span class="ruby-keyword">false</span> <span class="ruby-operator">:</span> <span class="ruby-keyword">true</span>
393
+ <span class="ruby-keyword">end</span></pre>
394
+ </div>
395
+
396
+ </div>
397
+
398
+
399
+
400
+
401
+ </div>
402
+
403
+
404
+ <div id="method-i-protocol-3F" class="method-detail ">
405
+
406
+ <div class="method-heading">
407
+ <span class="method-name">protocol?</span><span
408
+ class="method-args">()</span>
409
+
410
+ <span class="method-click-advice">click to toggle source</span>
411
+
412
+ </div>
413
+
414
+
415
+ <div class="method-description">
416
+
417
+ <p>Returns a symbol of the type of protocol this socket uses: :tcp, :udp,
418
+ :unix</p>
419
+
420
+
421
+
422
+
423
+ <div class="method-source-code" id="protocol-3F-source">
424
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 29</span>
425
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">protocol?</span>
426
+ <span class="ruby-ivar">@protocol</span>
427
+ <span class="ruby-keyword">end</span></pre>
428
+ </div>
429
+
430
+ </div>
431
+
432
+
433
+
434
+
435
+ </div>
436
+
437
+
438
+ <div id="method-i-puts" class="method-detail ">
439
+
440
+ <div class="method-heading">
441
+ <span class="method-name">puts</span><span
442
+ class="method-args">(*string)</span>
443
+
444
+ <span class="method-click-advice">click to toggle source</span>
445
+
446
+ </div>
447
+
448
+
449
+ <div class="method-description">
450
+
451
+ <p>Writes the given string(s) to the socket and appends a newline character to
452
+ any string not already ending with one.</p>
453
+
454
+
455
+
456
+
457
+ <div class="method-source-code" id="puts-source">
458
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 78</span>
459
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">puts</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">string</span>)
460
+ <span class="ruby-keyword">self</span>.<span class="ruby-identifier">write</span> <span class="ruby-identifier">string</span>.<span class="ruby-identifier">map</span>{<span class="ruby-operator">|</span><span class="ruby-identifier">s</span><span class="ruby-operator">|</span> <span class="ruby-identifier">s</span>.<span class="ruby-identifier">chomp</span>}.<span class="ruby-identifier">join</span>(<span class="ruby-string">&quot;\n&quot;</span>) <span class="ruby-operator">+</span> <span class="ruby-string">&quot;\n&quot;</span>
461
+ <span class="ruby-keyword">end</span></pre>
462
+ </div>
463
+
464
+ </div>
465
+
466
+
467
+
468
+
469
+ </div>
470
+
471
+
472
+ <div id="method-i-write" class="method-detail ">
473
+
474
+ <div class="method-heading">
475
+ <span class="method-name">write</span><span
476
+ class="method-args">(string)</span>
477
+
478
+ <span class="method-click-advice">click to toggle source</span>
479
+
480
+ </div>
481
+
482
+
483
+ <div class="method-description">
484
+
485
+ <p>Writes the given string to the socket. Returns the number of bytes written.</p>
486
+
487
+
488
+
489
+
490
+ <div class="method-source-code" id="write-source">
491
+ <pre><span class="ruby-comment"># File lib/ionian/socket.rb, line 84</span>
492
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">write</span>(<span class="ruby-identifier">string</span>)
493
+ <span class="ruby-identifier">create_socket</span> <span class="ruby-keyword">unless</span> <span class="ruby-ivar">@persistent</span>
494
+ <span class="ruby-identifier">num_bytes</span> = <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">write</span> <span class="ruby-identifier">string</span>
495
+
496
+ <span class="ruby-keyword">unless</span> <span class="ruby-ivar">@persistent</span>
497
+ <span class="ruby-comment"># Read in data to prevent RST packets.</span>
498
+ <span class="ruby-identifier">has_data</span> = <span class="ruby-operator">::</span><span class="ruby-constant">IO</span>.<span class="ruby-identifier">select</span> [<span class="ruby-ivar">@socket</span>], <span class="ruby-keyword">nil</span>, <span class="ruby-keyword">nil</span>, <span class="ruby-value">0</span>
499
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">readpartial</span> <span class="ruby-value">0xFFFF</span> <span class="ruby-keyword">if</span> <span class="ruby-identifier">has_data</span>
500
+
501
+ <span class="ruby-ivar">@socket</span>.<span class="ruby-identifier">close</span>
502
+ <span class="ruby-keyword">end</span>
503
+
504
+ <span class="ruby-identifier">num_bytes</span>
505
+ <span class="ruby-keyword">end</span></pre>
506
+ </div>
507
+
508
+ </div>
509
+
510
+
511
+ <div class="aliases">
512
+ Also aliased as: <a href="Socket.html#method-i-3C-3C">&lt;&lt;</a>
513
+ </div>
514
+
515
+
516
+
272
517
  </div>
273
518
 
274
519
 
data/doc/Ionian.html CHANGED
@@ -72,10 +72,9 @@
72
72
 
73
73
  <section class="description">
74
74
 
75
- <p>A library to simplify interaction with <a href="Ionian/IO.html">IO</a>
76
- streams. This includes network sockets, file sockets, and serial streams
77
- like the console and RS232. Features regular expression matching and
78
- notification of received data.</p>
75
+ <p>A library to simplify interaction with IO streams. This includes network
76
+ sockets, file sockets, and serial streams like the console and RS232.
77
+ Features regular expression matching and notification of received data.</p>
79
78
 
80
79
  </section>
81
80
 
data/doc/created.rid CHANGED
@@ -1,4 +1,5 @@
1
- Sun, 01 Dec 2013 18:46:23 -0800
2
- lib/ionian.rb Sun, 01 Dec 2013 18:46:19 -0800
3
- lib/ionian/io.rb Sun, 01 Dec 2013 18:46:19 -0800
4
- lib/ionian/socket.rb Sun, 01 Dec 2013 18:46:19 -0800
1
+ Sun, 01 Dec 2013 18:46:48 -0800
2
+ lib/ionian.rb Sun, 01 Dec 2013 18:46:44 -0800
3
+ lib/ionian/extension/io.rb Sun, 01 Dec 2013 18:46:44 -0800
4
+ lib/ionian/extension/socket.rb Sun, 01 Dec 2013 18:46:44 -0800
5
+ lib/ionian/socket.rb Sun, 01 Dec 2013 18:46:44 -0800
data/doc/index.html CHANGED
@@ -64,7 +64,11 @@
64
64
 
65
65
  <li><a href="./Ionian.html">Ionian</a>
66
66
 
67
- <li><a href="./Ionian/IO.html">Ionian::IO</a>
67
+ <li><a href="./Ionian/Extension.html">Ionian::Extension</a>
68
+
69
+ <li><a href="./Ionian/Extension/IO.html">Ionian::Extension::IO</a>
70
+
71
+ <li><a href="./Ionian/Extension/Socket.html">Ionian::Extension::Socket</a>
68
72
 
69
73
  <li><a href="./Ionian/Socket.html">Ionian::Socket</a>
70
74
 
@@ -1 +1 @@
1
- var search_data = {"index":{"searchIndex":["ionian","io","socket","expression()","expression=()","extended()","extended()","initialize_ionian()","initialize_ionian_socket()","no_delay()","no_delay=()","on_match()","purge()","read_match()","register_observer()","run_match()","unregister_observer()"],"longSearchIndex":["ionian","ionian::io","ionian::socket","ionian::io#expression()","ionian::io#expression=()","ionian::io::extended()","ionian::socket::extended()","ionian::io#initialize_ionian()","ionian::socket#initialize_ionian_socket()","ionian::socket#no_delay()","ionian::socket#no_delay=()","ionian::io#on_match()","ionian::io#purge()","ionian::io#read_match()","ionian::io#register_observer()","ionian::io#run_match()","ionian::io#unregister_observer()"],"info":[["Ionian","","Ionian.html","","<p>A library to simplify interaction with IO streams. This includes network\nsockets, file sockets, and serial …\n"],["Ionian::IO","","Ionian/IO.html","","<p>A mixin for IO objects that allows regular expression matching and\nconvenient notification of received …\n"],["Ionian::Socket","","Ionian/Socket.html","","<p>A mixin for Socket objects.\n<p>This module was designed to be extended by instantiated objects that\nimplement …\n"],["expression","Ionian::IO","Ionian/IO.html#method-i-expression","()","<p>Returns the regular expression used for #read_match.\n"],["expression=","Ionian::IO","Ionian/IO.html#method-i-expression-3D","(exp)","<p>Set the expression to match against the read buffer. Can be a regular\nexpression specifying capture groups, …\n"],["extended","Ionian::IO","Ionian/IO.html#method-c-extended","(obj)","<p>Called automaticallly when the object is extended with #extend.\n"],["extended","Ionian::Socket","Ionian/Socket.html#method-c-extended","(obj)","<p>Called automaticallly when the object is extended with #extend.\n"],["initialize_ionian","Ionian::IO","Ionian/IO.html#method-i-initialize_ionian","()","<p>Initialize the Ionian instance variables. This is called automatically if\n#extend is called on an object. …\n"],["initialize_ionian_socket","Ionian::Socket","Ionian/Socket.html#method-i-initialize_ionian_socket","()",""],["no_delay","Ionian::Socket","Ionian/Socket.html#method-i-no_delay","()","<p>Returns true if the TCP_NODELAY flag is enabled (Nagle disabled). Otherwise\nfalse.\n"],["no_delay=","Ionian::Socket","Ionian/Socket.html#method-i-no_delay-3D","(value)","<p>Setting to true enables the TCP_NODELAY flag (disables Nagle). Setting to\nfalse disables the flag (enables …\n"],["on_match","Ionian::IO","Ionian/IO.html#method-i-on_match","(&block)",""],["purge","Ionian::IO","Ionian/IO.html#method-i-purge","()","<p>Erase the data in the IO and Ionian buffers. This is typically handled\nautomatically.\n"],["read_match","Ionian::IO","Ionian/IO.html#method-i-read_match","(**kvargs, &block)","<p>Read matched data from the buffer. This method SHOULD NOT be used if\n#run_match is used.\n<p>Passes matches …\n"],["register_observer","Ionian::IO","Ionian/IO.html#method-i-register_observer","(&block)","<p>Register a block to be called when #run_match receives matched data. Method\ncallbacks can be registered …\n"],["run_match","Ionian::IO","Ionian/IO.html#method-i-run_match","(**kvargs)","<p>Start a thread that checks for data and notifies listeners (do |match,\nsocket|). Passes kvargs to #read_match …\n"],["unregister_observer","Ionian::IO","Ionian/IO.html#method-i-unregister_observer","(&block)","<p>Unregister a block from being called when matched data is received.\n"]]}}
1
+ var search_data = {"index":{"searchIndex":["ionian","extension","io","socket","socket","<<()","closed?()","cmd()","expression()","expression=()","extended()","extended()","flush()","has_data?()","has_data?()","initialize_ionian()","initialize_ionian_socket()","new()","no_delay()","no_delay=()","on_match()","persistent?()","protocol?()","purge()","puts()","read_match()","register_observer()","run_match()","unregister_observer()","write()"],"longSearchIndex":["ionian","ionian::extension","ionian::extension::io","ionian::extension::socket","ionian::socket","ionian::socket#<<()","ionian::socket#closed?()","ionian::socket#cmd()","ionian::extension::io#expression()","ionian::extension::io#expression=()","ionian::extension::io::extended()","ionian::extension::socket::extended()","ionian::socket#flush()","ionian::extension::io#has_data?()","ionian::socket#has_data?()","ionian::extension::io#initialize_ionian()","ionian::extension::socket#initialize_ionian_socket()","ionian::socket::new()","ionian::extension::socket#no_delay()","ionian::extension::socket#no_delay=()","ionian::extension::io#on_match()","ionian::socket#persistent?()","ionian::socket#protocol?()","ionian::extension::io#purge()","ionian::socket#puts()","ionian::extension::io#read_match()","ionian::extension::io#register_observer()","ionian::extension::io#run_match()","ionian::extension::io#unregister_observer()","ionian::socket#write()"],"info":[["Ionian","","Ionian.html","","<p>A library to simplify interaction with IO streams. This includes network\nsockets, file sockets, and serial …\n"],["Ionian::Extension","","Ionian/Extension.html","",""],["Ionian::Extension::IO","","Ionian/Extension/IO.html","","<p>A mixin for IO objects that allows regular expression matching and\nconvenient notification of received …\n"],["Ionian::Extension::Socket","","Ionian/Extension/Socket.html","","<p>A mixin for Socket objects.\n<p>This module was designed to be extended by instantiated objects that\nimplement …\n"],["Ionian::Socket","","Ionian/Socket.html","",""],["<<","Ionian::Socket","Ionian/Socket.html#method-i-3C-3C","(string)",""],["closed?","Ionian::Socket","Ionian/Socket.html#method-i-closed-3F","()","<p>Returns true if the socket is closed.\n"],["cmd","Ionian::Socket","Ionian/Socket.html#method-i-cmd","(string, **kvargs, &block)","<p>Send a command (data) to the socket. Returns received matches. Block yields\nreceived match. See Ionian::Extension::IO#read_match …\n"],["expression","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-expression","()","<p>Returns the regular expression used for #read_match.\n"],["expression=","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-expression-3D","(exp)","<p>Set the expression to match against the read buffer. Can be a regular\nexpression specifying capture groups, …\n"],["extended","Ionian::Extension::IO","Ionian/Extension/IO.html#method-c-extended","(obj)","<p>Called automaticallly when the object is extended with #extend.\n"],["extended","Ionian::Extension::Socket","Ionian/Extension/Socket.html#method-c-extended","(obj)","<p>Called automaticallly when the object is extended with #extend.\n"],["flush","Ionian::Socket","Ionian/Socket.html#method-i-flush","()","<p>Flushes buffered data to the operating system. This method has no effect on\nnon-persistent sockets.\n"],["has_data?","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-has_data-3F","(timeout: 0)","<p>Returns true if there is data in the receive buffer. Args:\n\n<pre>Timeout: Number of seconds to wait for data ...</pre>\n"],["has_data?","Ionian::Socket","Ionian/Socket.html#method-i-has_data-3F","(**kvargs)","<p>Returns true if there is data in the receive buffer. Args:\n\n<pre>Timeout: Number of seconds to wait for data ...</pre>\n"],["initialize_ionian","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-initialize_ionian","()","<p>Initialize the Ionian instance variables. This is called automatically if\n#extend is called on an object. …\n"],["initialize_ionian_socket","Ionian::Extension::Socket","Ionian/Extension/Socket.html#method-i-initialize_ionian_socket","()",""],["new","Ionian::Socket","Ionian/Socket.html#method-c-new","(**kvargs)","<p>TODO NOTES\n<p>Always lazily instiantiate @socket, even when persistent? May not work with\nforwarding method …\n"],["no_delay","Ionian::Extension::Socket","Ionian/Extension/Socket.html#method-i-no_delay","()","<p>Returns true if the TCP_NODELAY flag is enabled (Nagle disabled). Otherwise\nfalse.\n"],["no_delay=","Ionian::Extension::Socket","Ionian/Extension/Socket.html#method-i-no_delay-3D","(value)","<p>Setting to true enables the TCP_NODELAY flag (disables Nagle). Setting to\nfalse disables the flag (enables …\n"],["on_match","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-on_match","(&block)",""],["persistent?","Ionian::Socket","Ionian/Socket.html#method-i-persistent-3F","()","<p>Returns true if the socket remains open after writing data.\n"],["protocol?","Ionian::Socket","Ionian/Socket.html#method-i-protocol-3F","()","<p>Returns a symbol of the type of protocol this socket uses: :tcp, :udp,\n:unix\n"],["purge","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-purge","()","<p>Erase the data in the IO and Ionian buffers. This is typically handled\nautomatically.\n"],["puts","Ionian::Socket","Ionian/Socket.html#method-i-puts","(*string)","<p>Writes the given string(s) to the socket and appends a newline character to\nany string not already ending …\n"],["read_match","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-read_match","(**kvargs, &block)","<p>Read matched data from the buffer. This method SHOULD NOT be used if\n#run_match is used.\n<p>Passes matches …\n"],["register_observer","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-register_observer","(&block)","<p>Register a block to be called when #run_match receives matched data. Method\ncallbacks can be registered …\n"],["run_match","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-run_match","(**kvargs)","<p>Start a thread that checks for data and notifies listeners (do |match,\nsocket|). Passes kvargs to #read_match …\n"],["unregister_observer","Ionian::Extension::IO","Ionian/Extension/IO.html#method-i-unregister_observer","(&block)","<p>Unregister a block from being called when matched data is received.\n"],["write","Ionian::Socket","Ionian/Socket.html#method-i-write","(string)","<p>Writes the given string to the socket. Returns the number of bytes written.\n"]]}}
@@ -32,9 +32,15 @@
32
32
  <a href="Ionian.html">Ionian</a>
33
33
  </li>
34
34
  <li class="module">
35
- <a href="Ionian/IO.html">Ionian::IO</a>
35
+ <a href="Ionian/Extension.html">Ionian::Extension</a>
36
36
  </li>
37
37
  <li class="module">
38
+ <a href="Ionian/Extension/IO.html">Ionian::Extension::IO</a>
39
+ </li>
40
+ <li class="module">
41
+ <a href="Ionian/Extension/Socket.html">Ionian::Extension::Socket</a>
42
+ </li>
43
+ <li class="class">
38
44
  <a href="Ionian/Socket.html">Ionian::Socket</a>
39
45
  </li>
40
46
  </ul>
@@ -43,74 +49,129 @@
43
49
  <ul>
44
50
 
45
51
  <li class="method">
46
- <a href="Ionian/IO.html#method-c-extended">::extended</a>
52
+ <a href="Ionian/Extension/IO.html#method-c-extended">::extended</a>
53
+ &mdash;
54
+ <span class="container">Ionian::Extension::IO</span>
55
+
56
+ <li class="method">
57
+ <a href="Ionian/Extension/Socket.html#method-c-extended">::extended</a>
47
58
  &mdash;
48
- <span class="container">Ionian::IO</span>
59
+ <span class="container">Ionian::Extension::Socket</span>
49
60
 
50
61
  <li class="method">
51
- <a href="Ionian/Socket.html#method-c-extended">::extended</a>
62
+ <a href="Ionian/Socket.html#method-c-new">::new</a>
52
63
  &mdash;
53
64
  <span class="container">Ionian::Socket</span>
54
65
 
55
66
  <li class="method">
56
- <a href="Ionian/IO.html#method-i-expression">#expression</a>
67
+ <a href="Ionian/Socket.html#method-i-3C-3C">#&lt;&lt;</a>
57
68
  &mdash;
58
- <span class="container">Ionian::IO</span>
69
+ <span class="container">Ionian::Socket</span>
59
70
 
60
71
  <li class="method">
61
- <a href="Ionian/IO.html#method-i-expression-3D">#expression=</a>
72
+ <a href="Ionian/Socket.html#method-i-closed-3F">#closed?</a>
62
73
  &mdash;
63
- <span class="container">Ionian::IO</span>
74
+ <span class="container">Ionian::Socket</span>
64
75
 
65
76
  <li class="method">
66
- <a href="Ionian/IO.html#method-i-initialize_ionian">#initialize_ionian</a>
77
+ <a href="Ionian/Socket.html#method-i-cmd">#cmd</a>
67
78
  &mdash;
68
- <span class="container">Ionian::IO</span>
79
+ <span class="container">Ionian::Socket</span>
69
80
 
70
81
  <li class="method">
71
- <a href="Ionian/Socket.html#method-i-initialize_ionian_socket">#initialize_ionian_socket</a>
82
+ <a href="Ionian/Extension/IO.html#method-i-expression">#expression</a>
83
+ &mdash;
84
+ <span class="container">Ionian::Extension::IO</span>
85
+
86
+ <li class="method">
87
+ <a href="Ionian/Extension/IO.html#method-i-expression-3D">#expression=</a>
88
+ &mdash;
89
+ <span class="container">Ionian::Extension::IO</span>
90
+
91
+ <li class="method">
92
+ <a href="Ionian/Socket.html#method-i-flush">#flush</a>
93
+ &mdash;
94
+ <span class="container">Ionian::Socket</span>
95
+
96
+ <li class="method">
97
+ <a href="Ionian/Socket.html#method-i-has_data-3F">#has_data?</a>
72
98
  &mdash;
73
99
  <span class="container">Ionian::Socket</span>
74
100
 
75
101
  <li class="method">
76
- <a href="Ionian/Socket.html#method-i-no_delay">#no_delay</a>
102
+ <a href="Ionian/Extension/IO.html#method-i-has_data-3F">#has_data?</a>
103
+ &mdash;
104
+ <span class="container">Ionian::Extension::IO</span>
105
+
106
+ <li class="method">
107
+ <a href="Ionian/Extension/IO.html#method-i-initialize_ionian">#initialize_ionian</a>
108
+ &mdash;
109
+ <span class="container">Ionian::Extension::IO</span>
110
+
111
+ <li class="method">
112
+ <a href="Ionian/Extension/Socket.html#method-i-initialize_ionian_socket">#initialize_ionian_socket</a>
113
+ &mdash;
114
+ <span class="container">Ionian::Extension::Socket</span>
115
+
116
+ <li class="method">
117
+ <a href="Ionian/Extension/Socket.html#method-i-no_delay">#no_delay</a>
118
+ &mdash;
119
+ <span class="container">Ionian::Extension::Socket</span>
120
+
121
+ <li class="method">
122
+ <a href="Ionian/Extension/Socket.html#method-i-no_delay-3D">#no_delay=</a>
123
+ &mdash;
124
+ <span class="container">Ionian::Extension::Socket</span>
125
+
126
+ <li class="method">
127
+ <a href="Ionian/Extension/IO.html#method-i-on_match">#on_match</a>
128
+ &mdash;
129
+ <span class="container">Ionian::Extension::IO</span>
130
+
131
+ <li class="method">
132
+ <a href="Ionian/Socket.html#method-i-persistent-3F">#persistent?</a>
77
133
  &mdash;
78
134
  <span class="container">Ionian::Socket</span>
79
135
 
80
136
  <li class="method">
81
- <a href="Ionian/Socket.html#method-i-no_delay-3D">#no_delay=</a>
137
+ <a href="Ionian/Socket.html#method-i-protocol-3F">#protocol?</a>
82
138
  &mdash;
83
139
  <span class="container">Ionian::Socket</span>
84
140
 
85
141
  <li class="method">
86
- <a href="Ionian/IO.html#method-i-on_match">#on_match</a>
142
+ <a href="Ionian/Extension/IO.html#method-i-purge">#purge</a>
87
143
  &mdash;
88
- <span class="container">Ionian::IO</span>
144
+ <span class="container">Ionian::Extension::IO</span>
89
145
 
90
146
  <li class="method">
91
- <a href="Ionian/IO.html#method-i-purge">#purge</a>
147
+ <a href="Ionian/Socket.html#method-i-puts">#puts</a>
92
148
  &mdash;
93
- <span class="container">Ionian::IO</span>
149
+ <span class="container">Ionian::Socket</span>
94
150
 
95
151
  <li class="method">
96
- <a href="Ionian/IO.html#method-i-read_match">#read_match</a>
152
+ <a href="Ionian/Extension/IO.html#method-i-read_match">#read_match</a>
97
153
  &mdash;
98
- <span class="container">Ionian::IO</span>
154
+ <span class="container">Ionian::Extension::IO</span>
99
155
 
100
156
  <li class="method">
101
- <a href="Ionian/IO.html#method-i-register_observer">#register_observer</a>
157
+ <a href="Ionian/Extension/IO.html#method-i-register_observer">#register_observer</a>
102
158
  &mdash;
103
- <span class="container">Ionian::IO</span>
159
+ <span class="container">Ionian::Extension::IO</span>
104
160
 
105
161
  <li class="method">
106
- <a href="Ionian/IO.html#method-i-run_match">#run_match</a>
162
+ <a href="Ionian/Extension/IO.html#method-i-run_match">#run_match</a>
107
163
  &mdash;
108
- <span class="container">Ionian::IO</span>
164
+ <span class="container">Ionian::Extension::IO</span>
109
165
 
110
166
  <li class="method">
111
- <a href="Ionian/IO.html#method-i-unregister_observer">#unregister_observer</a>
167
+ <a href="Ionian/Extension/IO.html#method-i-unregister_observer">#unregister_observer</a>
112
168
  &mdash;
113
- <span class="container">Ionian::IO</span>
169
+ <span class="container">Ionian::Extension::IO</span>
170
+
171
+ <li class="method">
172
+ <a href="Ionian/Socket.html#method-i-write">#write</a>
173
+ &mdash;
174
+ <span class="container">Ionian::Socket</span>
114
175
  </ul>
115
176
  </main>
116
177
 
@@ -0,0 +1,165 @@
1
+ module Ionian
2
+ module Extension
3
+ # A mixin for IO objects that allows regular expression matching
4
+ # and convenient notification of received data.
5
+ #
6
+ # This module was designed to be extended by instantiated objects
7
+ # that implement the standard library IO class.
8
+ # my_socket.extend Ionian::IO
9
+ module IO
10
+ # Number of seconds to attempt an IO operation before timing out.
11
+ # See standard library IO::select.
12
+ attr_accessor :ionian_timeout
13
+
14
+ # Called automaticallly when the object is extended with #extend.
15
+ def self.extended(obj)
16
+ obj.initialize_ionian
17
+ end
18
+
19
+ # Initialize the Ionian instance variables.
20
+ # This is called automatically if #extend is called on an object.
21
+ def initialize_ionian
22
+ @ionian_listeners = []
23
+ @ionian_buf = ''
24
+ @ionian_expression = /(.*?)\n/
25
+ @ionian_timeout = nil
26
+ @ionian_skip_select = false
27
+ @ionian_build_methods = true
28
+ end
29
+
30
+ # Returns true if there is data in the receive buffer.
31
+ # Args:
32
+ # Timeout: Number of seconds to wait for data until
33
+ # giving up. Set to nil for blocking.
34
+ def has_data?(timeout: 0)
35
+ ::IO.select([self], nil, nil, timeout) ? true : false
36
+ end
37
+
38
+ # Returns the regular expression used for #read_match.
39
+ def expression
40
+ @ionian_expression
41
+ end
42
+
43
+ # Set the expression to match against the read buffer.
44
+ # Can be a regular expression specifying capture groups,
45
+ # or a string specifying the separator or line terminator
46
+ # sequence. It is possible to use named captures in a
47
+ # regex, which allows for convienient accessors like
48
+ # match[:parameter].
49
+ def expression=(exp)
50
+ @ionian_expression = exp
51
+ @ionian_expression = Regexp.new "(.*?)#{expression}" if exp.is_a? String
52
+ end
53
+
54
+ # Read matched data from the buffer.
55
+ # This method SHOULD NOT be used if #run_match is used.
56
+ #
57
+ # Passes matches to the block (do |match|). If there are multiple
58
+ # matches, the block is called multiple times.
59
+ #
60
+ # Returns an array of matches.
61
+ # Returns nil if no data was received within the timeout period.
62
+ #
63
+ # Junk data that could exist before a match in the buffer can
64
+ # be accessed with match.pre_match.
65
+ #
66
+ # Data at the end of the buffer that is not matched can be accessed
67
+ # in the last match with match.post_match. This data remains in the
68
+ # buffer for the next #read_match cycle. This is helpful for protocols
69
+ # like RS232 that do not have packet boundries.
70
+ #
71
+ # kvargs:
72
+ # timeout: Timeout in seconds IO::select will block.
73
+ # skip_select: Skip over the IO::select statement. Use if you
74
+ # are calling IO::select ahead of this method.
75
+ # build_methods: Build method accessors from named captures.
76
+ # Enabled by default.
77
+ def read_match(**kvargs, &block)
78
+ timeout = kvargs.fetch :timeout, @ionian_timeout
79
+ skip_select = kvargs.fetch :skip_select, @ionian_skip_select
80
+ build_methods = kvargs.fetch :build_methods, @ionian_build_methods
81
+
82
+ unless skip_select
83
+ return nil unless ::IO.select [self], nil, nil, timeout
84
+ end
85
+
86
+ # Read data from the IO buffer until it's empty.
87
+ loop do
88
+ @ionian_buf << readpartial(0xFFFF)
89
+ break unless ::IO.select [self], nil, nil, 0
90
+ end
91
+
92
+ @matches = []
93
+
94
+ while @ionian_buf =~ @ionian_expression
95
+ @matches << $~ # Match data.
96
+ yield $~ if block_given?
97
+ @ionian_buf = $' # Leave post match data in the buffer.
98
+ end
99
+
100
+ # Convert named captures to methods.
101
+ if build_methods
102
+ @matches.each do |match|
103
+ match.names
104
+ .map {|name| name.to_sym}
105
+ .each {|symbol| match.singleton_class
106
+ .send(:define_method, symbol) { match[symbol] } \
107
+ unless match.respond_to? symbol
108
+ }
109
+ end
110
+ end
111
+
112
+ @matches
113
+ end
114
+
115
+ # Start a thread that checks for data and notifies listeners (do |match, socket|).
116
+ # Passes kvargs to #read_match.
117
+ # This method SHOULD NOT be used if #read_match is used.
118
+ def run_match(**kvargs)
119
+ @match_listener ||= Thread.new do
120
+ begin
121
+ while not closed? do
122
+ matches = read_match kvargs
123
+ matches.each {|match|
124
+ @ionian_listeners.each {|listener| listener.call match, self}
125
+ } if matches
126
+ end
127
+ rescue EOFError
128
+ rescue IOError
129
+ ensure
130
+ @match_listener = nil
131
+ end
132
+ end
133
+ end
134
+
135
+ # Erase the data in the IO and Ionian buffers.
136
+ # This is typically handled automatically.
137
+ def purge
138
+ # Erase IO buffer.
139
+ while ::IO.select [self], nil, nil, 0
140
+ readpartial(0xFFFF)
141
+ end
142
+
143
+ @ionian_buf = ''
144
+ end
145
+
146
+ # Register a block to be called when #run_match receives matched data.
147
+ # Method callbacks can be registered with &object.method(:method).
148
+ # Returns a reference to the given block.
149
+ # block = ionian_socket.register_observer {...}
150
+ def register_observer(&block)
151
+ @ionian_listeners << block unless @ionian_listeners.include? block
152
+ block
153
+ end
154
+
155
+ alias_method :on_match, :register_observer
156
+
157
+ # Unregister a block from being called when matched data is received.
158
+ def unregister_observer(&block)
159
+ @ionian_listeners.delete_if {|o| o == block}
160
+ block
161
+ end
162
+
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,40 @@
1
+ require 'ionian/extension/io'
2
+ require 'socket'
3
+
4
+ module Ionian
5
+ module Extension
6
+ # A mixin for Socket objects.
7
+ #
8
+ # This module was designed to be extended by instantiated objects
9
+ # that implement the standard library Socket class.
10
+ # my_socket.extend Ionian::Socket
11
+ #
12
+ # Extending this module also extends Ionian::IO.
13
+ module Socket
14
+
15
+ # Called automaticallly when the object is extended with #extend.
16
+ def self.extended(obj)
17
+ obj.extend Ionian::Extension::IO
18
+ obj.initialize_ionian_socket
19
+ end
20
+
21
+ def initialize_ionian_socket
22
+ end
23
+
24
+ # Returns true if the TCP_NODELAY flag is enabled (Nagle disabled).
25
+ # Otherwise false.
26
+ def no_delay
27
+ nagle_disabled = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY).data.ord
28
+ nagle_disabled > 0 ? true : false
29
+ end
30
+
31
+ # Setting to true enables the TCP_NODELAY flag (disables Nagle).
32
+ # Setting to false disables the flag (enables Nagle).
33
+ def no_delay=(value)
34
+ disable_nagle = value ? 1 : 0
35
+ self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, disable_nagle
36
+ end
37
+
38
+ end
39
+ end
40
+ end
data/lib/ionian/socket.rb CHANGED
@@ -1,37 +1,147 @@
1
- require 'ionian/io'
2
- require 'socket'
1
+ require 'ionian/extension/socket'
3
2
 
4
3
  module Ionian
5
- # A mixin for Socket objects.
6
- #
7
- # This module was designed to be extended by instantiated objects
8
- # that implement the standard library Socket class.
9
- # my_socket.extend Ionian::Socket
10
- #
11
- # Extending this module also extends Ionian::IO.
12
- module Socket
4
+ class Socket
13
5
 
14
- # Called automaticallly when the object is extended with #extend.
15
- def self.extended(obj)
16
- obj.extend Ionian::IO
17
- obj.initialize_ionian_socket
6
+ ############
7
+ # TODO NOTES
8
+ ############
9
+ # Always lazily instiantiate @socket, even when persistent?
10
+ # May not work with forwarding method calls.
11
+ # Oh! Unless the forwarded methods check for @socket to exist.
12
+ # Will persistent methods have to check for the socket not to be
13
+ # closed as well?
14
+
15
+ def initialize(**kvargs)
16
+ @socket = nil
17
+
18
+ @host = kvargs.fetch :host
19
+ @port = kvargs.fetch :port, 23
20
+ @expression = kvargs.fetch :expression, nil
21
+ @protocol = kvargs.fetch :protocol, :tcp
22
+ @persistent = kvargs.fetch :persistent, true
23
+
24
+ create_socket if @persistent
25
+ end
26
+
27
+ # Returns a symbol of the type of protocol this socket uses:
28
+ # :tcp, :udp, :unix
29
+ def protocol?
30
+ @protocol
31
+ end
32
+
33
+ # Returns true if the socket remains open after writing data.
34
+ def persistent?
35
+ @persistent == false || @persistent == nil ? false : true
36
+ end
37
+
38
+ # Send a command (data) to the socket. Returns received matches.
39
+ # Block yields received match.
40
+ # See Ionian::Extension::IO#read_match
41
+ def cmd(string, **kvargs, &block)
42
+ create_socket unless @persistent
43
+ @socket.write string
44
+ @socket.flush
45
+
46
+ matches = @socket.read_match(kvargs) {|match| yield match if block_given?}
47
+ @socket.close unless @persistent
48
+
49
+ matches
50
+ end
51
+
52
+
53
+ ### Methods Forwarded To @socket ###
54
+
55
+ # Returns true if there is data in the receive buffer.
56
+ # Args:
57
+ # Timeout: Number of seconds to wait for data until
58
+ # giving up. Set to nil for blocking.
59
+ def has_data?(**kvargs)
60
+ return false unless @socket
61
+ @socket.has_data? kvargs
18
62
  end
19
63
 
20
- def initialize_ionian_socket
64
+ # Returns true if the socket is closed.
65
+ def closed?
66
+ return true unless @socket
67
+ @socket.closed?
21
68
  end
22
69
 
23
- # Returns true if the TCP_NODELAY flag is enabled (Nagle disabled).
24
- # Otherwise false.
25
- def no_delay
26
- nagle_disabled = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY).data.ord
27
- nagle_disabled > 0 ? true : false
70
+ # Flushes buffered data to the operating system.
71
+ # This method has no effect on non-persistent sockets.
72
+ def flush
73
+ @socket.flush if @persistent
74
+ end
75
+
76
+ # Writes the given string(s) to the socket and appends a
77
+ # newline character to any string not already ending with one.
78
+ def puts(*string)
79
+ self.write string.map{|s| s.chomp}.join("\n") + "\n"
80
+ end
81
+
82
+ # Writes the given string to the socket. Returns the number of
83
+ # bytes written.
84
+ def write(string)
85
+ create_socket unless @persistent
86
+ num_bytes = @socket.write string
87
+
88
+ unless @persistent
89
+ # Read in data to prevent RST packets.
90
+ has_data = ::IO.select [@socket], nil, nil, 0
91
+ @socket.readpartial 0xFFFF if has_data
92
+
93
+ @socket.close
94
+ end
95
+
96
+ num_bytes
97
+ end
98
+
99
+ alias_method :<<, :write
100
+
101
+
102
+ private
103
+
104
+ def create_socket
105
+ @socket.close if @socket and not @socket.closed?
106
+
107
+ case @protocol
108
+ when :tcp
109
+ @socket = ::TCPSocket.new @host, @port
110
+ when :udp
111
+ @socket = ::UDPSocket.new
112
+ @socket.connect @host, @port
113
+ when :unix
114
+ @socket = ::UNIXSocket.new @host
115
+ end
116
+
117
+ @socket.extend Ionian::Extension::Socket
118
+ @socket.expression = @expression if @expression
119
+
120
+ initialize_socket_methods
28
121
  end
29
122
 
30
- # Setting to true enables the TCP_NODELAY flag (disables Nagle).
31
- # Setting to false disables the flag (enables Nagle).
32
- def no_delay=(value)
33
- disable_nagle = value ? 1 : 0
34
- self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, disable_nagle
123
+ # Expose the @socket methods that haven't been defined by this class.
124
+ # Only do this once for performance -- when non-persistent sockets are
125
+ # recreated, they should be of the same type of socket.
126
+ def initialize_socket_methods
127
+ # Only initialize once, lazily.
128
+ # For non-persistent sockets, this forwards the socket methods
129
+ # the first time data is sent -- when the new socket is created.
130
+ return if @socket_methods_initialized
131
+
132
+ # Forward undefined methods to @socket.
133
+ # This was chosen over method_missing to avoid traversing the object
134
+ # hierarchy on every method call, like transmitting data.
135
+ @socket.methods
136
+ .select {|m| @socket.respond_to? m}
137
+ .select {|m| not self.respond_to? m}
138
+ .each do |m|
139
+ self.singleton_class.send :define_method, m do |*args, &block|
140
+ @socket.__send__ m, *args, &block
141
+ end
142
+ end
143
+
144
+ @socket_methods_initialized = true
35
145
  end
36
146
 
37
147
  end
data/lib/ionian.rb CHANGED
@@ -1,4 +1,5 @@
1
- require 'ionian/io'
1
+ require 'ionian/extension/io'
2
+ require 'ionian/extension/socket'
2
3
  require 'ionian/socket'
3
4
 
4
5
  # A library to simplify interaction with IO streams.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ionian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McLain
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: minitest
56
+ name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -75,8 +75,9 @@ extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
77
  - license.txt
78
+ - lib/ionian/extension/socket.rb
79
+ - lib/ionian/extension/io.rb
78
80
  - lib/ionian/socket.rb
79
- - lib/ionian/io.rb
80
81
  - lib/ionian.rb
81
82
  - doc/fonts/SourceCodePro-Regular.ttf
82
83
  - doc/fonts/SourceCodePro-Bold.ttf
data/lib/ionian/io.rb DELETED
@@ -1,155 +0,0 @@
1
- module Ionian
2
- # A mixin for IO objects that allows regular expression matching
3
- # and convenient notification of received data.
4
- #
5
- # This module was designed to be extended by instantiated objects
6
- # that implement the standard library IO class.
7
- # my_socket.extend Ionian::IO
8
- module IO
9
- # Number of seconds to attempt an IO operation before timing out.
10
- # See standard library IO::select.
11
- attr_accessor :ionian_timeout
12
-
13
- # Called automaticallly when the object is extended with #extend.
14
- def self.extended(obj)
15
- obj.initialize_ionian
16
- end
17
-
18
- # Initialize the Ionian instance variables.
19
- # This is called automatically if #extend is called on an object.
20
- def initialize_ionian
21
- @ionian_listeners = []
22
- @ionian_buf = ''
23
- @ionian_expression = /(.*?)\n/
24
- @ionian_timeout = nil
25
- @ionian_skip_select = false
26
- @ionian_build_methods = true
27
- end
28
-
29
- # Returns the regular expression used for #read_match.
30
- def expression
31
- @ionian_expression
32
- end
33
-
34
- # Set the expression to match against the read buffer.
35
- # Can be a regular expression specifying capture groups,
36
- # or a string specifying the separator or line terminator
37
- # sequence. It is possible to use named captures in a
38
- # regex, which allows for convienient accessors like
39
- # match[:parameter].
40
- def expression=(exp)
41
- @ionian_expression = exp
42
- @ionian_expression = Regexp.new "(.*?)#{expression}" if exp.is_a? String
43
- end
44
-
45
- # Read matched data from the buffer.
46
- # This method SHOULD NOT be used if #run_match is used.
47
- #
48
- # Passes matches to the block (do |match|). If there are multiple
49
- # matches, the block is called multiple times.
50
- #
51
- # Returns an array of matches.
52
- # Returns nil if no data was received within the timeout period.
53
- #
54
- # Junk data that could exist before a match in the buffer can
55
- # be accessed with match.pre_match.
56
- #
57
- # Data at the end of the buffer that is not matched can be accessed
58
- # in the last match with match.post_match. This data remains in the
59
- # buffer for the next #read_match cycle. This is helpful for protocols
60
- # like RS232 that do not have packet boundries.
61
- #
62
- # kvargs:
63
- # timeout: Timeout in seconds IO::select will block.
64
- # skip_select: Skip over the IO::select statement. Use if you
65
- # are calling IO::select ahead of this method.
66
- # build_methods: Build method accessors from named captures.
67
- # Enabled by default.
68
- def read_match(**kvargs, &block)
69
- timeout = kvargs.fetch :timeout, @ionian_timeout
70
- skip_select = kvargs.fetch :skip_select, @ionian_skip_select
71
- build_methods = kvargs.fetch :build_methods, @ionian_build_methods
72
-
73
- unless skip_select
74
- return nil unless ::IO.select [self], nil, nil, timeout
75
- end
76
-
77
- # Read data from the IO buffer until it's empty.
78
- loop do
79
- @ionian_buf << readpartial(0xFFFF)
80
- break unless ::IO.select [self], nil, nil, 0
81
- end
82
-
83
- @matches = []
84
-
85
- while @ionian_buf =~ @ionian_expression
86
- @matches << $~ # Match data.
87
- yield $~ if block_given?
88
- @ionian_buf = $' # Leave post match data in the buffer.
89
- end
90
-
91
- # Convert named captures to methods.
92
- if build_methods
93
- @matches.each do |match|
94
- match.names
95
- .map {|name| name.to_sym}
96
- .each {|symbol| match.singleton_class
97
- .send(:define_method, symbol) { match[symbol] } \
98
- unless match.respond_to? symbol
99
- }
100
- end
101
- end
102
-
103
- @matches
104
- end
105
-
106
- # Start a thread that checks for data and notifies listeners (do |match, socket|).
107
- # Passes kvargs to #read_match.
108
- # This method SHOULD NOT be used if #read_match is used.
109
- def run_match(**kvargs)
110
- @match_listener ||= Thread.new do
111
- begin
112
- while not closed? do
113
- matches = read_match kvargs
114
- matches.each {|match|
115
- @ionian_listeners.each {|listener| listener.call match, self}
116
- } if matches
117
- end
118
- rescue EOFError
119
- rescue IOError
120
- end
121
-
122
- @match_listener = nil
123
- end
124
- end
125
-
126
- # Erase the data in the IO and Ionian buffers.
127
- # This is typically handled automatically.
128
- def purge
129
- # Erase IO buffer.
130
- while ::IO.select [self], nil, nil, 0
131
- readpartial(0xFFFF)
132
- end
133
-
134
- @ionian_buf = ''
135
- end
136
-
137
- # Register a block to be called when #run_match receives matched data.
138
- # Method callbacks can be registered with &object.method(:method).
139
- # Returns a reference to the given block.
140
- # block = ionian_socket.register_observer {...}
141
- def register_observer(&block)
142
- @ionian_listeners << block unless @ionian_listeners.include? block
143
- block
144
- end
145
-
146
- alias_method :on_match, :register_observer
147
-
148
- # Unregister a block from being called when matched data is received.
149
- def unregister_observer(&block)
150
- @ionian_listeners.delete_if {|o| o == block}
151
- block
152
- end
153
-
154
- end
155
- end