google-protobuf 3.19.0.rc.1-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/ext/google/protobuf_c/convert.c +348 -0
  3. data/ext/google/protobuf_c/convert.h +72 -0
  4. data/ext/google/protobuf_c/defs.c +1284 -0
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +20 -0
  7. data/ext/google/protobuf_c/map.c +694 -0
  8. data/ext/google/protobuf_c/map.h +67 -0
  9. data/ext/google/protobuf_c/message.c +1328 -0
  10. data/ext/google/protobuf_c/message.h +101 -0
  11. data/ext/google/protobuf_c/protobuf.c +470 -0
  12. data/ext/google/protobuf_c/protobuf.h +117 -0
  13. data/ext/google/protobuf_c/repeated_field.c +659 -0
  14. data/ext/google/protobuf_c/repeated_field.h +63 -0
  15. data/ext/google/protobuf_c/ruby-upb.c +9171 -0
  16. data/ext/google/protobuf_c/ruby-upb.h +4704 -0
  17. data/ext/google/protobuf_c/wrap_memcpy.c +51 -0
  18. data/lib/google/2.3/protobuf_c.bundle +0 -0
  19. data/lib/google/2.4/protobuf_c.bundle +0 -0
  20. data/lib/google/2.5/protobuf_c.bundle +0 -0
  21. data/lib/google/2.6/protobuf_c.bundle +0 -0
  22. data/lib/google/2.7/protobuf_c.bundle +0 -0
  23. data/lib/google/3.0/protobuf_c.bundle +0 -0
  24. data/lib/google/protobuf/any_pb.rb +19 -0
  25. data/lib/google/protobuf/api_pb.rb +41 -0
  26. data/lib/google/protobuf/descriptor_dsl.rb +458 -0
  27. data/lib/google/protobuf/descriptor_pb.rb +266 -0
  28. data/lib/google/protobuf/duration_pb.rb +19 -0
  29. data/lib/google/protobuf/empty_pb.rb +17 -0
  30. data/lib/google/protobuf/field_mask_pb.rb +18 -0
  31. data/lib/google/protobuf/message_exts.rb +53 -0
  32. data/lib/google/protobuf/repeated_field.rb +188 -0
  33. data/lib/google/protobuf/source_context_pb.rb +18 -0
  34. data/lib/google/protobuf/struct_pb.rb +37 -0
  35. data/lib/google/protobuf/timestamp_pb.rb +19 -0
  36. data/lib/google/protobuf/type_pb.rb +91 -0
  37. data/lib/google/protobuf/well_known_types.rb +235 -0
  38. data/lib/google/protobuf/wrappers_pb.rb +50 -0
  39. data/lib/google/protobuf.rb +79 -0
  40. data/tests/basic.rb +640 -0
  41. data/tests/generated_code_test.rb +23 -0
  42. data/tests/stress.rb +38 -0
  43. metadata +144 -0
@@ -0,0 +1,51 @@
1
+ // Protocol Buffers - Google's data interchange format
2
+ // Copyright 2017 Google Inc. All rights reserved.
3
+ // https://developers.google.com/protocol-buffers/
4
+ //
5
+ // Redistribution and use in source and binary forms, with or without
6
+ // modification, are permitted provided that the following conditions are
7
+ // met:
8
+ //
9
+ // * Redistributions of source code must retain the above copyright
10
+ // notice, this list of conditions and the following disclaimer.
11
+ // * Redistributions in binary form must reproduce the above
12
+ // copyright notice, this list of conditions and the following disclaimer
13
+ // in the documentation and/or other materials provided with the
14
+ // distribution.
15
+ // * Neither the name of Google Inc. nor the names of its
16
+ // contributors may be used to endorse or promote products derived from
17
+ // this software without specific prior written permission.
18
+ //
19
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ #include <string.h>
32
+
33
+ // On x86-64 Linux with glibc, we link against the 2.2.5 version of memcpy so
34
+ // that we avoid depending on the 2.14 version of the symbol. This way,
35
+ // distributions that are using pre-2.14 versions of glibc can successfully use
36
+ // the gem we distribute (https://github.com/protocolbuffers/protobuf/issues/2783).
37
+ //
38
+ // This wrapper is enabled by passing the linker flags -Wl,-wrap,memcpy in
39
+ // extconf.rb.
40
+ #ifdef __linux__
41
+ #if defined(__x86_64__) && defined(__GNU_LIBRARY__)
42
+ __asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
43
+ void *__wrap_memcpy(void *dest, const void *src, size_t n) {
44
+ return memcpy(dest, src, n);
45
+ }
46
+ #else
47
+ void *__wrap_memcpy(void *dest, const void *src, size_t n) {
48
+ return memmove(dest, src, n);
49
+ }
50
+ #endif
51
+ #endif
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,19 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: google/protobuf/any.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("google/protobuf/any.proto", :syntax => :proto3) do
8
+ add_message "google.protobuf.Any" do
9
+ optional :type_url, :string, 1
10
+ optional :value, :bytes, 2
11
+ end
12
+ end
13
+ end
14
+
15
+ module Google
16
+ module Protobuf
17
+ Any = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Any").msgclass
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: google/protobuf/api.proto
3
+
4
+ require 'google/protobuf/source_context_pb'
5
+ require 'google/protobuf/type_pb'
6
+ require 'google/protobuf'
7
+
8
+ Google::Protobuf::DescriptorPool.generated_pool.build do
9
+ add_file("google/protobuf/api.proto", :syntax => :proto3) do
10
+ add_message "google.protobuf.Api" do
11
+ optional :name, :string, 1
12
+ repeated :methods, :message, 2, "google.protobuf.Method"
13
+ repeated :options, :message, 3, "google.protobuf.Option"
14
+ optional :version, :string, 4
15
+ optional :source_context, :message, 5, "google.protobuf.SourceContext"
16
+ repeated :mixins, :message, 6, "google.protobuf.Mixin"
17
+ optional :syntax, :enum, 7, "google.protobuf.Syntax"
18
+ end
19
+ add_message "google.protobuf.Method" do
20
+ optional :name, :string, 1
21
+ optional :request_type_url, :string, 2
22
+ optional :request_streaming, :bool, 3
23
+ optional :response_type_url, :string, 4
24
+ optional :response_streaming, :bool, 5
25
+ repeated :options, :message, 6, "google.protobuf.Option"
26
+ optional :syntax, :enum, 7, "google.protobuf.Syntax"
27
+ end
28
+ add_message "google.protobuf.Mixin" do
29
+ optional :name, :string, 1
30
+ optional :root, :string, 2
31
+ end
32
+ end
33
+ end
34
+
35
+ module Google
36
+ module Protobuf
37
+ Api = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Api").msgclass
38
+ Method = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Method").msgclass
39
+ Mixin = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Mixin").msgclass
40
+ end
41
+ end
@@ -0,0 +1,458 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Code that implements the DSL for defining proto messages.
4
+
5
+ require 'google/protobuf/descriptor_pb'
6
+
7
+ module Google
8
+ module Protobuf
9
+ module Internal
10
+ class AtomicCounter
11
+ def initialize
12
+ @n = 0
13
+ @mu = Mutex.new
14
+ end
15
+
16
+ def get_and_increment
17
+ n = @n
18
+ @mu.synchronize {
19
+ @n += 1
20
+ }
21
+ return n
22
+ end
23
+ end
24
+
25
+ class Builder
26
+ @@file_number = AtomicCounter.new
27
+
28
+ def initialize(pool)
29
+ @pool = pool
30
+ @default_file = nil # Constructed lazily
31
+ end
32
+
33
+ def add_file(name, options={}, &block)
34
+ builder = FileBuilder.new(@pool, name, options)
35
+ builder.instance_eval(&block)
36
+ internal_add_file(builder)
37
+ end
38
+
39
+ def add_message(name, &block)
40
+ internal_default_file.add_message(name, &block)
41
+ end
42
+
43
+ def add_enum(name, &block)
44
+ internal_default_file.add_enum(name, &block)
45
+ end
46
+
47
+ # ---- Internal methods, not part of the DSL ----
48
+
49
+ def build
50
+ if @default_file
51
+ internal_add_file(@default_file)
52
+ end
53
+ end
54
+
55
+ private def internal_add_file(file_builder)
56
+ proto = file_builder.build
57
+ serialized = Google::Protobuf::FileDescriptorProto.encode(proto)
58
+ @pool.add_serialized_file(serialized)
59
+ end
60
+
61
+ private def internal_default_file
62
+ number = @@file_number.get_and_increment
63
+ filename = "ruby_default_file#{number}.proto"
64
+ @default_file ||= FileBuilder.new(@pool, filename)
65
+ end
66
+ end
67
+
68
+ class FileBuilder
69
+ def initialize(pool, name, options={})
70
+ @pool = pool
71
+ @file_proto = Google::Protobuf::FileDescriptorProto.new(
72
+ name: name,
73
+ syntax: options.fetch(:syntax, "proto3")
74
+ )
75
+ end
76
+
77
+ def add_message(name, &block)
78
+ builder = MessageBuilder.new(name, self, @file_proto)
79
+ builder.instance_eval(&block)
80
+ builder.internal_add_synthetic_oneofs
81
+ end
82
+
83
+ def add_enum(name, &block)
84
+ EnumBuilder.new(name, @file_proto).instance_eval(&block)
85
+ end
86
+
87
+ # ---- Internal methods, not part of the DSL ----
88
+
89
+ # These methods fix up the file descriptor to account for differences
90
+ # between the DSL and FileDescriptorProto.
91
+
92
+ # The DSL can omit a package name; here we infer what the package is if
93
+ # was not specified.
94
+ def infer_package(names)
95
+ # Package is longest common prefix ending in '.', if any.
96
+ if not names.empty?
97
+ min, max = names.minmax
98
+ last_common_dot = nil
99
+ min.size.times { |i|
100
+ if min[i] != max[i] then break end
101
+ if min[i] == "." then last_common_dot = i end
102
+ }
103
+ if last_common_dot
104
+ return min.slice(0, last_common_dot)
105
+ end
106
+ end
107
+
108
+ nil
109
+ end
110
+
111
+ def rewrite_enum_default(field)
112
+ if field.type != :TYPE_ENUM or !field.has_default_value? or !field.has_type_name?
113
+ return
114
+ end
115
+
116
+ value = field.default_value
117
+ type_name = field.type_name
118
+
119
+ if value.empty? or value[0].ord < "0".ord or value[0].ord > "9".ord
120
+ return
121
+ end
122
+
123
+ if type_name.empty? || type_name[0] != "."
124
+ return
125
+ end
126
+
127
+ type_name = type_name[1..-1]
128
+ as_int = Integer(value) rescue return
129
+
130
+ enum_desc = @pool.lookup(type_name)
131
+ if enum_desc.is_a?(Google::Protobuf::EnumDescriptor)
132
+ # Enum was defined in a previous file.
133
+ name = enum_desc.lookup_value(as_int)
134
+ if name
135
+ # Update the default value in the proto.
136
+ field.default_value = name
137
+ end
138
+ else
139
+ # See if enum was defined in this file.
140
+ @file_proto.enum_type.each { |enum_proto|
141
+ if enum_proto.name == type_name
142
+ enum_proto.value.each { |enum_value_proto|
143
+ if enum_value_proto.number == as_int
144
+ # Update the default value in the proto.
145
+ field.default_value = enum_value_proto.name
146
+ return
147
+ end
148
+ }
149
+ # We found the right enum, but no value matched.
150
+ return
151
+ end
152
+ }
153
+ end
154
+ end
155
+
156
+ # Historically we allowed enum defaults to be specified as a number.
157
+ # In retrospect this was a mistake as descriptors require defaults to
158
+ # be specified as a label. This can make a difference if multiple
159
+ # labels have the same number.
160
+ #
161
+ # Here we do a pass over all enum defaults and rewrite numeric defaults
162
+ # by looking up their labels. This is complicated by the fact that the
163
+ # enum definition can live in either the symtab or the file_proto.
164
+ #
165
+ # We take advantage of the fact that this is called *before* enums or
166
+ # messages are nested in other messages, so we only have to iterate
167
+ # one level deep.
168
+ def rewrite_enum_defaults
169
+ @file_proto.message_type.each { |msg|
170
+ msg.field.each { |field|
171
+ rewrite_enum_default(field)
172
+ }
173
+ }
174
+ end
175
+
176
+ # We have to do some relatively complicated logic here for backward
177
+ # compatibility.
178
+ #
179
+ # In descriptor.proto, messages are nested inside other messages if that is
180
+ # what the original .proto file looks like. For example, suppose we have this
181
+ # foo.proto:
182
+ #
183
+ # package foo;
184
+ # message Bar {
185
+ # message Baz {}
186
+ # }
187
+ #
188
+ # The descriptor for this must look like this:
189
+ #
190
+ # file {
191
+ # name: "test.proto"
192
+ # package: "foo"
193
+ # message_type {
194
+ # name: "Bar"
195
+ # nested_type {
196
+ # name: "Baz"
197
+ # }
198
+ # }
199
+ # }
200
+ #
201
+ # However, the Ruby generated code has always generated messages in a flat,
202
+ # non-nested way:
203
+ #
204
+ # Google::Protobuf::DescriptorPool.generated_pool.build do
205
+ # add_message "foo.Bar" do
206
+ # end
207
+ # add_message "foo.Bar.Baz" do
208
+ # end
209
+ # end
210
+ #
211
+ # Here we need to do a translation where we turn this generated code into the
212
+ # above descriptor. We need to infer that "foo" is the package name, and not
213
+ # a message itself. */
214
+
215
+ def split_parent_name(msg_or_enum)
216
+ name = msg_or_enum.name
217
+ idx = name.rindex(?.)
218
+ if idx
219
+ return name[0...idx], name[idx+1..-1]
220
+ else
221
+ return nil, name
222
+ end
223
+ end
224
+
225
+ def get_parent_msg(msgs_by_name, name, parent_name)
226
+ parent_msg = msgs_by_name[parent_name]
227
+ if parent_msg.nil?
228
+ raise "To define name #{name}, there must be a message named #{parent_name} to enclose it"
229
+ end
230
+ return parent_msg
231
+ end
232
+
233
+ def fix_nesting
234
+ # Calculate and update package.
235
+ msgs_by_name = @file_proto.message_type.map { |msg| [msg.name, msg] }.to_h
236
+ enum_names = @file_proto.enum_type.map { |enum_proto| enum_proto.name }
237
+
238
+ package = infer_package(msgs_by_name.keys + enum_names)
239
+ if package
240
+ @file_proto.package = package
241
+ end
242
+
243
+ # Update nesting based on package.
244
+ final_msgs = Google::Protobuf::RepeatedField.new(:message, Google::Protobuf::DescriptorProto)
245
+ final_enums = Google::Protobuf::RepeatedField.new(:message, Google::Protobuf::EnumDescriptorProto)
246
+
247
+ # Note: We don't iterate over msgs_by_name.values because we want to
248
+ # preserve order as listed in the DSL.
249
+ @file_proto.message_type.each { |msg|
250
+ parent_name, msg.name = split_parent_name(msg)
251
+ if parent_name == package
252
+ final_msgs << msg
253
+ else
254
+ get_parent_msg(msgs_by_name, msg.name, parent_name).nested_type << msg
255
+ end
256
+ }
257
+
258
+ @file_proto.enum_type.each { |enum|
259
+ parent_name, enum.name = split_parent_name(enum)
260
+ if parent_name == package
261
+ final_enums << enum
262
+ else
263
+ get_parent_msg(msgs_by_name, enum.name, parent_name).enum_type << enum
264
+ end
265
+ }
266
+
267
+ @file_proto.message_type = final_msgs
268
+ @file_proto.enum_type = final_enums
269
+ end
270
+
271
+ def internal_file_proto
272
+ @file_proto
273
+ end
274
+
275
+ def build
276
+ rewrite_enum_defaults
277
+ fix_nesting
278
+ return @file_proto
279
+ end
280
+ end
281
+
282
+ class MessageBuilder
283
+ def initialize(name, file_builder, file_proto)
284
+ @file_builder = file_builder
285
+ @msg_proto = Google::Protobuf::DescriptorProto.new(
286
+ :name => name
287
+ )
288
+ file_proto.message_type << @msg_proto
289
+ end
290
+
291
+ def optional(name, type, number, type_class=nil, options=nil)
292
+ internal_add_field(:LABEL_OPTIONAL, name, type, number, type_class, options)
293
+ end
294
+
295
+ def proto3_optional(name, type, number, type_class=nil, options=nil)
296
+ internal_add_field(:LABEL_OPTIONAL, name, type, number, type_class, options,
297
+ proto3_optional: true)
298
+ end
299
+
300
+ def required(name, type, number, type_class=nil, options=nil)
301
+ internal_add_field(:LABEL_REQUIRED, name, type, number, type_class, options)
302
+ end
303
+
304
+ def repeated(name, type, number, type_class = nil, options=nil)
305
+ internal_add_field(:LABEL_REPEATED, name, type, number, type_class, options)
306
+ end
307
+
308
+ def oneof(name, &block)
309
+ OneofBuilder.new(name, self).instance_eval(&block)
310
+ end
311
+
312
+ # Defines a new map field on this message type with the given key and
313
+ # value types, tag number, and type class (for message and enum value
314
+ # types). The key type must be :int32/:uint32/:int64/:uint64, :bool, or
315
+ # :string. The value type type must be a Ruby symbol (as accepted by
316
+ # FieldDescriptor#type=) and the type_class must be a string, if
317
+ # present (as accepted by FieldDescriptor#submsg_name=).
318
+ def map(name, key_type, value_type, number, value_type_class = nil)
319
+ if key_type == :float or key_type == :double or key_type == :enum or
320
+ key_type == :message
321
+ raise ArgError, "Not an acceptable key type: " + key_type
322
+ end
323
+ entry_name = "#{@msg_proto.name}_MapEntry_#{name}"
324
+
325
+ @file_builder.add_message entry_name do
326
+ optional :key, key_type, 1
327
+ optional :value, value_type, 2, value_type_class
328
+ end
329
+ options = @file_builder.internal_file_proto.message_type.last.options ||= MessageOptions.new
330
+ options.map_entry = true
331
+ repeated name, :message, number, entry_name
332
+ end
333
+
334
+ # ---- Internal methods, not part of the DSL ----
335
+
336
+ def internal_add_synthetic_oneofs
337
+ # We have to build a set of all names, to ensure that synthetic oneofs
338
+ # are not creating conflicts
339
+ names = {}
340
+ @msg_proto.field.each { |field| names[field.name] = true }
341
+ @msg_proto.oneof_decl.each { |oneof| names[oneof.name] = true }
342
+
343
+ @msg_proto.field.each { |field|
344
+ if field.proto3_optional
345
+ # Prepend '_' until we are no longer conflicting.
346
+ oneof_name = field.name
347
+ while names[oneof_name]
348
+ oneof_name = "_" + oneof_name
349
+ end
350
+ names[oneof_name] = true
351
+ field.oneof_index = @msg_proto.oneof_decl.size
352
+ @msg_proto.oneof_decl << Google::Protobuf::OneofDescriptorProto.new(
353
+ name: oneof_name
354
+ )
355
+ end
356
+ }
357
+ end
358
+
359
+ def internal_add_field(label, name, type, number, type_class, options,
360
+ oneof_index: nil, proto3_optional: false)
361
+ # Allow passing either:
362
+ # - (name, type, number, options) or
363
+ # - (name, type, number, type_class, options)
364
+ if options.nil? and type_class.instance_of?(Hash)
365
+ options = type_class;
366
+ type_class = nil;
367
+ end
368
+
369
+ field_proto = Google::Protobuf::FieldDescriptorProto.new(
370
+ :label => label,
371
+ :name => name,
372
+ :type => ("TYPE_" + type.to_s.upcase).to_sym,
373
+ :number => number
374
+ )
375
+
376
+ if type_class
377
+ # Make it an absolute type name by prepending a dot.
378
+ field_proto.type_name = "." + type_class
379
+ end
380
+
381
+ if oneof_index
382
+ field_proto.oneof_index = oneof_index
383
+ end
384
+
385
+ if proto3_optional
386
+ field_proto.proto3_optional = true
387
+ end
388
+
389
+ if options
390
+ if options.key?(:default)
391
+ default = options[:default]
392
+ if !default.instance_of?(String)
393
+ # Call #to_s since all defaults are strings in the descriptor.
394
+ default = default.to_s
395
+ end
396
+ # XXX: we should be C-escaping bytes defaults.
397
+ field_proto.default_value = default.dup.force_encoding("UTF-8")
398
+ end
399
+ if options.key?(:json_name)
400
+ field_proto.json_name = options[:json_name]
401
+ end
402
+ end
403
+
404
+ @msg_proto.field << field_proto
405
+ end
406
+
407
+ def internal_msg_proto
408
+ @msg_proto
409
+ end
410
+ end
411
+
412
+ class OneofBuilder
413
+ def initialize(name, msg_builder)
414
+ @msg_builder = msg_builder
415
+ oneof_proto = Google::Protobuf::OneofDescriptorProto.new(
416
+ :name => name
417
+ )
418
+ msg_proto = msg_builder.internal_msg_proto
419
+ @oneof_index = msg_proto.oneof_decl.size
420
+ msg_proto.oneof_decl << oneof_proto
421
+ end
422
+
423
+ def optional(name, type, number, type_class=nil, options=nil)
424
+ @msg_builder.internal_add_field(
425
+ :LABEL_OPTIONAL, name, type, number, type_class, options,
426
+ oneof_index: @oneof_index)
427
+ end
428
+ end
429
+
430
+ class EnumBuilder
431
+ def initialize(name, file_proto)
432
+ @enum_proto = Google::Protobuf::EnumDescriptorProto.new(
433
+ :name => name
434
+ )
435
+ file_proto.enum_type << @enum_proto
436
+ end
437
+
438
+ def value(name, number)
439
+ enum_value_proto = Google::Protobuf::EnumValueDescriptorProto.new(
440
+ name: name,
441
+ number: number
442
+ )
443
+ @enum_proto.value << enum_value_proto
444
+ end
445
+ end
446
+
447
+ end
448
+
449
+ # Re-open the class (the rest of the class is implemented in C)
450
+ class DescriptorPool
451
+ def build(&block)
452
+ builder = Internal::Builder.new(self)
453
+ builder.instance_eval(&block)
454
+ builder.build
455
+ end
456
+ end
457
+ end
458
+ end