bunny 0.6.3.rc2 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +15 -0
  4. data/.yardopts +9 -0
  5. data/CHANGELOG +3 -0
  6. data/Gemfile +39 -0
  7. data/Gemfile.lock +34 -0
  8. data/LICENSE +5 -4
  9. data/README.textile +54 -0
  10. data/Rakefile +15 -13
  11. data/bunny.gemspec +42 -61
  12. data/examples/simple_08.rb +4 -2
  13. data/examples/simple_09.rb +4 -2
  14. data/examples/simple_ack_08.rb +3 -1
  15. data/examples/simple_ack_09.rb +3 -1
  16. data/examples/simple_consumer_08.rb +4 -2
  17. data/examples/simple_consumer_09.rb +4 -2
  18. data/examples/simple_fanout_08.rb +3 -1
  19. data/examples/simple_fanout_09.rb +3 -1
  20. data/examples/simple_headers_08.rb +5 -3
  21. data/examples/simple_headers_09.rb +5 -3
  22. data/examples/simple_publisher_08.rb +3 -1
  23. data/examples/simple_publisher_09.rb +3 -1
  24. data/examples/simple_topic_08.rb +5 -3
  25. data/examples/simple_topic_09.rb +5 -3
  26. data/ext/amqp-0.8.json +616 -0
  27. data/ext/amqp-0.9.1.json +388 -0
  28. data/ext/config.yml +4 -0
  29. data/ext/qparser.rb +463 -0
  30. data/lib/bunny.rb +88 -66
  31. data/lib/bunny/channel08.rb +38 -38
  32. data/lib/bunny/channel09.rb +37 -37
  33. data/lib/bunny/client08.rb +184 -206
  34. data/lib/bunny/client09.rb +277 -363
  35. data/lib/bunny/consumer.rb +35 -0
  36. data/lib/bunny/exchange08.rb +37 -41
  37. data/lib/bunny/exchange09.rb +106 -124
  38. data/lib/bunny/queue08.rb +216 -202
  39. data/lib/bunny/queue09.rb +256 -326
  40. data/lib/bunny/subscription08.rb +30 -29
  41. data/lib/bunny/subscription09.rb +84 -83
  42. data/lib/bunny/version.rb +5 -0
  43. data/lib/qrack/amq-client-url.rb +165 -0
  44. data/lib/qrack/channel.rb +19 -17
  45. data/lib/qrack/client.rb +152 -151
  46. data/lib/qrack/errors.rb +5 -0
  47. data/lib/qrack/protocol/protocol08.rb +132 -130
  48. data/lib/qrack/protocol/protocol09.rb +133 -131
  49. data/lib/qrack/protocol/spec08.rb +2 -0
  50. data/lib/qrack/protocol/spec09.rb +2 -0
  51. data/lib/qrack/qrack08.rb +7 -10
  52. data/lib/qrack/qrack09.rb +7 -10
  53. data/lib/qrack/queue.rb +27 -40
  54. data/lib/qrack/subscription.rb +102 -101
  55. data/lib/qrack/transport/buffer08.rb +266 -264
  56. data/lib/qrack/transport/buffer09.rb +268 -264
  57. data/lib/qrack/transport/frame08.rb +13 -11
  58. data/lib/qrack/transport/frame09.rb +9 -7
  59. data/spec/spec_08/bunny_spec.rb +48 -45
  60. data/spec/spec_08/connection_spec.rb +10 -7
  61. data/spec/spec_08/exchange_spec.rb +145 -143
  62. data/spec/spec_08/queue_spec.rb +161 -161
  63. data/spec/spec_09/bunny_spec.rb +46 -44
  64. data/spec/spec_09/connection_spec.rb +15 -8
  65. data/spec/spec_09/exchange_spec.rb +147 -145
  66. data/spec/spec_09/queue_spec.rb +182 -184
  67. metadata +60 -41
  68. data/README.rdoc +0 -66
@@ -0,0 +1,388 @@
1
+ {
2
+ "name": "AMQP",
3
+ "major-version": 0,
4
+ "minor-version": 9,
5
+ "revision": 1,
6
+ "port": 5672,
7
+ "copyright": [
8
+ "Copyright (C) 2008-2009 LShift Ltd, Cohesive Financial Technologies LLC,\n",
9
+ "and Rabbit Technologies Ltd\n",
10
+ "\n",
11
+ "Permission is hereby granted, free of charge, to any person\n",
12
+ "obtaining a copy of this file (the \"Software\"), to deal in the\n",
13
+ "Software without restriction, including without limitation the \n",
14
+ "rights to use, copy, modify, merge, publish, distribute, \n",
15
+ "sublicense, and/or sell copies of the Software, and to permit \n",
16
+ "persons to whom the Software is furnished to do so, subject to \n",
17
+ "the following conditions:\n",
18
+ "\n",
19
+ "The above copyright notice and this permission notice shall be\n",
20
+ "included in all copies or substantial portions of the Software.\n",
21
+ "\n",
22
+ "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n",
23
+ "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n",
24
+ "OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n",
25
+ "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n",
26
+ "HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n",
27
+ "WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
28
+ "FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n",
29
+ "OTHER DEALINGS IN THE SOFTWARE.\n",
30
+ "\n",
31
+ "Class information entered from amqp_xml0-8.pdf and domain types from amqp-xml-doc0-9.pdf\n",
32
+ "Updated for 0-9-1 by Tony Garnock-Jones\n",
33
+ "\n",
34
+ "b3cb053f15e7b98808c0ccc67f23cb3e amqp_xml0-8.pdf\n",
35
+ "http://www.twiststandards.org/index.php?option=com_docman&task=cat_view&gid=28&&Itemid=90\n",
36
+ "8444db91e2949dbecfb2585e9eef6d64 amqp-xml-doc0-9.pdf\n",
37
+ "https://jira.amqp.org/confluence/download/attachments/720900/amqp-xml-doc0-9.pdf?version=1\n"],
38
+
39
+ "domains": [
40
+ ["bit", "bit"],
41
+ ["channel-id", "longstr"],
42
+ ["class-id", "short"],
43
+ ["consumer-tag", "shortstr"],
44
+ ["delivery-tag", "longlong"],
45
+ ["destination", "shortstr"],
46
+ ["duration", "longlong"],
47
+ ["exchange-name", "shortstr"],
48
+ ["long", "long"],
49
+ ["longlong", "longlong"],
50
+ ["longstr", "longstr"],
51
+ ["method-id", "short"],
52
+ ["no-ack", "bit"],
53
+ ["no-local", "bit"],
54
+ ["octet", "octet"],
55
+ ["offset", "longlong"],
56
+ ["path", "shortstr"],
57
+ ["peer-properties", "table"],
58
+ ["queue-name", "shortstr"],
59
+ ["redelivered", "bit"],
60
+ ["reference", "longstr"],
61
+ ["reject-code", "short"],
62
+ ["reject-text", "shortstr"],
63
+ ["reply-code", "short"],
64
+ ["reply-text", "shortstr"],
65
+ ["security-token", "longstr"],
66
+ ["short", "short"],
67
+ ["shortstr", "shortstr"],
68
+ ["table", "table"],
69
+ ["timestamp", "timestamp"]
70
+ ],
71
+
72
+ "constants": [
73
+ {"name": "FRAME-METHOD", "value": 1},
74
+ {"name": "FRAME-HEADER", "value": 2},
75
+ {"name": "FRAME-BODY", "value": 3},
76
+ {"name": "FRAME-HEARTBEAT", "value": 8},
77
+ {"name": "FRAME-MIN-SIZE", "value": 4096},
78
+ {"name": "FRAME-END", "value": 206},
79
+ {"name": "REPLY-SUCCESS", "value": 200},
80
+ {"name": "CONTENT-TOO-LARGE", "value": 311, "class": "soft-error"},
81
+ {"name": "NO-ROUTE", "value": 312, "class": "soft-error"},
82
+ {"name": "NO-CONSUMERS", "value": 313, "class": "soft-error"},
83
+ {"name": "ACCESS-REFUSED", "value": 403, "class": "soft-error"},
84
+ {"name": "NOT-FOUND", "value": 404, "class": "soft-error"},
85
+ {"name": "RESOURCE-LOCKED", "value": 405, "class": "soft-error"},
86
+ {"name": "PRECONDITION-FAILED", "value": 406, "class": "soft-error"},
87
+ {"name": "CONNECTION-FORCED", "value": 320, "class": "hard-error"},
88
+ {"name": "INVALID-PATH", "value": 402, "class": "hard-error"},
89
+ {"name": "FRAME-ERROR", "value": 501, "class": "hard-error"},
90
+ {"name": "SYNTAX-ERROR", "value": 502, "class": "hard-error"},
91
+ {"name": "COMMAND-INVALID", "value": 503, "class": "hard-error"},
92
+ {"name": "CHANNEL-ERROR", "value": 504, "class": "hard-error"},
93
+ {"name": "UNEXPECTED-FRAME", "value": 505, "class": "hard-error"},
94
+ {"name": "RESOURCE-ERROR", "value": 506, "class": "hard-error"},
95
+ {"name": "NOT-ALLOWED", "value": 530, "class": "hard-error"},
96
+ {"name": "NOT-IMPLEMENTED", "value": 540, "class": "hard-error"},
97
+ {"name": "INTERNAL-ERROR", "value": 541, "class": "hard-error"}
98
+ ],
99
+
100
+ "classes": [
101
+ {
102
+ "id": 10,
103
+ "methods": [{"id": 10,
104
+ "arguments": [{"type": "octet", "name": "version-major", "default-value": 0},
105
+ {"type": "octet", "name": "version-minor", "default-value": 8},
106
+ {"domain": "peer-properties", "name": "server properties"},
107
+ {"type": "longstr", "name": "mechanisms", "default-value": "PLAIN"},
108
+ {"type": "longstr", "name": "locales", "default-value": "en_US"}],
109
+ "name": "start"},
110
+ {"id": 11,
111
+ "arguments": [{"domain": "peer-properties", "name": "client-properties"},
112
+ {"type": "shortstr", "name": "mechanism", "default-value": "PLAIN"},
113
+ {"type": "longstr", "name": "response"},
114
+ {"type": "shortstr", "name": "locale", "default-value": "en_US"}],
115
+ "name": "start-ok"},
116
+ {"id": 20,
117
+ "arguments": [{"type": "longstr", "name": "challenge"}],
118
+ "name": "secure"},
119
+ {"id": 21,
120
+ "arguments": [{"type": "longstr", "name": "response"}],
121
+ "name": "secure-ok"},
122
+ {"id": 30,
123
+ "arguments": [{"type": "short", "name": "channel-max", "default-value": 0},
124
+ {"type": "long", "name": "frame-max", "default-value": 0},
125
+ {"type": "short", "name": "heartbeat", "default-value": 0}],
126
+ "name": "tune"},
127
+ {"id": 31,
128
+ "arguments": [{"type": "short", "name": "channel-max", "default-value": 0},
129
+ {"type": "long", "name": "frame-max", "default-value": 0},
130
+ {"type": "short", "name": "heartbeat", "default-value": 0}],
131
+ "name": "tune-ok"},
132
+ {"id": 40,
133
+ "arguments": [{"type": "shortstr", "name": "virtual-host", "default-value": "/"},
134
+ {"type": "shortstr", "name": "deprecated-capabilities", "default-value": ""},
135
+ {"type": "bit", "name": "deprecated-insist", "default-value": false}],
136
+ "name": "open"},
137
+ {"id": 41,
138
+ "arguments": [{"type": "shortstr", "name": "deprecated-known-hosts", "default-value": ""}],
139
+ "name": "open-ok"},
140
+ {"id": 50,
141
+ "arguments": [{"type": "short", "name": "reply-code"},
142
+ {"type": "shortstr", "name": "reply-text", "default-value": ""},
143
+ {"type": "short", "name": "class-id"},
144
+ {"type": "short", "name": "method-id"}],
145
+ "name": "close"},
146
+ {"id": 51,
147
+ "arguments": [],
148
+ "name": "close-ok"}],
149
+ "name": "connection",
150
+ "properties": []
151
+ },
152
+ {
153
+ "id": 20,
154
+ "methods": [{"id": 10,
155
+ "arguments": [{"type": "shortstr", "name": "deprecated-out-of-band", "default-value": ""}],
156
+ "name": "open"},
157
+ {"id": 11,
158
+ "arguments": [{"type": "longstr", "name": "deprecated-channel-id", "default-value": ""}],
159
+ "name": "open-ok"},
160
+ {"id": 20,
161
+ "arguments": [{"type": "bit", "name": "active"}],
162
+ "name": "flow"},
163
+ {"id": 21,
164
+ "arguments": [{"type": "bit", "name": "active"}],
165
+ "name": "flow-ok"},
166
+ {"id": 40,
167
+ "arguments": [{"type": "short", "name": "reply-code"},
168
+ {"type": "shortstr", "name": "reply-text", "default-value": ""},
169
+ {"type": "short", "name": "class-id"},
170
+ {"type": "short", "name": "method-id"}],
171
+ "name": "close"},
172
+ {"id": 41,
173
+ "arguments": [],
174
+ "name": "close-ok"}],
175
+ "name": "channel"
176
+ },
177
+ {
178
+ "id": 40,
179
+ "methods": [{"id": 10,
180
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
181
+ {"type": "shortstr", "name": "exchange"},
182
+ {"type": "shortstr", "name": "type", "default-value": "direct"},
183
+ {"type": "bit", "name": "passive", "default-value": false},
184
+ {"type": "bit", "name": "durable", "default-value": false},
185
+ {"type": "bit", "name": "deprecated-auto-delete", "default-value": false},
186
+ {"type": "bit", "name": "deprecated-internal", "default-value": false},
187
+ {"type": "bit", "name": "nowait", "default-value": false},
188
+ {"type": "table", "name": "arguments", "default-value": {}}],
189
+ "name": "declare"},
190
+ {"id": 11,
191
+ "arguments": [],
192
+ "name": "declare-ok"},
193
+ {"id": 20,
194
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
195
+ {"type": "shortstr", "name": "exchange"},
196
+ {"type": "bit", "name": "if-unused", "default-value": false},
197
+ {"type": "bit", "name": "nowait", "default-value": false}],
198
+ "name": "delete"},
199
+ {"id": 21,
200
+ "arguments": [],
201
+ "name": "delete-ok"}],
202
+ "name": "exchange"
203
+ },
204
+ {
205
+ "id": 50,
206
+ "methods": [{"id": 10,
207
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
208
+ {"type": "shortstr", "name": "queue", "default-value": ""},
209
+ {"type": "bit", "name": "passive", "default-value": false},
210
+ {"type": "bit", "name": "durable", "default-value": false},
211
+ {"type": "bit", "name": "exclusive", "default-value": false},
212
+ {"type": "bit", "name": "auto-delete", "default-value": false},
213
+ {"type": "bit", "name": "nowait", "default-value": false},
214
+ {"type": "table", "name": "arguments", "default-value": {}}],
215
+ "name": "declare"},
216
+ {"id": 11,
217
+ "arguments": [{"type": "shortstr", "name": "queue"},
218
+ {"type": "long", "name": "message-count"},
219
+ {"type": "long", "name": "consumer-count"}],
220
+ "name": "declare-ok"},
221
+ {"id": 20,
222
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
223
+ {"type": "shortstr", "name": "queue"},
224
+ {"type": "shortstr", "name": "exchange"},
225
+ {"type": "shortstr", "name": "routing-key"},
226
+ {"type": "bit", "name": "nowait", "default-value": false},
227
+ {"type": "table", "name": "arguments", "default-value": {}}],
228
+ "name": "bind"},
229
+ {"id": 21,
230
+ "arguments": [],
231
+ "name": "bind-ok"},
232
+ {"id": 30,
233
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
234
+ {"type": "shortstr", "name": "queue"},
235
+ {"type": "bit", "name": "nowait", "default-value": false}],
236
+ "name": "purge"},
237
+ {"id": 31,
238
+ "arguments": [{"type": "long", "name": "message-count"}],
239
+ "name": "purge-ok"},
240
+ {"id": 40,
241
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
242
+ {"type": "shortstr", "name": "queue"},
243
+ {"type": "bit", "name": "if-unused", "default-value": false},
244
+ {"type": "bit", "name": "if-empty", "default-value": false},
245
+ {"type": "bit", "name": "nowait", "default-value": false}],
246
+ "name": "delete"},
247
+ {"id": 41,
248
+ "arguments": [{"type": "long", "name": "message-count"}],
249
+ "name": "delete-ok"},
250
+ {"id": 50,
251
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
252
+ {"type": "shortstr", "name": "queue"},
253
+ {"type": "shortstr", "name": "exchange"},
254
+ {"type": "shortstr", "name": "routing-key"},
255
+ {"type": "table", "name": "arguments"}],
256
+ "name": "unbind"},
257
+ {"id": 51,
258
+ "arguments": [],
259
+ "name": "unbind-ok"}
260
+ ],
261
+ "name": "queue"
262
+ },
263
+ {
264
+ "id": 60,
265
+ "methods": [{"id": 10,
266
+ "arguments": [{"type": "long", "name": "prefetch-size", "default-value": 0},
267
+ {"type": "short", "name": "prefetch-count", "default-value": 0},
268
+ {"type": "bit", "name": "global", "default-value": false}],
269
+ "name": "qos"},
270
+ {"id": 11,
271
+ "arguments": [],
272
+ "name": "qos-ok"},
273
+ {"id": 20,
274
+ "arguments": [{"domain": "short", "name": "deprecated-ticket", "default-value": 1},
275
+ {"domain": "queue-name", "name": "queue"},
276
+ {"type": "shortstr", "name": "consumer-tag"},
277
+ {"type": "bit", "name": "no-local", "default-value": false},
278
+ {"type": "bit", "name": "no-ack", "default-value": false},
279
+ {"type": "bit", "name": "exclusive", "default-value": false},
280
+ {"type": "bit", "name": "nowait", "default-value": false},
281
+ {"type": "table", "name": "filter", "default-value": {}}],
282
+ "name": "consume"},
283
+ {"id": 21,
284
+ "arguments": [{"type": "shortstr", "name": "consumer-tag"}],
285
+ "name": "consume-ok"},
286
+ {"id": 30,
287
+ "arguments": [{"type": "shortstr", "name": "consumer-tag"},
288
+ {"type": "bit", "name": "nowait", "default-value": false}],
289
+ "name": "cancel"},
290
+ {"id": 31,
291
+ "arguments": [{"type": "shortstr", "name": "consumer-tag"}],
292
+ "name": "cancel-ok"},
293
+ {"content": true,
294
+ "id": 40,
295
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
296
+ {"type": "shortstr", "name": "exchange", "default-value": ""},
297
+ {"type": "shortstr", "name": "routing-key"},
298
+ {"type": "bit", "name": "mandatory", "default-value": false},
299
+ {"type": "bit", "name": "immediate", "default-value": false}],
300
+ "name": "publish"},
301
+ {"content": true,
302
+ "id": 50,
303
+ "arguments": [{"type": "short", "name": "reply-code"},
304
+ {"type": "shortstr", "name": "reply-text", "default-value": ""},
305
+ {"type": "shortstr", "name": "exchange"},
306
+ {"type": "shortstr", "name": "routing-key"}],
307
+ "name": "return"},
308
+ {"content": true,
309
+ "id": 60,
310
+ "arguments": [{"type": "shortstr", "name": "consumer-tag"},
311
+ {"type": "longlong", "name": "delivery-tag"},
312
+ {"type": "bit", "name": "redelivered", "default-value": false},
313
+ {"type": "shortstr", "name": "exchange"},
314
+ {"type": "shortstr", "name": "routing-key"}],
315
+ "name": "deliver"},
316
+ {"id": 70,
317
+ "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1},
318
+ {"type": "shortstr", "name": "queue"},
319
+ {"type": "bit", "name": "no-ack", "default-value": false}],
320
+ "name": "get"},
321
+ {"content": true,
322
+ "id": 71,
323
+ "arguments": [{"type": "longlong", "name": "delivery-tag"},
324
+ {"type": "bit", "name": "redelivered", "default-value": false},
325
+ {"type": "shortstr", "name": "exchange"},
326
+ {"type": "shortstr", "name": "routing-key"},
327
+ {"type": "long", "name": "message-count"}],
328
+ "name": "get-ok"},
329
+ {"id": 72,
330
+ "arguments": [{"type": "shortstr", "name": "deprecated-cluster-id", "default-value": ""}],
331
+ "name": "get-empty"},
332
+ {"id": 80,
333
+ "arguments": [{"type": "longlong", "name": "delivery-tag", "default-value": 0},
334
+ {"type": "bit", "name": "multiple", "default-value": true}],
335
+ "name": "ack"},
336
+ {"id": 90,
337
+ "arguments": [{"type": "longlong", "name": "delivery-tag"},
338
+ {"type": "bit", "name": "requeue", "default-value": true}],
339
+ "name": "reject"},
340
+ {"id": 100,
341
+ "arguments": [{"type": "bit", "name": "requeue", "default-value": false}],
342
+ "name": "recover-async"},
343
+ {"id": 110,
344
+ "arguments": [{"type": "bit", "name": "requeue", "default-value": false}],
345
+ "name": "recover"},
346
+ {"id": 111,
347
+ "arguments": [],
348
+ "name": "recover-ok"}],
349
+ "name": "basic",
350
+ "properties": [{"type": "shortstr", "name": "content-type"},
351
+ {"type": "shortstr", "name": "content-encoding"},
352
+ {"type": "table", "name": "headers"},
353
+ {"type": "octet", "name": "delivery-mode"},
354
+ {"type": "octet", "name": "priority"},
355
+ {"type": "shortstr", "name": "correlation-id"},
356
+ {"type": "shortstr", "name": "reply-to"},
357
+ {"type": "shortstr", "name": "expiration"},
358
+ {"type": "shortstr", "name": "message-id"},
359
+ {"type": "timestamp", "name": "timestamp"},
360
+ {"type": "shortstr", "name": "type"},
361
+ {"type": "shortstr", "name": "user-id"},
362
+ {"type": "shortstr", "name": "app-id"},
363
+ {"type": "shortstr", "name": "deprecated-cluster-id"}]
364
+ },
365
+ {
366
+ "id": 90,
367
+ "methods": [{"id": 10,
368
+ "arguments": [],
369
+ "name": "select"},
370
+ {"id": 11,
371
+ "arguments": [],
372
+ "name": "select-ok"},
373
+ {"id": 20,
374
+ "arguments": [],
375
+ "name": "commit"},
376
+ {"id": 21,
377
+ "arguments": [],
378
+ "name": "commit-ok"},
379
+ {"id": 30,
380
+ "arguments": [],
381
+ "name": "rollback"},
382
+ {"id": 31,
383
+ "arguments": [],
384
+ "name": "rollback-ok"}],
385
+ "name": "tx"
386
+ }
387
+ ]
388
+ }
@@ -0,0 +1,4 @@
1
+ ---
2
+ :spec_out: '../lib/qrack/protocol/spec08.rb'
3
+ :frame_out: '../lib/qrack/transport/frame08.rb'
4
+ :spec_in: 'amqp-0.8.json'
@@ -0,0 +1,463 @@
1
+ # encoding: utf-8
2
+
3
+ require 'json'
4
+ require 'erb'
5
+ require 'pathname'
6
+ require 'yaml'
7
+
8
+ def spec_v8_0_0?(spec)
9
+ spec['major'] == '8' && spec['minor'] == '0' && spec['revision'] == '0'
10
+ end
11
+
12
+ def spec_details(spec)
13
+ meta = {}
14
+
15
+ meta['major'] = spec['major-version']
16
+ meta['minor'] = spec['minor-version']
17
+ meta['revision'] = spec['revision'] || '0'
18
+ meta['port'] = spec['port']
19
+ meta['comment'] = "AMQ Protocol version #{meta['major']}.#{meta['minor']}.#{meta['revision']}"
20
+
21
+ meta
22
+ end
23
+
24
+ def process_constants(spec)
25
+ # AMQP constants
26
+
27
+ frame_constants = {}
28
+ other_constants = {}
29
+
30
+ spec['constants'].each do |constant|
31
+ if constant['name'].match(/^frame/i)
32
+ frame_constants[constant['value'].to_i] =
33
+ constant['name'].sub(/^frame./i,'').split(/\s|-/).map{|w| w.downcase.capitalize}.join
34
+ else
35
+ other_constants[constant['value']] = constant['name']
36
+ end
37
+ end
38
+
39
+ [frame_constants.sort, other_constants.sort]
40
+ end
41
+
42
+ def domain_types(spec, major, minor, revision)
43
+ # AMQP domain types
44
+
45
+ # add types that may be missing in the spec version
46
+ dt_arr = add_types(spec)
47
+ spec["domains"].each do |domain|
48
+ # JSON spec gives domain types as two element arrays like ["channel-id", "longstr"]
49
+ dt_arr << domain.last
50
+ end
51
+
52
+ # Return sorted array
53
+ dt_arr.uniq.sort
54
+ end
55
+
56
+ def classes(spec, major, minor, revision)
57
+ # AMQP classes
58
+ spec['classes'].map do |amqp_class|
59
+ cls_hash = {}
60
+ cls_hash[:name] = amqp_class['name']
61
+ cls_hash[:index] = amqp_class['id']
62
+ # Get fields for class
63
+ cls_hash[:fields] = fields(amqp_class) # are these amqp_class["properties"] ?
64
+ # Get methods for class
65
+ meth_arr = class_methods(amqp_class)
66
+ # Add missing methods
67
+ add_arr =[]
68
+ add_arr = add_methods(spec) if cls_hash[:name] == 'queue'
69
+ method_arr = meth_arr + add_arr
70
+ # Add array to class hash
71
+ cls_hash[:methods] = method_arr
72
+ cls_hash
73
+ end
74
+ end
75
+
76
+ # Get methods for class
77
+ def class_methods(amqp_class)
78
+ amqp_class['methods'].map do |method|
79
+ meth_hash = {}
80
+ meth_hash[:name] = method['name']
81
+ meth_hash[:index] = method['id']
82
+ # Get fields for method
83
+ meth_hash[:fields] = fields(method)
84
+ meth_hash
85
+ end
86
+ end
87
+
88
+ # Get the fields for a class or method
89
+ def fields(element)
90
+ # The JSON spec puts these in "properties" for a class and "arguments" for a
91
+ # method
92
+ (element['arguments'] || element['properties'] || []).map do |field|
93
+ field_hash = {}
94
+ field_hash[:name] = field['name'].tr(' ', '-')
95
+ field_hash[:domain] = field['type'] || field['domain']
96
+
97
+ # Convert domain type if necessary
98
+ conv_arr = convert_type(field_hash[:domain])
99
+ field_hash[:domain] = conv_arr.last unless conv_arr.empty?
100
+
101
+ field_hash
102
+ end
103
+ end
104
+
105
+ def add_types(spec)
106
+ spec_v8_0_0?(spec) ? ['long', 'longstr', 'octet', 'timestamp'] : []
107
+ end
108
+
109
+ def add_methods(spec)
110
+ meth_arr = []
111
+
112
+ if spec_v8_0_0?(spec)
113
+ # Add Queue Unbind method
114
+ meth_hash = {:name => 'unbind',
115
+ :index => '50',
116
+ :fields => [{:name => 'ticket', :domain => 'short'},
117
+ {:name => 'queue', :domain => 'shortstr'},
118
+ {:name => 'exchange', :domain => 'shortstr'},
119
+ {:name => 'routing_key', :domain => 'shortstr'},
120
+ {:name => 'arguments', :domain => 'table'}
121
+ ]
122
+ }
123
+
124
+ meth_arr << meth_hash
125
+
126
+ # Add Queue Unbind-ok method
127
+ meth_hash = {:name => 'unbind-ok',
128
+ :index => '51',
129
+ :fields => []
130
+ }
131
+
132
+ meth_arr << meth_hash
133
+ end
134
+
135
+ # Return methods
136
+ meth_arr
137
+
138
+ end
139
+
140
+ def convert_type(name)
141
+ type_arr = @type_conversion.select {|k,v| k == name}.flatten
142
+ end
143
+
144
+ # Start of Main program
145
+
146
+ # Read in config options
147
+ CONFIG = YAML::load(File.read('config.yml'))
148
+
149
+ # Get path to the spec file and the spec file name on its own
150
+ specpath = CONFIG[:spec_in]
151
+ path = Pathname.new(specpath)
152
+ specfile = path.basename.to_s
153
+
154
+ # Read in the spec file
155
+ spec = JSON.parse(IO.read(specpath))
156
+
157
+ # Declare type conversion hash
158
+ @type_conversion = {'path' => 'shortstr',
159
+ 'known hosts' => 'shortstr',
160
+ 'known-hosts' => 'shortstr',
161
+ 'reply code' => 'short',
162
+ 'reply-code' => 'short',
163
+ 'reply text' => 'shortstr',
164
+ 'reply-text' => 'shortstr',
165
+ 'class id' => 'short',
166
+ 'class-id' => 'short',
167
+ 'method id' => 'short',
168
+ 'method-id' => 'short',
169
+ 'channel-id' => 'longstr',
170
+ 'access ticket' => 'short',
171
+ 'access-ticket' => 'short',
172
+ 'exchange name' => 'shortstr',
173
+ 'exchange-name' => 'shortstr',
174
+ 'queue name' => 'shortstr',
175
+ 'queue-name' => 'shortstr',
176
+ 'consumer tag' => 'shortstr',
177
+ 'consumer-tag' => 'shortstr',
178
+ 'delivery tag' => 'longlong',
179
+ 'delivery-tag' => 'longlong',
180
+ 'redelivered' => 'bit',
181
+ 'no ack' => 'bit',
182
+ 'no-ack' => 'bit',
183
+ 'no local' => 'bit',
184
+ 'no-local' => 'bit',
185
+ 'peer properties' => 'table',
186
+ 'peer-properties' => 'table',
187
+ 'destination' => 'shortstr',
188
+ 'duration' => 'longlong',
189
+ 'security-token' => 'longstr',
190
+ 'reject-code' => 'short',
191
+ 'reject-text' => 'shortstr',
192
+ 'offset' => 'longlong',
193
+ 'no-wait' => 'bit',
194
+ 'message-count' => 'long'
195
+ }
196
+
197
+ # Spec details
198
+ spec_info = spec_details(spec)
199
+
200
+ # Constants
201
+ constants = process_constants(spec)
202
+
203
+ # Frame constants
204
+ frame_constants = constants[0].select {|k,v| k <= 8}
205
+ frame_footer = constants[0].select {|k,v| v == 'End'}[0][0]
206
+
207
+ # Other constants
208
+ other_constants = constants[1]
209
+
210
+ # Domain types
211
+ data_types = domain_types(spec, spec_info['major'], spec_info['minor'], spec_info['revision'])
212
+
213
+ # Classes
214
+ class_defs = classes(spec, spec_info['major'], spec_info['minor'], spec_info['revision'])
215
+
216
+ # Generate spec.rb
217
+ spec_rb = File.open(CONFIG[:spec_out], 'w')
218
+ spec_rb.puts(
219
+ ERB.new(%q[
220
+ #:stopdoc:
221
+ # this file was autogenerated on <%= Time.now.to_s %>
222
+ # using <%= specfile.ljust(16) %> (mtime: <%= File.mtime(specpath) %>)
223
+ #
224
+ # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb')
225
+
226
+ module Qrack
227
+ module Protocol
228
+ HEADER = "AMQP".freeze
229
+ VERSION_MAJOR = <%= spec_info['major'] %>
230
+ VERSION_MINOR = <%= spec_info['minor'] %>
231
+ REVISION = <%= spec_info['revision'] %>
232
+ PORT = <%= spec_info['port'] %>
233
+
234
+ RESPONSES = {
235
+ <%- other_constants.each do |value, name| -%>
236
+ <%= value %> => :<%= name.gsub(/\s|-/, '_').upcase -%>,
237
+ <%- end -%>
238
+ }
239
+
240
+ FIELDS = [
241
+ <%- data_types.each do |d| -%>
242
+ :<%= d -%>,
243
+ <%- end -%>
244
+ ]
245
+
246
+ class Class
247
+ class << self
248
+ FIELDS.each do |f|
249
+ class_eval %[
250
+ def #{f} name
251
+ properties << [ :#{f}, name ] unless properties.include?([:#{f}, name])
252
+ attr_accessor name
253
+ end
254
+ ]
255
+ end
256
+
257
+ def properties() @properties ||= [] end
258
+
259
+ def id() self::ID end
260
+ def name() self::NAME end
261
+ end
262
+
263
+ class Method
264
+ class << self
265
+ FIELDS.each do |f|
266
+ class_eval %[
267
+ def #{f} name
268
+ arguments << [ :#{f}, name ] unless arguments.include?([:#{f}, name])
269
+ attr_accessor name
270
+ end
271
+ ]
272
+ end
273
+
274
+ def arguments() @arguments ||= [] end
275
+
276
+ def parent() Protocol.const_get(self.to_s[/Protocol::(.+?)::/,1]) end
277
+ def id() self::ID end
278
+ def name() self::NAME end
279
+ end
280
+
281
+ def == b
282
+ self.class.arguments.inject(true) do |eql, (type, name)|
283
+ eql and __send__("#{name}") == b.__send__("#{name}")
284
+ end
285
+ end
286
+ end
287
+
288
+ def self.methods() @methods ||= {} end
289
+
290
+ def self.Method(id, name)
291
+ @_base_methods ||= {}
292
+ @_base_methods[id] ||= ::Class.new(Method) do
293
+ class_eval %[
294
+ def self.inherited klass
295
+ klass.const_set(:ID, #{id})
296
+ klass.const_set(:NAME, :#{name.to_s})
297
+ klass.parent.methods[#{id}] = klass
298
+ klass.parent.methods[klass::NAME] = klass
299
+ end
300
+ ]
301
+ end
302
+ end
303
+ end
304
+
305
+ def self.classes() @classes ||= {} end
306
+
307
+ def self.Class(id, name)
308
+ @_base_classes ||= {}
309
+ @_base_classes[id] ||= ::Class.new(Class) do
310
+ class_eval %[
311
+ def self.inherited klass
312
+ klass.const_set(:ID, #{id})
313
+ klass.const_set(:NAME, :#{name.to_s})
314
+ Protocol.classes[#{id}] = klass
315
+ Protocol.classes[klass::NAME] = klass
316
+ end
317
+ ]
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ module Qrack
324
+ module Protocol
325
+ <%- class_defs.each do |h| -%>
326
+ class <%= h[:name].capitalize.ljust(12) %> < Class( <%= h[:index].to_s.rjust(3) %>, :<%= h[:name].ljust(12) %> ); end
327
+ <%- end -%>
328
+
329
+ <%- class_defs.each do |c| -%>
330
+ class <%= c[:name].capitalize %>
331
+ <%- c[:fields].each do |p| -%>
332
+ <%= p[:domain].ljust(10) %> :<%= p[:name].tr('-','_') %>
333
+ <%- end if c[:fields] -%>
334
+
335
+ <%- c[:methods].each do |m| -%>
336
+ class <%= m[:name].capitalize.gsub(/-(.)/){ "#{$1.upcase}"}.ljust(12) %> < Method( <%= m[:index].to_s.rjust(3) %>, :<%= m[:name].tr('- ','_').ljust(14) %> ); end
337
+ <%- end -%>
338
+
339
+ <%- c[:methods].each do |m| -%>
340
+
341
+ class <%= m[:name].capitalize.gsub(/-(.)/){ "#{$1.upcase}"} %>
342
+ <%- m[:fields].each do |a| -%>
343
+ <%- if a[:domain] -%>
344
+ <%= a[:domain].ljust(16) %> :<%= a[:name].tr('- ','_') %>
345
+ <%- end -%>
346
+ <%- end -%>
347
+ end
348
+ <%- end -%>
349
+
350
+ end
351
+
352
+ <%- end -%>
353
+ end
354
+
355
+ end
356
+ ].gsub!(/^ /,''), nil, '>-%').result(binding)
357
+ )
358
+
359
+ # Close spec.rb file
360
+ spec_rb.close
361
+
362
+ # Generate frame.rb file
363
+
364
+ frame_rb = File.open(CONFIG[:frame_out], 'w')
365
+ frame_rb.puts(
366
+ ERB.new(%q[
367
+ #:stopdoc:
368
+ # this file was autogenerated on <%= Time.now.to_s %>
369
+ #
370
+ # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb')
371
+
372
+ module Qrack
373
+ module Transport
374
+ class Frame
375
+
376
+ FOOTER = <%= frame_footer %>
377
+ ID = 0
378
+
379
+ @types = {
380
+ <%- frame_constants.each do |value, name| -%>
381
+ <%= value %> => '<%= name %>',
382
+ <%- end -%>
383
+ }
384
+
385
+ attr_accessor :channel, :payload
386
+
387
+ def initialize payload = nil, channel = 0
388
+ @channel, @payload = channel, payload
389
+ end
390
+
391
+ def id
392
+ self.class::ID
393
+ end
394
+
395
+ def to_binary
396
+ buf = Transport::Buffer.new
397
+ buf.write :octet, id
398
+ buf.write :short, channel
399
+ buf.write :longstr, payload
400
+ buf.write :octet, FOOTER
401
+ buf.rewind
402
+ buf
403
+ end
404
+
405
+ def to_s
406
+ to_binary.to_s
407
+ end
408
+
409
+ def == frame
410
+ [ :id, :channel, :payload ].inject(true) do |eql, field|
411
+ eql and __send__(field) == frame.__send__(field)
412
+ end
413
+ end
414
+
415
+ def self.parse buf
416
+ buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer
417
+ buf.extract do
418
+ id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet)
419
+ Qrack::Transport.const_get(@types[id]).new(payload, channel) if footer == FOOTER
420
+ end
421
+ end
422
+
423
+ end
424
+
425
+ class Method < Frame
426
+
427
+ ID = 1
428
+
429
+ def initialize payload = nil, channel = 0
430
+ super
431
+ unless @payload.is_a? Protocol::Class::Method or @payload.nil?
432
+ @payload = Protocol.parse(@payload)
433
+ end
434
+ end
435
+ end
436
+
437
+ class Header < Frame
438
+
439
+ ID = 2
440
+
441
+ def initialize payload = nil, channel = 0
442
+ super
443
+ unless @payload.is_a? Protocol::Header or @payload.nil?
444
+ @payload = Protocol::Header.new(@payload)
445
+ end
446
+ end
447
+ end
448
+
449
+ <%- frame_constants.each do |value, name| -%>
450
+ <%- if value > 2 -%>
451
+ class <%= name %> < Frame
452
+ ID = <%= value %>
453
+ end
454
+
455
+ <%- end -%>
456
+ <%- end -%>
457
+ end
458
+ end
459
+ ].gsub!(/^ /,''), nil, '>-%').result(binding)
460
+ )
461
+
462
+ # Close frame.rb file
463
+ frame_rb.close