stark 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,13 @@
1
+ === 0.7.0 / 2013-03-04
2
+
3
+ * 5 bugfixes:
4
+
5
+ * Add proper support for include
6
+ * Add proper support for namespace
7
+ * Fix lists in structs
8
+ * Fix reading enums in structs
9
+ * Flesh out more converters, get struct-in-struct working properly
10
+
1
11
  === 0.6.1 / 2013-03-02
2
12
 
3
13
  * 1 bugfix:
data/Manifest.txt CHANGED
@@ -19,9 +19,11 @@ lib/stark/struct.rb
19
19
  lib/stark/thrift.kpeg
20
20
  stark.gemspec
21
21
  test/ThriftSpec.thrift
22
+ test/blah.thrift
22
23
  test/gen-rb/profile_constants.rb
23
24
  test/gen-rb/profile_types.rb
24
25
  test/gen-rb/user_storage.rb
26
+ test/include_blah.thrift
25
27
  test/leg.rb
26
28
  test/legacy_profile/profile_constants.rb
27
29
  test/legacy_profile/profile_types.rb
@@ -29,4 +31,5 @@ test/legacy_profile/user_storage.rb
29
31
  test/profile.thrift
30
32
  test/test_client.rb
31
33
  test/test_parser.rb
34
+ test/test_ruby.rb
32
35
  test/test_server.rb
data/README.txt CHANGED
@@ -13,9 +13,13 @@ Optimized thrift bindings for ruby
13
13
 
14
14
  == SYNOPSIS:
15
15
 
16
- $ stark service.thrift > service.rb
16
+ $ stark service.thrift service.rb
17
17
  require 'service'
18
18
 
19
+ OR
20
+
21
+ Stark.materialize "service.thrift"
22
+
19
23
  Use Service::Client and Service::Processor like the default thrift
20
24
  docs describe them.
21
25
 
data/Rakefile CHANGED
@@ -17,6 +17,4 @@ task :parser do
17
17
  sh "kpeg -o lib/stark/raw_parser.rb -s -f lib/stark/thrift.kpeg"
18
18
  end
19
19
 
20
- # task :test => :parser
21
-
22
20
  # vim: syntax=ruby
data/bin/stark CHANGED
@@ -4,14 +4,20 @@ require 'rubygems'
4
4
  require 'stark/parser'
5
5
  require 'stark/ruby'
6
6
 
7
- data = File.read ARGV.shift
7
+ file = ARGV.shift
8
+ unless file
9
+ puts "stark blah.thrift <blah.rb>"
10
+ exit 1
11
+ end
8
12
 
9
- tg = Stark::Parser.new data
13
+ ast = Stark::Parser.ast File.read(file)
10
14
 
11
- unless tg.parse
12
- tg.raise_error
15
+ if out = ARGV.shift
16
+ out = File.open out, "w"
17
+ else
18
+ out = STDOUT
13
19
  end
14
20
 
15
- ruby = Stark::Ruby.new
21
+ ruby = Stark::Ruby.new out
16
22
 
17
- tg.result.each { |i| i.accept ruby }
23
+ ruby.run ast
@@ -2,6 +2,38 @@ require 'thrift'
2
2
 
3
3
  module Stark
4
4
  module Converters
5
+ module BYTE
6
+ module_function
7
+
8
+ def type
9
+ Thrift::Types::BYTE
10
+ end
11
+
12
+ def read(ip)
13
+ ip.read_byte
14
+ end
15
+
16
+ def write(op, value)
17
+ op.write_byte value
18
+ end
19
+ end
20
+
21
+ module I16
22
+ module_function
23
+
24
+ def type
25
+ Thrift::Types::I16
26
+ end
27
+
28
+ def read(ip)
29
+ ip.read_i16
30
+ end
31
+
32
+ def write(op, value)
33
+ op.write_i16 value
34
+ end
35
+ end
36
+
5
37
  module I32
6
38
  module_function
7
39
 
@@ -18,6 +50,54 @@ module Stark
18
50
  end
19
51
  end
20
52
 
53
+ module I64
54
+ module_function
55
+
56
+ def type
57
+ Thrift::Types::I64
58
+ end
59
+
60
+ def read(ip)
61
+ ip.read_i64
62
+ end
63
+
64
+ def write(op, value)
65
+ op.write_i64 value
66
+ end
67
+ end
68
+
69
+ module BOOL
70
+ module_function
71
+
72
+ def type
73
+ Thrift::Types::BOOL
74
+ end
75
+
76
+ def read(ip)
77
+ ip.read_bool
78
+ end
79
+
80
+ def write(op, value)
81
+ op.write_bool value
82
+ end
83
+ end
84
+
85
+ module DOUBLE
86
+ module_function
87
+
88
+ def type
89
+ Thrift::Types::DOUBLE
90
+ end
91
+
92
+ def read(ip)
93
+ ip.read_double
94
+ end
95
+
96
+ def write(op, value)
97
+ op.write_double value
98
+ end
99
+ end
100
+
21
101
  module STRING
22
102
  module_function
23
103
 
@@ -33,5 +113,76 @@ module Stark
33
113
  op.write_string value
34
114
  end
35
115
  end
116
+
117
+ class Struct
118
+ def initialize(cls)
119
+ @class = cls
120
+ end
121
+
122
+ def type
123
+ Thrift::Types::STRUCT
124
+ end
125
+
126
+ def read(ip)
127
+ obj = @class.new
128
+ obj.read ip
129
+ end
130
+
131
+ def write(op, value)
132
+ value.write op
133
+ end
134
+ end
135
+
136
+ class Enum
137
+ def initialize(cls)
138
+ @class = cls
139
+ end
140
+
141
+ def type
142
+ Thrift::Types::I32
143
+ end
144
+
145
+ def read(ip)
146
+ @class[ip.read_i32]
147
+ end
148
+
149
+ def write(op, value)
150
+ op.write_i32 @class[value]
151
+ end
152
+ end
153
+
154
+ class List
155
+ def initialize(value)
156
+ @value = value
157
+ end
158
+
159
+ def type
160
+ Thrift::Types::LIST
161
+ end
162
+
163
+ def read(ip)
164
+ vt, size = ip.read_list_begin
165
+
166
+ if vt != @value.type
167
+ raise TypeError, "List expected to be type: #{@value.type}"
168
+ end
169
+
170
+ v = @value
171
+
172
+ Array.new(size) { v.read(ip) }
173
+ end
174
+
175
+ def write(op, value)
176
+ value = Array(value)
177
+
178
+ op.write_list_begin @value.type, value.size
179
+
180
+ c = @value
181
+ value.each { |v| c.write op, v }
182
+
183
+ op.write_list_end
184
+ end
185
+
186
+ end
36
187
  end
37
188
  end
data/lib/stark/parser.rb CHANGED
@@ -2,3 +2,31 @@ module Stark
2
2
  end
3
3
 
4
4
  require 'stark/raw_parser'
5
+
6
+ class Stark::Parser
7
+ def self.expand(ast)
8
+ out = []
9
+
10
+ ast.each do |elem|
11
+ case elem
12
+ when AST::Include
13
+ data = File.read elem.path
14
+ out += expand(Stark::Parser.ast(data))
15
+ else
16
+ out << elem
17
+ end
18
+ end
19
+
20
+ out
21
+ end
22
+
23
+ def ast
24
+ raise_error unless parse
25
+ Stark::Parser.expand result
26
+ end
27
+
28
+ def self.ast(arg)
29
+ parser = Stark::Parser.new arg
30
+ parser.ast
31
+ end
32
+ end
@@ -1609,7 +1609,7 @@ class Stark::Parser
1609
1609
  return _tmp
1610
1610
  end
1611
1611
 
1612
- # Element = (Comment | Header bsp | Definition bsp)
1612
+ # Element = (Comment | obsp Header bsp | Definition bsp)
1613
1613
  def _Element
1614
1614
 
1615
1615
  _save = self.pos
@@ -1620,6 +1620,11 @@ class Stark::Parser
1620
1620
 
1621
1621
  _save1 = self.pos
1622
1622
  while true # sequence
1623
+ _tmp = apply(:_obsp)
1624
+ unless _tmp
1625
+ self.pos = _save1
1626
+ break
1627
+ end
1623
1628
  _tmp = apply(:_Header)
1624
1629
  unless _tmp
1625
1630
  self.pos = _save1
@@ -3983,7 +3988,7 @@ class Stark::Parser
3983
3988
  Rules[:_CaptureDocText] = rule_info("CaptureDocText", "{}")
3984
3989
  Rules[:_DestroyDocText] = rule_info("DestroyDocText", "{}")
3985
3990
  Rules[:_HeaderList] = rule_info("HeaderList", "(HeaderList Header | Header)")
3986
- Rules[:_Element] = rule_info("Element", "(Comment | Header bsp | Definition bsp)")
3991
+ Rules[:_Element] = rule_info("Element", "(Comment | obsp Header bsp | Definition bsp)")
3987
3992
  Rules[:_Header] = rule_info("Header", "(Include | Namespace)")
3988
3993
  Rules[:_Namespace] = rule_info("Namespace", "(\"namespace\" - tok_identifier:l - tok_identifier:n {namespace(l,n)} | \"namespace\" - \"*\" - tok_identifier:n {namespace(nil,n)})")
3989
3994
  Rules[:_Include] = rule_info("Include", "\"include\" - tok_literal:f {include(f)}")
data/lib/stark/ruby.rb CHANGED
@@ -21,8 +21,22 @@ module Stark
21
21
  o "require 'stark/exception'"
22
22
  end
23
23
 
24
+ def run(ast)
25
+ ast.each { |a| a.accept self }
26
+ close
27
+ end
28
+
29
+ def close
30
+ if @namespace
31
+ outdent
32
+ o "end"
33
+ end
34
+ end
35
+
24
36
  def process_namespace(ns)
25
37
  @namespace = ns.namespace if ns.lang == "rb"
38
+ o "module #{ns.namespace}"
39
+ indent
26
40
  end
27
41
 
28
42
  def process_include(inc)
@@ -42,6 +56,20 @@ module Stark
42
56
  @enums[enum.name] = enum
43
57
  end
44
58
 
59
+ def converter(t)
60
+ if t.kind_of? Stark::Parser::AST::List
61
+ "Stark::Converters::List.new(#{converter(t.value)})"
62
+ elsif BUILTINS.include? t.downcase
63
+ "Stark::Converters::#{t.upcase}"
64
+ elsif desc = @structs[t]
65
+ "Stark::Converters::Struct.new(#{t})"
66
+ elsif desc = @enums[t]
67
+ "Stark::Converters::Enum.new(Enum_#{t})"
68
+ else
69
+ raise "Blah"
70
+ end
71
+ end
72
+
45
73
  def process_struct(str)
46
74
  @structs[str.name] = str
47
75
 
@@ -50,13 +78,12 @@ module Stark
50
78
  o "Fields = {"
51
79
  indent
52
80
 
53
- str.fields.each do |f|
54
- c = "Stark::Converters::#{f.type.upcase}"
55
-
56
- o "#{f.index} => Stark::Field.new(#{f.index}, '#{f.name}', #{c}),"
81
+ fields = str.fields.map do |f|
82
+ c = converter f.type
83
+ "#{f.index} => Stark::Field.new(#{f.index}, '#{f.name}', #{c})"
57
84
  end
58
85
 
59
- o ":count => #{str.fields.size}"
86
+ o " #{fields.join(', ')}"
60
87
 
61
88
  outdent
62
89
  o "}"
@@ -70,6 +97,8 @@ module Stark
70
97
 
71
98
  end
72
99
 
100
+ BUILTINS = %w!bool byte i16 i32 i64 double string!
101
+
73
102
  def process_exception(str)
74
103
  @exceptions[str.name] = str
75
104
 
@@ -81,13 +110,12 @@ module Stark
81
110
  o "Fields = {"
82
111
  indent
83
112
 
84
- str.fields.each do |f|
85
- c = "Stark::Converters::#{f.type.upcase}"
86
-
87
- o "#{f.index} => Stark::Field.new(#{f.index}, '#{f.name}', #{c}),"
113
+ fields = str.fields.map do |f|
114
+ c = converter f.type
115
+ "#{f.index} => Stark::Field.new(#{f.index}, '#{f.name}', #{c})"
88
116
  end
89
117
 
90
- o ":count => #{str.fields.size}"
118
+ o " #{fields.join(', ')}"
91
119
 
92
120
  outdent
93
121
  o "}"
@@ -187,19 +215,52 @@ module Stark
187
215
  WriteFunc[t] || raise("unknown type - #{t}")
188
216
  end
189
217
 
218
+ def write_field(ft, name, idx)
219
+ if desc = @structs[ft]
220
+ o "op.write_field_begin '#{name}', ::Thrift::Types::STRUCT, #{idx}"
221
+ output_struct desc, name
222
+ o "op.write_field_end"
223
+ elsif desc = @enums[ft]
224
+ o "op.write_field_begin '#{name}', ::Thrift::Types::I32, #{idx}"
225
+ o "op.write_i32 Enum_#{desc.name}[#{name}.to_sym]"
226
+
227
+ o "op.write_field_end"
228
+ elsif ft.kind_of? Stark::Parser::AST::Map
229
+ o "#{name} = hash_cast #{name}"
230
+ o "op.write_field_begin '#{name}', ::Thrift::Types::MAP, #{idx}"
231
+ o "op.write_map_begin(#{wire_type(ft.key)}, #{wire_type(ft.value)}, #{name}.size)"
232
+
233
+ o "#{name}.each do |k,v|"
234
+ indent
235
+ o "op.#{write_func(ft.key)} k"
236
+ o "op.#{write_func(ft.value)} v"
237
+ outdent
238
+ o "end"
239
+
240
+ o "op.write_map_end"
241
+ o "op.write_field_end"
242
+ elsif ft.kind_of? Stark::Parser::AST::List
243
+ o "#{name} = Array(#{name})"
244
+ o "op.write_field_begin '#{name}', ::Thrift::Types::LIST, #{idx}"
245
+ o "op.write_list_begin(#{wire_type(ft.value)}, #{name}.size)"
246
+ o "#{name}.each { |v| op.#{write_func(ft.value)}(v) }"
247
+ o "op.write_list_end"
248
+
249
+ o "op.write_field_end"
250
+ elsif ft != "void"
251
+ o "op.write_field_begin '#{name}', #{type(ft)}, #{idx}"
252
+ o "op.#{write_func(ft)} #{name}"
253
+ o "op.write_field_end"
254
+ end
255
+
256
+ end
257
+
190
258
  def output_struct(desc, obj)
191
259
  o "op.write_struct_begin '#{desc.name}'"
192
260
 
193
261
  desc.fields.each do |f|
194
- if desc = @structs[f.type]
195
- o "op.write_field_begin '#{f.name}', ::Thrift::Types::STRUCT, #{f.index}"
196
- output_struct desc, f.name
197
- o "op.write_field_end"
198
- else
199
- o "op.write_field_begin '#{f.name}', #{type(f.type)}, #{f.index}"
200
- o "op.#{write_func(f.type)} #{obj}.#{f.name}"
201
- o "op.write_field_end"
202
- end
262
+ o "#{f.name} = #{obj}.#{f.name}"
263
+ write_field f.type, f.name, f.index
203
264
  end
204
265
 
205
266
  o "op.write_field_stop"
@@ -310,42 +371,7 @@ module Stark
310
371
 
311
372
  ft = func.return_type
312
373
 
313
- if desc = @structs[ft]
314
- o "op.write_field_begin 'result', ::Thrift::Types::STRUCT, 0"
315
- output_struct desc, "result"
316
- o "op.write_field_end"
317
- elsif desc = @enums[ft]
318
- o "op.write_field_begin 'result', ::Thrift::Types::I32, 0"
319
- o "op.write_i32 Enum_#{desc.name}[result.to_sym]"
320
-
321
- o "op.write_field_end"
322
- elsif ft.kind_of? Stark::Parser::AST::Map
323
- o "result = hash_cast result"
324
- o "op.write_field_begin 'result', ::Thrift::Types::MAP, 0"
325
- o "op.write_map_begin(#{wire_type(ft.key)}, #{wire_type(ft.value)}, result.size)"
326
-
327
- o "result.each do |k,v|"
328
- indent
329
- o "op.#{write_func(ft.key)} k"
330
- o "op.#{write_func(ft.value)} v"
331
- outdent
332
- o "end"
333
-
334
- o "op.write_map_end"
335
- o "op.write_field_end"
336
- elsif ft.kind_of? Stark::Parser::AST::List
337
- o "result = Array(result)"
338
- o "op.write_field_begin 'result', ::Thrift::Types::LIST, 0"
339
- o "op.write_list_begin(#{wire_type(ft.value)}, result.size)"
340
- o "result.each { |v| op.#{write_func(ft.value)}(v) }"
341
- o "op.write_list_end"
342
-
343
- o "op.write_field_end"
344
- elsif ft != "void"
345
- o "op.write_field_begin 'result', #{type(ft)}, 0"
346
- o "op.#{write_func(ft)} result"
347
- o "op.write_field_end"
348
- end
374
+ write_field ft, 'result', 0
349
375
 
350
376
  o "op.write_field_stop"
351
377
  o "op.write_struct_end"
@@ -393,42 +419,7 @@ module Stark
393
419
  o "op.write_struct_begin \"#{func.name}_args\""
394
420
 
395
421
  Array(func.arguments).each do |arg|
396
- if desc = @structs[arg.type]
397
- o "op.write_field_begin '#{arg.name}', ::Thrift::Types::STRUCT, #{arg.index}"
398
- output_struct desc, arg.name
399
- o "op.write_field_end"
400
- elsif desc = @enums[arg.type]
401
- o "op.write_field_begin '#{arg.name}', ::Thrift::Types::I32, #{arg.index}"
402
- o "op.write_i32 Enum_#{desc.name}[#{arg.name}.to_sym]"
403
-
404
- o "op.write_field_end"
405
- elsif arg.type.kind_of? Stark::Parser::AST::Map
406
- o "#{arg.name} = hash_cast #{arg.name}"
407
- o "op.write_field_begin '#{arg.name}', ::Thrift::Types::MAP, #{arg.index}"
408
- o "op.write_map_begin(#{wire_type(arg.type.key)}, #{wire_type(arg.type.value)}, #{arg.name}.size)"
409
-
410
- o "#{arg.name}.each do |k,v|"
411
- indent
412
- o "op.#{write_func(arg.type.key)} k"
413
- o "op.#{write_func(arg.type.value)} v"
414
- outdent
415
- o "end"
416
-
417
- o "op.write_map_end"
418
- o "op.write_field_end"
419
- elsif arg.type.kind_of? Stark::Parser::AST::List
420
- o "#{arg.name} = Array(#{arg.name})"
421
- o "op.write_field_begin '#{arg.name}', ::Thrift::Types::LIST, #{arg.index}"
422
- o "op.write_list_begin(#{wire_type(arg.type.value)}, #{arg.name}.size)"
423
- o "#{arg.name}.each { |v| op.#{write_func(arg.type.value)}(v) }"
424
- o "op.write_list_end"
425
-
426
- o "op.write_field_end"
427
- elsif arg.type != "void"
428
- o "op.write_field_begin '#{arg.name}', #{type(arg.type)}, #{arg.index}"
429
- o "op.#{write_func(arg.type)} #{arg.name}"
430
- o "op.write_field_end"
431
- end
422
+ write_field arg.type, arg.name, arg.index
432
423
  end
433
424
 
434
425
  o "op.write_field_stop"
data/lib/stark/struct.rb CHANGED
@@ -15,6 +15,23 @@ module Stark
15
15
  end
16
16
  end
17
17
 
18
+ def read(ip)
19
+ ip.read_struct_begin
20
+
21
+ while true
22
+ _, ftype, fid = ip.read_field_begin
23
+ break if ftype == ::Thrift::Types::STOP
24
+
25
+ set_from_index ftype, fid, ip
26
+
27
+ ip.read_field_end
28
+ end
29
+
30
+ ip.read_struct_end
31
+
32
+ self
33
+ end
34
+
18
35
  def write_fields(op)
19
36
  self.class::Fields.each do |idx, field|
20
37
  next if idx == :count
@@ -184,7 +184,7 @@ HeaderList = HeaderList Header
184
184
  | Header
185
185
 
186
186
  Element = Comment
187
- | Header bsp
187
+ | obsp Header bsp
188
188
  | Definition bsp
189
189
 
190
190
  Header = Include | Namespace
data/lib/stark.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'thrift'
2
2
 
3
3
  module Stark
4
- VERSION = '0.6.1'
4
+ VERSION = '0.7.0'
5
5
 
6
6
  def self.pipe_transport
7
7
  cr, cw = IO.pipe
@@ -18,19 +18,16 @@ module Stark
18
18
  require 'stark/ruby'
19
19
  require 'stringio'
20
20
 
21
- data = File.read file
22
-
23
- tg = Stark::Parser.new data
24
-
25
- unless tg.parse
26
- tg.raise_error
27
- end
21
+ ast = Stark::Parser.ast File.read(file)
28
22
 
29
23
  stream = StringIO.new
30
24
 
31
25
  ruby = Stark::Ruby.new stream
26
+ ruby.run ast
32
27
 
33
- tg.result.each { |i| i.accept ruby }
28
+ if ENV['STARK_DEBUG']
29
+ puts stream.string
30
+ end
34
31
 
35
32
  namespace.module_eval stream.string
36
33
  end
data/test/blah.thrift ADDED
@@ -0,0 +1,5 @@
1
+ enum Blah {
2
+ FOO
3
+ BAR
4
+ BAZ
5
+ }