stark 0.6.1 → 0.7.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/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
+ }