ionian 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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