beefcake 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -67,25 +67,14 @@ Any object responding to `<<` can accept encoding
67
67
  Ruby deserves and needs first-class ProtoBuf support.
68
68
  Other libs didn't feel very "Ruby" to me and were hard to parse.
69
69
 
70
- # Caveats
70
+ # Generate code from `.proto` file
71
71
 
72
- Currently Beefcake doesn't parse `.proto` files. This is OK for now.
73
- In the simple case, you can create message types by hand; This is Ruby
74
- after all.
72
+ $ protoc --beefcake_out output/path -I path/to/proto/files/dir path/to/proto/file
75
73
 
76
- Example (for the above):
74
+ You can set the BEEFCAKE_NAMESPACE variable to generate the classes under a
75
+ desired namespace. (i.e. App::Foo::Bar)
77
76
 
78
- message Variety {
79
- required int32 x = 1
80
- required int32 y = 2
81
- optional string tag = 3
82
-
83
- ...
84
- }
85
-
86
- In the near future, a generator would be nice. I welcome anyone willing
87
- to work on it to submit patches. The other ruby libs lacked things I would
88
- like, such as an optional namespace param rather than installing on (main).
77
+ # Misc
89
78
 
90
79
  This library was built with EventMachine in mind. Not just blocking-IO.
91
80
 
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+
4
+ require 'beefcake'
5
+ require 'stringio'
6
+
7
+
8
+ class CodeGeneratorRequest
9
+ include Beefcake::Message
10
+
11
+
12
+ class FieldDescriptorProto
13
+ include Beefcake::Message
14
+
15
+ module Type
16
+ ## 0 is reserved for errors.
17
+ ## Order is weird for historical reasons.
18
+ TYPE_DOUBLE = 1
19
+ TYPE_FLOAT = 2
20
+ TYPE_INT64 = 3 ## Not ZigZag encoded. Negative numbers
21
+ ## take 10 bytes. Use TYPE_SINT64 if negative
22
+ ## values are likely.
23
+ TYPE_UINT64 = 4
24
+ TYPE_INT32 = 5 ## Not ZigZag encoded. Negative numbers
25
+ ## take 10 bytes. Use TYPE_SINT32 if negative
26
+ ## values are likely.
27
+ TYPE_FIXED64 = 6
28
+ TYPE_FIXED32 = 7
29
+ TYPE_BOOL = 8
30
+ TYPE_STRING = 9
31
+ TYPE_GROUP = 10 ## Tag-delimited aggregate.
32
+ TYPE_MESSAGE = 11 ## Length-delimited aggregate.
33
+
34
+ ## New in version 2.
35
+ TYPE_BYTES = 12
36
+ TYPE_UINT32 = 13
37
+ TYPE_ENUM = 14
38
+ TYPE_SFIXED32 = 15
39
+ TYPE_SFIXED64 = 16
40
+ TYPE_SINT32 = 17 ## Uses ZigZag encoding.
41
+ TYPE_SINT64 = 18 ## Uses ZigZag encoding.
42
+ end
43
+
44
+ module Label
45
+ LABEL_OPTIONAL = 1
46
+ LABEL_REQUIRED = 2
47
+ LABEL_REPEATED = 3
48
+ end
49
+
50
+ optional :name, :string, 1
51
+ optional :number, :int32, 3
52
+ optional :label, Label, 4
53
+
54
+ ## If type_name is set, this need not be set. If both this and type_name
55
+ ## are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
56
+ optional :type, Type, 5
57
+
58
+ ## For message and enum types, this is the name of the type. If the name
59
+ ## starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
60
+ ## rules are used to find the type (i.e. first the nested types within this
61
+ ## message are searched, then within the parent, on up to the root
62
+ ## namespace).
63
+ optional :type_name, :string, 6
64
+
65
+ ## For extensions, this is the name of the type being extended. It is
66
+ ## resolved in the same manner as type_name.
67
+ optional :extended, :string, 2
68
+
69
+ ## For numeric types, contains the original text representation of the value.
70
+ ## For booleans, "true" or "false".
71
+ ## For strings, contains the default text contents (not escaped in any way).
72
+ ## For bytes, contains the C escaped value. All bytes >= 128 are escaped.
73
+ optional :default_value, :string, 7
74
+ end
75
+
76
+
77
+ class EnumValueDescriptorProto
78
+ include Beefcake::Message
79
+
80
+ optional :name, :string, 1
81
+ optional :number, :int32, 2
82
+ # optional EnumValueOptions options = 3;
83
+ end
84
+
85
+ class EnumDescriptorProto
86
+ include Beefcake::Message
87
+
88
+ optional :name, :string, 1
89
+ repeated :value, EnumValueDescriptorProto, 2
90
+ # optional :options, EnumOptions, 3
91
+ end
92
+
93
+ class DescriptorProto
94
+ include Beefcake::Message
95
+
96
+ optional :name, :string, 1
97
+
98
+ repeated :field, FieldDescriptorProto, 2
99
+ repeated :extended, FieldDescriptorProto, 6
100
+ repeated :nested_type, DescriptorProto, 3
101
+ repeated :enum_type, EnumDescriptorProto, 4
102
+ end
103
+
104
+
105
+ class FileDescriptorProto
106
+ include Beefcake::Message
107
+
108
+ optional :name, :string, 1 # file name, relative to root of source tree
109
+ optional :package, :string, 2 # e.g. "foo", "foo.bar", etc.
110
+
111
+ repeated :message_type, DescriptorProto, 4;
112
+ end
113
+
114
+
115
+ repeated :file_to_generate, :string, 1
116
+ optional :parameter, :string, 2
117
+
118
+ repeated :proto_file, FileDescriptorProto, 15
119
+ end
120
+
121
+ class CodeGeneratorResponse
122
+ include Beefcake::Message
123
+
124
+ class File
125
+ include Beefcake::Message
126
+
127
+ optional :name, :string, 1
128
+ optional :content, :string, 15
129
+ end
130
+
131
+ repeated :file, File, 15
132
+ end
133
+
134
+
135
+ module Beefcake
136
+ class Generator < Struct.new(:c)
137
+
138
+ L = CodeGeneratorRequest::FieldDescriptorProto::Label
139
+ T = CodeGeneratorRequest::FieldDescriptorProto::Type
140
+
141
+
142
+ def self.compile(ns, req)
143
+ file = req.proto_file.map do |file|
144
+ g = new(StringIO.new)
145
+ g.compile(ns, file)
146
+
147
+ g.c.rewind
148
+ CodeGeneratorResponse::File.new(
149
+ :name => File.basename(file.name, ".proto") + ".pb.rb",
150
+ :content => g.c.read
151
+ )
152
+ end
153
+
154
+ CodeGeneratorResponse.new(:file => file)
155
+ end
156
+
157
+ def file!(file)
158
+ c.puts "## Generated from #{file.name} for #{file.package}"
159
+
160
+ file.message_type.each do |mt|
161
+ message!(mt)
162
+ end
163
+ end
164
+
165
+ def message!(pkg, mt)
166
+ c.puts
167
+ c.puts "class #{mt.name}"
168
+ c.puts " include Beefcake::Message"
169
+ c.puts
170
+
171
+ mt.enum_type.each do |et|
172
+ enum!(et)
173
+ end
174
+
175
+ ## Generate Types
176
+ (mt.nested_type || []).each do |nt|
177
+ message!(nt)
178
+ end
179
+ c.puts
180
+
181
+ ## Generate fields
182
+ (mt.field || []).each do |f|
183
+ field!(pkg, f)
184
+ end
185
+ c.puts
186
+
187
+ c.puts "end"
188
+ end
189
+
190
+ def enum!(et)
191
+ c.puts " module #{et.name}"
192
+ et.value.each do |v|
193
+ c.puts " %s = %d" % [v.name, v.number]
194
+ end
195
+ c.puts " end"
196
+ end
197
+
198
+ def field!(pkg, f)
199
+ # Turn the label into Ruby
200
+ label = name_for(f, L, f.label)
201
+
202
+ # Turn the name into a Ruby
203
+ name = ":#{f.name}"
204
+
205
+ # Determine the type-name and convert to Ruby
206
+ type = if f.type_name
207
+ # We have a type_name so we will use it after converting to a
208
+ # Ruby friendly version
209
+ t = f.type_name
210
+ t = t.gsub(pkg, "") # Remove the leading package name
211
+ t = t.gsub(/^\.*/, "") # Remove leading `.`s
212
+
213
+ t.gsub(".", "::") # Convert to Ruby namespacing syntax
214
+ else
215
+ ":#{name_for(f, T, f.type)}"
216
+ end
217
+
218
+ # Finally, generate the declaration
219
+ c.print " %s %s, %s, %d" % [label, name, type, f.number]
220
+
221
+ if f.default_value
222
+ c.print ", :default => #{f.default_value}"
223
+ end
224
+
225
+ c.puts
226
+ end
227
+
228
+ # Determines the name for a
229
+ def name_for(b, mod, val)
230
+ b.name_for(mod, val).gsub(/.*_/, "").downcase
231
+ end
232
+
233
+ def compile(ns, file)
234
+ c.puts "## Generated from #{file.name} for #{file.package}"
235
+
236
+ ns.each do |name|
237
+ c.puts "module #{name}"
238
+ end
239
+
240
+ file.message_type.each do |mt|
241
+ message!(file.package, mt)
242
+ end
243
+
244
+ ns.each do |name|
245
+ c.puts "end"
246
+ end
247
+ end
248
+
249
+ end
250
+ end
251
+
252
+ ns = (ENV["BEEFCAKE_NAMESPACE"] || "").split("::")
253
+
254
+ req = CodeGeneratorRequest.decode(STDIN.read)
255
+ res = Beefcake::Generator.compile(ns, req)
256
+
257
+ # Send it out!
258
+ STDOUT.print(res.encode)
@@ -84,7 +84,10 @@ module Beefcake
84
84
  end
85
85
 
86
86
  def encode!(buf, fld, fn)
87
- Array(self[fld.name]).each do |val|
87
+ v = self[fld.name]
88
+ v = v.is_a?(Array) ? v : [v]
89
+
90
+ v.compact.each do |val|
88
91
  case fld.type
89
92
  when Class # encodable
90
93
  # TODO: raise error if type != val.class
@@ -208,6 +211,7 @@ module Beefcake
208
211
  end
209
212
 
210
213
  def ==(o)
214
+ return false if o == nil
211
215
  fields.values.all? {|fld| self[fld.name] == o[fld.name] }
212
216
  end
213
217
 
@@ -218,6 +222,8 @@ module Beefcake
218
222
  val = self[fld.name]
219
223
 
220
224
  case fld.type
225
+ when Class
226
+ "#{fld.name}: #{val.inspect}"
221
227
  when Module
222
228
  title = name_for(fld.type, val) || "-NA-"
223
229
  "#{fld.name}: #{title}(#{val.inspect})"
@@ -120,11 +120,11 @@ class MessageTest < Test::Unit::TestCase
120
120
  def test_encode_strings
121
121
  buf = Beefcake::Buffer.new
122
122
 
123
- buf.append(:string, "testing", 1)
123
+ buf.append(:string, "test\ning", 1)
124
124
  buf.append(:bytes, "unixisawesome", 2)
125
125
 
126
126
  msg = LendelsMessage.new({
127
- :string => "testing",
127
+ :string => "test\ning",
128
128
  :bytes => "unixisawesome"
129
129
  })
130
130
 
@@ -325,6 +325,11 @@ class MessageTest < Test::Unit::TestCase
325
325
  assert_equal "<EnumsMessage a: -NA-(2)>", msg.inspect
326
326
  end
327
327
 
328
+ def test_inspect_nested_types
329
+ msg = CompositeMessage.new(:encodable => SimpleMessage.new(:a => 1))
330
+ assert_equal "<CompositeMessage encodable: <SimpleMessage a: 1>>", msg.inspect
331
+ end
332
+
328
333
  def test_to_hash
329
334
  msg = SimpleMessage.new :a => 1
330
335
  exp = { :a => 1 }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beefcake
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Blake Mizerany
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-15 00:00:00 -08:00
18
+ date: 2011-03-22 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -34,8 +34,8 @@ dependencies:
34
34
  version_requirements: *id001
35
35
  description: A sane protobuf library for Ruby
36
36
  email:
37
- executables: []
38
-
37
+ executables:
38
+ - protoc-gen-beefcake
39
39
  extensions: []
40
40
 
41
41
  extra_rdoc_files:
@@ -53,6 +53,7 @@ files:
53
53
  - test/buffer_encode_test.rb
54
54
  - test/buffer_test.rb
55
55
  - test/message_test.rb
56
+ - bin/protoc-gen-beefcake
56
57
  has_rdoc: true
57
58
  homepage: http://github.com/bmizerany/beefcake
58
59
  licenses: []