stark 0.5.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.
data/lib/stark/ruby.rb ADDED
@@ -0,0 +1,468 @@
1
+ require 'stark/ast'
2
+
3
+ module Stark
4
+ class Ruby
5
+ def initialize(stream=STDOUT)
6
+
7
+ @namespace = nil
8
+ @indent = 0
9
+ @structs = {}
10
+ @enums = {}
11
+
12
+ @stream = stream
13
+
14
+
15
+ o "require 'stark/client'"
16
+ o "require 'stark/struct'"
17
+ o "require 'stark/field'"
18
+ o "require 'stark/converters'"
19
+ o "require 'stark/processor'"
20
+ end
21
+
22
+ def process_namespace(ns)
23
+ @namespace = ns.namespace if ns.lang == "rb"
24
+ end
25
+
26
+ def process_include(inc)
27
+ end
28
+
29
+ def process_enum(enum)
30
+ e = "Enum_#{enum.name}"
31
+ o "#{e} = Hash.new { |h,k| p [:bad, k]; h[k] = -1 }"
32
+
33
+ idx = 0
34
+ enum.values.each do |f|
35
+ o "#{e}[#{idx}] = :'#{f}'"
36
+ o "#{e}[:'#{f}'] = #{idx}"
37
+ idx += 1
38
+ end
39
+
40
+ @enums[enum.name] = enum
41
+ end
42
+
43
+ def process_struct(str)
44
+ @structs[str.name] = str
45
+
46
+ o "class #{str.name} < Stark::Struct"
47
+ indent
48
+ o "Fields = {"
49
+ indent
50
+
51
+ str.fields.each do |f|
52
+ c = "Stark::Converters::#{f.type.upcase}"
53
+
54
+ o "#{f.index} => Stark::Field.new(#{f.index}, '#{f.name}', #{c}),"
55
+ end
56
+
57
+ o ":count => #{str.fields.size}"
58
+
59
+ outdent
60
+ o "}"
61
+ outdent
62
+ o "end"
63
+
64
+ end
65
+
66
+ def o(str)
67
+ @stream.print(" " * @indent)
68
+ @stream.puts str
69
+ end
70
+
71
+ def indent
72
+ @indent += 2
73
+ end
74
+
75
+ def outdent
76
+ @indent -= 2
77
+ end
78
+
79
+ CoreTypes = {
80
+ 'bool' => "::Thrift::Types::BOOL",
81
+ 'byte' => "::Thrift::Types::BYTE",
82
+ 'double' => "::Thrift::Types::DOUBLE",
83
+ 'i16' => "::Thrift::Types::I16",
84
+ 'i32' => "::Thrift::Types::I32",
85
+ 'i64' => "::Thrift::Types::I64",
86
+ 'string' => '::Thrift::Types::STRING',
87
+ 'struct' => '::Thrift::Types::STRUCT',
88
+ 'map' => '::Thrift::Types::MAP',
89
+ 'set' => '::Thrift::Types::SET',
90
+ 'list' => '::Thrift::Types::LIST'
91
+ }
92
+
93
+ ReadFunc = {
94
+ 'bool' => 'read_bool',
95
+ 'byte' => 'read_byte',
96
+ 'double' => 'read_double',
97
+ 'i16' => "read_i16",
98
+ 'i32' => "read_i32",
99
+ 'i64' => "read_i64",
100
+ 'string' => 'read_string',
101
+ }
102
+
103
+ WriteFunc = {
104
+ 'bool' => 'write_bool',
105
+ 'byte' => 'write_byte',
106
+ 'double' => 'write_double',
107
+ 'i16' => "write_i16",
108
+ 'i32' => "write_i32",
109
+ 'i64' => "write_i64",
110
+ 'string' => 'write_string',
111
+ }
112
+
113
+ def type(t)
114
+ CoreTypes[t] || raise("unknown type - #{t}")
115
+ end
116
+
117
+ def wire_type(t)
118
+ return "::Thrift::Types::STRUCT" if @structs[t]
119
+ return "::Thrift::Types::I32" if @enums[t]
120
+
121
+ case t
122
+ when Stark::Parser::AST::Map
123
+ "::Thrift::Types::MAP"
124
+ when Stark::Parser::AST::List
125
+ "::Thrift::Types::LIST"
126
+ when Stark::Parser::AST::Set
127
+ "::Thrift::Types::SET"
128
+ else
129
+ type t
130
+ end
131
+ end
132
+
133
+ def object_type(t)
134
+ return t if @structs[t]
135
+ type t
136
+ end
137
+
138
+ def read_func(t)
139
+ ReadFunc[t] || raise("unknown type - #{t}")
140
+ end
141
+
142
+ def write_func(t)
143
+ WriteFunc[t] || raise("unknown type - #{t}")
144
+ end
145
+
146
+ def output_struct(desc, obj)
147
+ o "op.write_struct_begin '#{desc.name}'"
148
+
149
+ desc.fields.each do |f|
150
+ if desc = @structs[f.type]
151
+ o "op.write_field_begin '#{f.name}', ::Thrift::Types::STRUCT, #{f.index}"
152
+ output_struct desc, f.name
153
+ o "op.write_field_end"
154
+ else
155
+ o "op.write_field_begin '#{f.name}', #{type(f.type)}, #{f.index}"
156
+ o "op.#{write_func(f.type)} #{obj}.#{f.name}"
157
+ o "op.write_field_end"
158
+ end
159
+ end
160
+
161
+ o "op.write_field_stop"
162
+ o "op.write_struct_end"
163
+ end
164
+
165
+ def write_processor(serv)
166
+ o "class Processor < Stark::Processor"
167
+ indent
168
+
169
+ serv.functions.each do |func|
170
+ o "def process_#{func.name}(seqid, ip, op)"
171
+ indent
172
+
173
+ o "ip.read_struct_begin"
174
+ args = Array(func.arguments)
175
+ o "args = Array.new(#{args.size})"
176
+
177
+ args.each do |arg|
178
+ if desc = @structs[arg.type]
179
+ o "_, rtype, rid = ip.read_field_begin"
180
+ o "if rtype != #{wire_type(arg.type)}"
181
+ o " handle_unexpected rtype"
182
+ o "else"
183
+ o " args[#{arg.index - 1}] = read_struct ip, rtype, rid, #{desc.name}"
184
+ o "end"
185
+ o "ip.read_field_end"
186
+ elsif desc = @enums[arg.type]
187
+ o "_, rtype, _ = ip.read_field_begin"
188
+ o "if rtype != #{wire_type(arg.type)}"
189
+ o " handle_unexpected rtype"
190
+ o "else"
191
+ o " args[#{arg.index - 1}] = Enum_#{desc.name}[ip.read_i32]"
192
+ o "end"
193
+ o "ip.read_field_end"
194
+
195
+ elsif arg.type.kind_of? Stark::Parser::AST::Map
196
+ ft = arg.type
197
+
198
+ o "_, rtype, _ = ip.read_field_begin"
199
+ o "if rtype != #{wire_type(arg.type)}"
200
+ o " handle_unexpected rtype"
201
+ o "else"
202
+ o " kt, vt, size = ip.read_map_begin"
203
+ o " if kt == #{wire_type(ft.key)} && vt == #{wire_type(ft.value)}"
204
+ o " result = {}"
205
+ o " size.times do"
206
+ o " result[ip.#{read_func(ft.key)}] = ip.#{read_func(ft.value)}"
207
+ o " end"
208
+ o " args[#{arg.index - 1}] = result"
209
+ o " else"
210
+ o " handle_bad_map size"
211
+ o " end"
212
+ o " ip.read_map_end"
213
+ o "end"
214
+ o "ip.read_field_end"
215
+ elsif arg.type.kind_of? Stark::Parser::AST::List
216
+ ft = arg.type
217
+ o "_, rtype, _ = ip.read_field_begin"
218
+ o "if rtype == ::Thrift::Types::LIST"
219
+ o " vt, size = ip.read_list_begin"
220
+ o " if vt == #{wire_type(ft.value)}"
221
+ o " args[#{arg.index - 1}] = Array.new(size) { |n| ip.#{read_func(ft.value)} }"
222
+ o " else"
223
+ o " handle_bad_list size"
224
+ o " end"
225
+ o " ip.read_list_end"
226
+ o "else"
227
+ o " handle_unexpected rtype"
228
+ o "end"
229
+ o "ip.read_field_end"
230
+ else
231
+ o "_, rtype, _ = ip.read_field_begin"
232
+ o "if rtype == #{type(arg.type)}"
233
+ o " args[#{arg.index - 1}]= ip.#{read_func(arg.type)}"
234
+ o "else"
235
+ o " handle_unexpected rtype"
236
+ o "end"
237
+ o "ip.read_field_end"
238
+ end
239
+ end
240
+
241
+ o "_, rtype, _ = ip.read_field_begin"
242
+ o "fail unless rtype == ::Thrift::Types::STOP"
243
+ o "ip.read_struct_end"
244
+ o "ip.read_message_end"
245
+
246
+ o "result = @handler.#{func.name}(*args)"
247
+
248
+ o "op.write_message_begin '#{func.name}', ::Thrift::MessageTypes::REPLY, seqid"
249
+ o "op.write_struct_begin '#{func.name}_result'"
250
+
251
+ ft = func.return_type
252
+
253
+ if desc = @structs[ft]
254
+ o "op.write_field_begin 'result', ::Thrift::Types::STRUCT, 0"
255
+ output_struct desc, "result"
256
+ o "op.write_field_end"
257
+ elsif desc = @enums[ft]
258
+ o "op.write_field_begin 'result', ::Thrift::Types::I32, 0"
259
+ o "op.write_i32 Enum_#{desc.name}[result.to_sym]"
260
+
261
+ o "op.write_field_end"
262
+ elsif ft.kind_of? Stark::Parser::AST::Map
263
+ o "result = hash_cast result"
264
+ o "op.write_field_begin 'result', ::Thrift::Types::MAP, 0"
265
+ o "op.write_map_begin(#{wire_type(ft.key)}, #{wire_type(ft.value)}, result.size)"
266
+
267
+ o "result.each do |k,v|"
268
+ indent
269
+ o "op.#{write_func(ft.key)} k"
270
+ o "op.#{write_func(ft.value)} v"
271
+ outdent
272
+ o "end"
273
+
274
+ o "op.write_map_end"
275
+ o "op.write_field_end"
276
+ elsif ft.kind_of? Stark::Parser::AST::List
277
+ o "result = Array(result)"
278
+ o "op.write_field_begin 'result', ::Thrift::Types::LIST, 0"
279
+ o "op.write_list_begin(#{wire_type(ft.value)}, result.size)"
280
+ o "result.each { |v| op.#{write_func(ft.value)}(v) }"
281
+ o "op.write_list_end"
282
+
283
+ o "op.write_field_end"
284
+ elsif ft != "void"
285
+ o "op.write_field_begin 'result', #{type(ft)}, 0"
286
+ o "op.#{write_func(ft)} result"
287
+ o "op.write_field_end"
288
+ end
289
+
290
+ o "op.write_field_stop"
291
+ o "op.write_struct_end"
292
+ o "op.write_message_end"
293
+ o "op.trans.flush"
294
+ o "return result"
295
+
296
+ outdent
297
+ o "end"
298
+ end
299
+
300
+ outdent
301
+ o "end"
302
+ end
303
+
304
+ def process_service(serv)
305
+ o "module #{serv.name}"
306
+ indent
307
+ o "class Client < Stark::Client"
308
+ indent
309
+
310
+ o "Functions = {}"
311
+ serv.functions.each do |func|
312
+ o "Functions[\"#{func.name}\"] = {"
313
+
314
+ o " :args => {"
315
+
316
+ Array(func.arguments).each do |a|
317
+ o " #{a.index} => #{wire_type(a.type)}"
318
+ end
319
+
320
+ o " }"
321
+ o " }"
322
+ end
323
+
324
+ serv.functions.each do |func|
325
+ names = Array(func.arguments).map { |f| f.name }.join(", ")
326
+
327
+ o "def #{func.name}(#{names})"
328
+ indent
329
+ o "op = @oprot"
330
+ o "op.write_message_begin '#{func.name}', ::Thrift::MessageTypes::CALL, 0"
331
+ o "op.write_struct_begin \"#{func.name}_args\""
332
+
333
+ Array(func.arguments).each do |arg|
334
+ if desc = @structs[arg.type]
335
+ o "op.write_field_begin '#{arg.name}', ::Thrift::Types::STRUCT, #{arg.index}"
336
+ output_struct desc, arg.name
337
+ o "op.write_field_end"
338
+ elsif desc = @enums[arg.type]
339
+ o "op.write_field_begin '#{arg.name}', ::Thrift::Types::I32, #{arg.index}"
340
+ o "op.write_i32 Enum_#{desc.name}[#{arg.name}.to_sym]"
341
+
342
+ o "op.write_field_end"
343
+ elsif arg.type.kind_of? Stark::Parser::AST::Map
344
+ o "#{arg.name} = hash_cast #{arg.name}"
345
+ o "op.write_field_begin '#{arg.name}', ::Thrift::Types::MAP, #{arg.index}"
346
+ o "op.write_map_begin(#{wire_type(arg.type.key)}, #{wire_type(arg.type.value)}, #{arg.name}.size)"
347
+
348
+ o "#{arg.name}.each do |k,v|"
349
+ indent
350
+ o "op.#{write_func(arg.type.key)} k"
351
+ o "op.#{write_func(arg.type.value)} v"
352
+ outdent
353
+ o "end"
354
+
355
+ o "op.write_map_end"
356
+ o "op.write_field_end"
357
+ elsif arg.type.kind_of? Stark::Parser::AST::List
358
+ o "#{arg.name} = Array(#{arg.name})"
359
+ o "op.write_field_begin '#{arg.name}', ::Thrift::Types::LIST, #{arg.index}"
360
+ o "op.write_list_begin(#{wire_type(arg.type.value)}, #{arg.name}.size)"
361
+ o "#{arg.name}.each { |v| op.#{write_func(arg.type.value)}(v) }"
362
+ o "op.write_list_end"
363
+
364
+ o "op.write_field_end"
365
+ elsif arg.type != "void"
366
+ o "op.write_field_begin '#{arg.name}', #{type(arg.type)}, #{arg.index}"
367
+ o "op.#{write_func(arg.type)} #{arg.name}"
368
+ o "op.write_field_end"
369
+ end
370
+ end
371
+
372
+ o "op.write_field_stop"
373
+ o "op.write_struct_end"
374
+ o "op.write_message_end"
375
+ o "op.trans.flush"
376
+
377
+ o "ip = @iprot"
378
+ o "_, mtype, _ = ip.read_message_begin"
379
+ o "handle_exception mtype"
380
+
381
+ o "ip.read_struct_begin"
382
+ o "result = nil"
383
+
384
+ if func.return_type == "void"
385
+ o "_, rtype, _ = ip.read_field_begin"
386
+ else
387
+ if desc = @structs[func.return_type]
388
+ o "_, rtype, rid = ip.read_field_begin"
389
+ o "if rtype != #{wire_type(func.return_type)}"
390
+ o " handle_unexpected rtype"
391
+ o "else"
392
+ o " result = read_generic rtype, rid, #{desc.name}"
393
+ o "end"
394
+ elsif desc = @enums[func.return_type]
395
+ o "_, rtype, rid = ip.read_field_begin"
396
+ o "if rtype != #{wire_type(func.return_type)}"
397
+ o " handle_unexpected rtype"
398
+ o "else"
399
+ o " result = Enum_#{desc.name}[ip.read_i32]"
400
+ o "end"
401
+
402
+ elsif func.return_type.kind_of? Stark::Parser::AST::Map
403
+ ft = func.return_type
404
+
405
+ o "_, rtype, rid = ip.read_field_begin"
406
+ o "if rtype != #{wire_type(func.return_type)}"
407
+ o " handle_unexpected rtype"
408
+ o "else"
409
+ o " kt, vt, size = ip.read_map_begin"
410
+ o " if kt == #{wire_type(ft.key)} && vt == #{wire_type(ft.value)}"
411
+ o " result = {}"
412
+ o " size.times do"
413
+ o " result[ip.#{read_func(ft.key)}] = ip.#{read_func(ft.value)}"
414
+ o " end"
415
+ o " else"
416
+ o " handle_bad_map size"
417
+ o " end"
418
+ o " ip.read_map_end"
419
+ o "end"
420
+ elsif func.return_type.kind_of? Stark::Parser::AST::List
421
+ ft = func.return_type
422
+ o "_, rtype, rid = ip.read_field_begin"
423
+ o "if rtype == ::Thrift::Types::LIST"
424
+ o " vt, size = ip.read_list_begin"
425
+ o " if vt == #{wire_type(ft.value)}"
426
+ o " result = Array.new(size) { |n| ip.#{read_func(ft.value)} }"
427
+ o " else"
428
+ o " handle_bad_list size"
429
+ o " end"
430
+ o " ip.read_list_end"
431
+ o "else"
432
+ o " handle_unexpected rtype"
433
+ o "end"
434
+ else
435
+ o "_, rtype, _ = ip.read_field_begin"
436
+ o "if rtype == #{type(func.return_type)}"
437
+ o " result = ip.#{read_func(func.return_type)}"
438
+ o "else"
439
+ o " handle_unexpected rtype"
440
+ o "end"
441
+ end
442
+
443
+ o "_, rtype, rid = ip.read_field_begin unless rtype == ::Thrift::Types::STOP"
444
+ end
445
+
446
+ o "fail if rtype != ::Thrift::Types::STOP"
447
+
448
+ o "ip.read_struct_end"
449
+ o "ip.read_message_end"
450
+ o "return result"
451
+
452
+ outdent
453
+
454
+ o "end"
455
+ end
456
+
457
+ outdent
458
+ o "end"
459
+
460
+ write_processor serv
461
+
462
+ outdent
463
+ o "end"
464
+ end
465
+ end
466
+
467
+ end
468
+
@@ -0,0 +1,26 @@
1
+ module Stark
2
+ class Struct
3
+ def initialize(fields={})
4
+ @fields = fields
5
+ end
6
+
7
+ def set_from_index(type, idx, ip)
8
+ info = self.class::Fields[idx]
9
+ return unless info
10
+
11
+ if info.type == type
12
+ @fields[info.name] = info.read(ip)
13
+ else
14
+ ip.skip type
15
+ end
16
+ end
17
+
18
+ def method_missing(meth, *args)
19
+ if val = @fields[meth.to_s]
20
+ return val
21
+ end
22
+
23
+ super
24
+ end
25
+ end
26
+ end