protobuf-cucumber 3.10.4
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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rubocop.yml +70 -0
- data/.rubocop_todo.yml +145 -0
- data/.travis.yml +40 -0
- data/.yardopts +5 -0
- data/CHANGES.md +344 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +64 -0
- data/bin/protoc-gen-ruby +22 -0
- data/bin/rpc_server +5 -0
- data/install-protobuf.sh +28 -0
- data/lib/protobuf.rb +129 -0
- data/lib/protobuf/cli.rb +257 -0
- data/lib/protobuf/code_generator.rb +120 -0
- data/lib/protobuf/decoder.rb +28 -0
- data/lib/protobuf/deprecation.rb +117 -0
- data/lib/protobuf/descriptors.rb +3 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +62 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +301 -0
- data/lib/protobuf/encoder.rb +11 -0
- data/lib/protobuf/enum.rb +365 -0
- data/lib/protobuf/exceptions.rb +9 -0
- data/lib/protobuf/field.rb +74 -0
- data/lib/protobuf/field/base_field.rb +380 -0
- data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
- data/lib/protobuf/field/bool_field.rb +64 -0
- data/lib/protobuf/field/bytes_field.rb +78 -0
- data/lib/protobuf/field/double_field.rb +25 -0
- data/lib/protobuf/field/enum_field.rb +61 -0
- data/lib/protobuf/field/field_array.rb +104 -0
- data/lib/protobuf/field/field_hash.rb +122 -0
- data/lib/protobuf/field/fixed32_field.rb +25 -0
- data/lib/protobuf/field/fixed64_field.rb +28 -0
- data/lib/protobuf/field/float_field.rb +43 -0
- data/lib/protobuf/field/int32_field.rb +21 -0
- data/lib/protobuf/field/int64_field.rb +34 -0
- data/lib/protobuf/field/integer_field.rb +23 -0
- data/lib/protobuf/field/message_field.rb +51 -0
- data/lib/protobuf/field/sfixed32_field.rb +27 -0
- data/lib/protobuf/field/sfixed64_field.rb +28 -0
- data/lib/protobuf/field/signed_integer_field.rb +29 -0
- data/lib/protobuf/field/sint32_field.rb +21 -0
- data/lib/protobuf/field/sint64_field.rb +21 -0
- data/lib/protobuf/field/string_field.rb +51 -0
- data/lib/protobuf/field/uint32_field.rb +21 -0
- data/lib/protobuf/field/uint64_field.rb +21 -0
- data/lib/protobuf/field/varint_field.rb +77 -0
- data/lib/protobuf/generators/base.rb +85 -0
- data/lib/protobuf/generators/enum_generator.rb +39 -0
- data/lib/protobuf/generators/extension_generator.rb +27 -0
- data/lib/protobuf/generators/field_generator.rb +193 -0
- data/lib/protobuf/generators/file_generator.rb +262 -0
- data/lib/protobuf/generators/group_generator.rb +122 -0
- data/lib/protobuf/generators/message_generator.rb +104 -0
- data/lib/protobuf/generators/option_generator.rb +17 -0
- data/lib/protobuf/generators/printable.rb +160 -0
- data/lib/protobuf/generators/service_generator.rb +50 -0
- data/lib/protobuf/lifecycle.rb +33 -0
- data/lib/protobuf/logging.rb +39 -0
- data/lib/protobuf/message.rb +260 -0
- data/lib/protobuf/message/fields.rb +233 -0
- data/lib/protobuf/message/serialization.rb +85 -0
- data/lib/protobuf/optionable.rb +70 -0
- data/lib/protobuf/rpc/buffer.rb +78 -0
- data/lib/protobuf/rpc/client.rb +140 -0
- data/lib/protobuf/rpc/connectors/base.rb +221 -0
- data/lib/protobuf/rpc/connectors/ping.rb +89 -0
- data/lib/protobuf/rpc/connectors/socket.rb +78 -0
- data/lib/protobuf/rpc/connectors/zmq.rb +319 -0
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +50 -0
- data/lib/protobuf/rpc/env.rb +60 -0
- data/lib/protobuf/rpc/error.rb +28 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/middleware.rb +25 -0
- data/lib/protobuf/rpc/middleware/exception_handler.rb +40 -0
- data/lib/protobuf/rpc/middleware/logger.rb +95 -0
- data/lib/protobuf/rpc/middleware/request_decoder.rb +79 -0
- data/lib/protobuf/rpc/middleware/response_encoder.rb +83 -0
- data/lib/protobuf/rpc/middleware/runner.rb +18 -0
- data/lib/protobuf/rpc/rpc.pb.rb +64 -0
- data/lib/protobuf/rpc/rpc_method.rb +16 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +121 -0
- data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
- data/lib/protobuf/rpc/servers/socket_runner.rb +46 -0
- data/lib/protobuf/rpc/servers/zmq/broker.rb +194 -0
- data/lib/protobuf/rpc/servers/zmq/server.rb +321 -0
- data/lib/protobuf/rpc/servers/zmq/util.rb +48 -0
- data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
- data/lib/protobuf/rpc/servers/zmq_runner.rb +70 -0
- data/lib/protobuf/rpc/service.rb +172 -0
- data/lib/protobuf/rpc/service_directory.rb +261 -0
- data/lib/protobuf/rpc/service_dispatcher.rb +45 -0
- data/lib/protobuf/rpc/service_filters.rb +250 -0
- data/lib/protobuf/rpc/stat.rb +119 -0
- data/lib/protobuf/socket.rb +21 -0
- data/lib/protobuf/tasks.rb +1 -0
- data/lib/protobuf/tasks/compile.rake +80 -0
- data/lib/protobuf/varint.rb +20 -0
- data/lib/protobuf/varint_pure.rb +31 -0
- data/lib/protobuf/version.rb +3 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf/zmq.rb +21 -0
- data/profile.html +5103 -0
- data/proto/dynamic_discovery.proto +44 -0
- data/proto/google/protobuf/compiler/plugin.proto +147 -0
- data/proto/google/protobuf/descriptor.proto +779 -0
- data/proto/rpc.proto +69 -0
- data/protobuf-cucumber.gemspec +57 -0
- data/spec/benchmark/tasks.rb +143 -0
- data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
- data/spec/encoding/all_types_spec.rb +103 -0
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/class_inheritance_spec.rb +52 -0
- data/spec/functional/code_generator_spec.rb +58 -0
- data/spec/functional/socket_server_spec.rb +59 -0
- data/spec/functional/zmq_server_spec.rb +105 -0
- data/spec/lib/protobuf/cli_spec.rb +317 -0
- data/spec/lib/protobuf/code_generator_spec.rb +87 -0
- data/spec/lib/protobuf/enum_spec.rb +307 -0
- data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
- data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/enum_field_spec.rb +44 -0
- data/spec/lib/protobuf/field/field_array_spec.rb +105 -0
- data/spec/lib/protobuf/field/field_hash_spec.rb +168 -0
- data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +120 -0
- data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
- data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +79 -0
- data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field_spec.rb +192 -0
- data/spec/lib/protobuf/generators/base_spec.rb +154 -0
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +82 -0
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +42 -0
- data/spec/lib/protobuf/generators/field_generator_spec.rb +197 -0
- data/spec/lib/protobuf/generators/file_generator_spec.rb +119 -0
- data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
- data/spec/lib/protobuf/generators/service_generator_spec.rb +99 -0
- data/spec/lib/protobuf/lifecycle_spec.rb +94 -0
- data/spec/lib/protobuf/message_spec.rb +944 -0
- data/spec/lib/protobuf/optionable_spec.rb +265 -0
- data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +226 -0
- data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +34 -0
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +110 -0
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +91 -0
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +43 -0
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +293 -0
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +517 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +162 -0
- data/spec/lib/protobuf/rpc/stat_spec.rb +101 -0
- data/spec/lib/protobuf/varint_spec.rb +29 -0
- data/spec/lib/protobuf_spec.rb +105 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/all.rb +6 -0
- data/spec/support/packed_field.rb +23 -0
- data/spec/support/protos/all_types.data.bin +0 -0
- data/spec/support/protos/all_types.data.txt +119 -0
- data/spec/support/protos/enum.pb.rb +63 -0
- data/spec/support/protos/enum.proto +37 -0
- data/spec/support/protos/extreme_values.data.bin +0 -0
- data/spec/support/protos/google_unittest.bin +0 -0
- data/spec/support/protos/google_unittest.pb.rb +798 -0
- data/spec/support/protos/google_unittest.proto +884 -0
- data/spec/support/protos/google_unittest_custom_options.bin +0 -0
- data/spec/support/protos/google_unittest_custom_options.pb.rb +361 -0
- data/spec/support/protos/google_unittest_custom_options.proto +424 -0
- data/spec/support/protos/google_unittest_import.pb.rb +55 -0
- data/spec/support/protos/google_unittest_import.proto +73 -0
- data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
- data/spec/support/protos/google_unittest_import_public.proto +41 -0
- data/spec/support/protos/map-test.bin +157 -0
- data/spec/support/protos/map-test.pb.rb +85 -0
- data/spec/support/protos/map-test.proto +68 -0
- data/spec/support/protos/multi_field_extensions.pb.rb +59 -0
- data/spec/support/protos/multi_field_extensions.proto +35 -0
- data/spec/support/protos/resource.pb.rb +172 -0
- data/spec/support/protos/resource.proto +137 -0
- data/spec/support/resource_service.rb +23 -0
- data/spec/support/server.rb +65 -0
- data/spec/support/test_app_file.rb +2 -0
- data/varint_prof.rb +82 -0
- metadata +579 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'protobuf/field/base_field'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Field
|
5
|
+
class VarintField < BaseField
|
6
|
+
|
7
|
+
##
|
8
|
+
# Constants
|
9
|
+
#
|
10
|
+
INT32_MAX = 2**31 - 1
|
11
|
+
INT32_MIN = -2**31
|
12
|
+
INT64_MAX = 2**63 - 1
|
13
|
+
INT64_MIN = -2**63
|
14
|
+
UINT32_MAX = 2**32 - 1
|
15
|
+
UINT64_MAX = 2**64 - 1
|
16
|
+
|
17
|
+
##
|
18
|
+
# Class Methods
|
19
|
+
#
|
20
|
+
|
21
|
+
def self.default
|
22
|
+
0
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.encode(value)
|
26
|
+
::Protobuf::Varint.encode(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Public Instance Methods
|
31
|
+
#
|
32
|
+
def acceptable?(val)
|
33
|
+
int_val = if val.is_a?(Integer)
|
34
|
+
return true if val >= 0 && val < INT32_MAX # return quickly for smallest integer size, hot code path
|
35
|
+
val
|
36
|
+
elsif val.is_a?(Numeric)
|
37
|
+
val.to_i
|
38
|
+
else
|
39
|
+
Integer(val, 10)
|
40
|
+
end
|
41
|
+
|
42
|
+
int_val >= self.class.min && int_val <= self.class.max
|
43
|
+
rescue
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def coerce!(val)
|
48
|
+
if val.is_a?(Integer) && val >= 0 && val <= INT32_MAX
|
49
|
+
val
|
50
|
+
else
|
51
|
+
fail TypeError, "Expected value of type '#{type_class}' for field #{name}, but got '#{val.class}'" unless acceptable?(val)
|
52
|
+
|
53
|
+
if val.is_a?(Integer) || val.is_a?(Numeric)
|
54
|
+
val.to_i
|
55
|
+
else
|
56
|
+
Integer(val, 10)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
rescue ArgumentError
|
60
|
+
fail TypeError, "Expected value of type '#{type_class}' for field #{name}, but got '#{val.class}'"
|
61
|
+
end
|
62
|
+
|
63
|
+
def decode(value)
|
64
|
+
value
|
65
|
+
end
|
66
|
+
|
67
|
+
def encode(value)
|
68
|
+
::Protobuf::Field::VarintField.encode(value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def wire_type
|
72
|
+
::Protobuf::WireType::VARINT
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'protobuf/generators/printable'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Generators
|
5
|
+
class Base
|
6
|
+
include ::Protobuf::Generators::Printable
|
7
|
+
|
8
|
+
def self.validate_tags(type_name, tags)
|
9
|
+
return if tags.empty?
|
10
|
+
|
11
|
+
unique_tags = tags.uniq
|
12
|
+
|
13
|
+
if unique_tags.size < tags.size
|
14
|
+
::Protobuf::CodeGenerator.fatal("#{type_name} object has duplicate tags. Expected #{unique_tags.size} tags, but got #{tags.size}. Suppress with PB_NO_TAG_WARNINGS=1.")
|
15
|
+
end
|
16
|
+
|
17
|
+
unless ENV.key?('PB_NO_TAG_WARNINGS')
|
18
|
+
expected_size = tags.max - tags.min + 1
|
19
|
+
if tags.size < expected_size
|
20
|
+
::Protobuf::CodeGenerator.print_tag_warning_suppress
|
21
|
+
::Protobuf::CodeGenerator.warn("#{type_name} object should have #{expected_size} tags (#{tags.min}..#{tags.max}), but found #{tags.size} tags.")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :descriptor, :namespace, :options
|
27
|
+
|
28
|
+
def initialize(descriptor, indent_level = 0, options = {})
|
29
|
+
@descriptor = descriptor
|
30
|
+
@options = options
|
31
|
+
@namespace = @options.fetch(:namespace) { [] }
|
32
|
+
init_printer(indent_level)
|
33
|
+
end
|
34
|
+
|
35
|
+
def fully_qualified_type_namespace
|
36
|
+
".#{type_namespace.join('.')}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_once(label)
|
40
|
+
tracker_ivar = "@_#{label}_compiled"
|
41
|
+
value_ivar = "@_#{label}_compiled_value"
|
42
|
+
|
43
|
+
if instance_variable_get(tracker_ivar)
|
44
|
+
return instance_variable_get(value_ivar)
|
45
|
+
end
|
46
|
+
|
47
|
+
return_value = yield
|
48
|
+
instance_variable_set(tracker_ivar, true)
|
49
|
+
instance_variable_set(value_ivar, return_value)
|
50
|
+
return_value
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
compile
|
55
|
+
print_contents # see Printable
|
56
|
+
end
|
57
|
+
|
58
|
+
def type_namespace
|
59
|
+
@type_namespace ||= @namespace + [descriptor.name]
|
60
|
+
end
|
61
|
+
|
62
|
+
def serialize_value(value)
|
63
|
+
case value
|
64
|
+
when Message
|
65
|
+
fields = value.each_field.map do |field, inner_value|
|
66
|
+
next unless value.field?(field.name)
|
67
|
+
serialized_inner_value = serialize_value(inner_value)
|
68
|
+
"#{field.fully_qualified_name.inspect} => #{serialized_inner_value}"
|
69
|
+
end.compact
|
70
|
+
"{ #{fields.join(', ')} }"
|
71
|
+
when Enum
|
72
|
+
"::#{value.parent_class}::#{value.name}"
|
73
|
+
when String
|
74
|
+
value.inspect
|
75
|
+
when nil
|
76
|
+
"nil"
|
77
|
+
when Array
|
78
|
+
'[' + value.map { |x| serialize_value(x) }.join(', ') + ']'
|
79
|
+
else
|
80
|
+
value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'protobuf/generators/base'
|
2
|
+
require 'protobuf/generators/option_generator'
|
3
|
+
|
4
|
+
module Protobuf
|
5
|
+
module Generators
|
6
|
+
class EnumGenerator < Base
|
7
|
+
|
8
|
+
def compile
|
9
|
+
run_once(:compile) do
|
10
|
+
tags = []
|
11
|
+
|
12
|
+
print_class(descriptor.name, :enum) do
|
13
|
+
if descriptor.options
|
14
|
+
print OptionGenerator.new(descriptor.options, current_indent).to_s
|
15
|
+
puts
|
16
|
+
end
|
17
|
+
|
18
|
+
descriptor.value.each do |enum_value_descriptor|
|
19
|
+
tags << enum_value_descriptor.number
|
20
|
+
puts build_value(enum_value_descriptor)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
unless descriptor.options.try(:allow_alias)
|
25
|
+
self.class.validate_tags(fully_qualified_type_namespace, tags)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_value(enum_value_descriptor)
|
31
|
+
name = enum_value_descriptor.name
|
32
|
+
name.upcase! if ENV.key?('PB_UPCASE_ENUMS')
|
33
|
+
number = enum_value_descriptor.number
|
34
|
+
"define :#{name}, #{number}"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'protobuf/generators/base'
|
2
|
+
require 'protobuf/generators/group_generator'
|
3
|
+
|
4
|
+
module Protobuf
|
5
|
+
module Generators
|
6
|
+
class ExtensionGenerator < Base
|
7
|
+
|
8
|
+
def initialize(message_type, field_descriptors, indent_level)
|
9
|
+
super(nil, indent_level)
|
10
|
+
@message_type = modulize(message_type)
|
11
|
+
@field_descriptors = field_descriptors
|
12
|
+
end
|
13
|
+
|
14
|
+
def compile
|
15
|
+
run_once(:compile) do
|
16
|
+
print_class(@message_type, :message) do
|
17
|
+
group = GroupGenerator.new(current_indent)
|
18
|
+
group.add_extension_fields(@field_descriptors)
|
19
|
+
group.order = [:extension_field]
|
20
|
+
print group.to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'protobuf/generators/base'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Generators
|
5
|
+
class FieldGenerator < Base
|
6
|
+
|
7
|
+
##
|
8
|
+
# Constants
|
9
|
+
#
|
10
|
+
PROTO_INFINITY_DEFAULT = /^inf$/i
|
11
|
+
PROTO_NEGATIVE_INFINITY_DEFAULT = /^-inf$/i
|
12
|
+
PROTO_NAN_DEFAULT = /^nan$/i
|
13
|
+
RUBY_INFINITY_DEFAULT = '::Float::INFINITY'.freeze
|
14
|
+
RUBY_NEGATIVE_INFINITY_DEFAULT = '-::Float::INFINITY'.freeze
|
15
|
+
RUBY_NAN_DEFAULT = '::Float::NAN'.freeze
|
16
|
+
|
17
|
+
##
|
18
|
+
# Attributes
|
19
|
+
#
|
20
|
+
attr_reader :field_options
|
21
|
+
|
22
|
+
def initialize(field_descriptor, enclosing_msg_descriptor, indent_level)
|
23
|
+
super(field_descriptor, indent_level)
|
24
|
+
@enclosing_msg_descriptor = enclosing_msg_descriptor
|
25
|
+
end
|
26
|
+
|
27
|
+
def applicable_options
|
28
|
+
# Note on the strange use of `#inspect`:
|
29
|
+
# :boom.inspect #=> ":boom"
|
30
|
+
# :".boom.foo".inspect #=> ":\".boom.foo\""
|
31
|
+
# An alternative to `#inspect` would be always adding double quotes,
|
32
|
+
# but the generatated code looks un-idiomatic:
|
33
|
+
# ":\"#{:boom}\"" #=> ":\"boom\"" <-- Note the unnecessary double quotes
|
34
|
+
@applicable_options ||= field_options.map { |k, v| "#{k.inspect} => #{v}" }
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_value
|
38
|
+
@default_value ||= begin
|
39
|
+
if defaulted?
|
40
|
+
case descriptor.type.name
|
41
|
+
when :TYPE_ENUM
|
42
|
+
enum_default_value
|
43
|
+
when :TYPE_STRING, :TYPE_BYTES
|
44
|
+
string_default_value
|
45
|
+
when :TYPE_FLOAT, :TYPE_DOUBLE
|
46
|
+
float_double_default_value
|
47
|
+
else
|
48
|
+
verbatim_default_value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def defaulted?
|
55
|
+
descriptor.respond_to_has_and_present?(:default_value)
|
56
|
+
end
|
57
|
+
|
58
|
+
def deprecated?
|
59
|
+
descriptor.options.try(:deprecated?) { false }
|
60
|
+
end
|
61
|
+
|
62
|
+
def extension?
|
63
|
+
descriptor.respond_to_has_and_present?(:extendee)
|
64
|
+
end
|
65
|
+
|
66
|
+
def compile
|
67
|
+
run_once(:compile) do
|
68
|
+
field_definition = if map?
|
69
|
+
["map #{map_key_type_name}", map_value_type_name, name, number, applicable_options]
|
70
|
+
else
|
71
|
+
["#{label} #{type_name}", name, number, applicable_options]
|
72
|
+
end
|
73
|
+
puts field_definition.flatten.compact.join(', ')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def label
|
78
|
+
@label ||= descriptor.label.name.to_s.downcase.sub(/label_/, '') # required, optional, repeated
|
79
|
+
end
|
80
|
+
|
81
|
+
def name
|
82
|
+
@name ||= descriptor.name.to_sym.inspect
|
83
|
+
end
|
84
|
+
|
85
|
+
def number
|
86
|
+
@number ||= descriptor.number
|
87
|
+
end
|
88
|
+
|
89
|
+
def field_options
|
90
|
+
@field_options ||= begin
|
91
|
+
opts = {}
|
92
|
+
opts[:default] = default_value if defaulted?
|
93
|
+
opts[:packed] = 'true' if packed?
|
94
|
+
opts[:deprecated] = 'true' if deprecated?
|
95
|
+
opts[:extension] = 'true' if extension?
|
96
|
+
if descriptor.options
|
97
|
+
descriptor.options.each_field do |field_option|
|
98
|
+
next unless descriptor.options.field?(field_option.name)
|
99
|
+
option_value = descriptor.options[field_option.name]
|
100
|
+
opts[field_option.fully_qualified_name] = serialize_value(option_value)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
opts
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def packed?
|
108
|
+
descriptor.options.try(:packed?) { false }
|
109
|
+
end
|
110
|
+
|
111
|
+
# Determine the field type
|
112
|
+
def type_name
|
113
|
+
@type_name ||= determine_type_name(descriptor)
|
114
|
+
end
|
115
|
+
|
116
|
+
# If this field is a map field, this returns a message descriptor that
|
117
|
+
# represents the entries in the map. Returns nil if this field is not
|
118
|
+
# a map field.
|
119
|
+
def map_entry
|
120
|
+
@map_entry ||= determine_map_entry
|
121
|
+
end
|
122
|
+
|
123
|
+
def map?
|
124
|
+
!map_entry.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
def map_key_type_name
|
128
|
+
return nil if map_entry.nil?
|
129
|
+
determine_type_name(map_entry.field.find { |v| v.name == 'key' && v.number == 1 })
|
130
|
+
end
|
131
|
+
|
132
|
+
def map_value_type_name
|
133
|
+
return nil if map_entry.nil?
|
134
|
+
determine_type_name(map_entry.field.find { |v| v.name == 'value' && v.number == 2 })
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def enum_default_value
|
140
|
+
optionally_upcased_default =
|
141
|
+
if ENV.key?('PB_UPCASE_ENUMS')
|
142
|
+
verbatim_default_value.upcase
|
143
|
+
else
|
144
|
+
verbatim_default_value
|
145
|
+
end
|
146
|
+
"#{type_name}::#{optionally_upcased_default}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def float_double_default_value
|
150
|
+
case verbatim_default_value
|
151
|
+
when PROTO_INFINITY_DEFAULT then
|
152
|
+
RUBY_INFINITY_DEFAULT
|
153
|
+
when PROTO_NEGATIVE_INFINITY_DEFAULT then
|
154
|
+
RUBY_NEGATIVE_INFINITY_DEFAULT
|
155
|
+
when PROTO_NAN_DEFAULT then
|
156
|
+
RUBY_NAN_DEFAULT
|
157
|
+
else
|
158
|
+
verbatim_default_value
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def string_default_value
|
163
|
+
%("#{verbatim_default_value.gsub(/'/, '\\\\\'')}")
|
164
|
+
end
|
165
|
+
|
166
|
+
def verbatim_default_value
|
167
|
+
descriptor.default_value
|
168
|
+
end
|
169
|
+
|
170
|
+
def determine_type_name(descriptor)
|
171
|
+
case descriptor.type.name
|
172
|
+
when :TYPE_MESSAGE, :TYPE_ENUM, :TYPE_GROUP then
|
173
|
+
modulize(descriptor.type_name)
|
174
|
+
else
|
175
|
+
type_name = descriptor.type.name.to_s.downcase.sub(/^type_/, '')
|
176
|
+
":#{type_name}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def determine_map_entry
|
181
|
+
return nil if @enclosing_msg_descriptor.nil?
|
182
|
+
return nil unless descriptor.label.name == :LABEL_REPEATED && descriptor.type.name == :TYPE_MESSAGE
|
183
|
+
# find nested message type
|
184
|
+
name_parts = descriptor.type_name.split(".")
|
185
|
+
return nil if name_parts.size < 2 || name_parts[-2] != @enclosing_msg_descriptor.name
|
186
|
+
nested = @enclosing_msg_descriptor.nested_type.find { |e| e.name == name_parts[-1] }
|
187
|
+
return nested if !nested.nil? && nested.options.try(:map_entry?)
|
188
|
+
nil
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'protobuf/generators/base'
|
3
|
+
require 'protobuf/generators/group_generator'
|
4
|
+
|
5
|
+
module Protobuf
|
6
|
+
module Generators
|
7
|
+
class FileGenerator < Base
|
8
|
+
|
9
|
+
attr_reader :output_file
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
@output_file = ::Google::Protobuf::Compiler::CodeGeneratorResponse::File.new(:name => file_name)
|
14
|
+
@extension_fields = Hash.new { |h, k| h[k] = [] }
|
15
|
+
@known_messages = {}
|
16
|
+
@known_enums = {}
|
17
|
+
@dangling_messages = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def file_name
|
21
|
+
convert_filename(descriptor.name, false)
|
22
|
+
end
|
23
|
+
|
24
|
+
def compile
|
25
|
+
run_once(:compile) do
|
26
|
+
map_extensions(descriptor, [descriptor.package])
|
27
|
+
|
28
|
+
print_file_comment
|
29
|
+
print_generic_requires
|
30
|
+
print_import_requires
|
31
|
+
|
32
|
+
print_package do
|
33
|
+
inject_optionable
|
34
|
+
group = GroupGenerator.new(current_indent)
|
35
|
+
group.add_options(descriptor.options) if descriptor.options
|
36
|
+
group.add_enums(descriptor.enum_type, :namespace => [descriptor.package])
|
37
|
+
group.add_message_declarations(descriptor.message_type)
|
38
|
+
group.add_messages(descriptor.message_type, :extension_fields => @extension_fields, :namespace => [descriptor.package])
|
39
|
+
group.add_extended_messages(unknown_extensions)
|
40
|
+
group.add_services(descriptor.service)
|
41
|
+
|
42
|
+
group.add_header(:enum, 'Enum Classes')
|
43
|
+
group.add_header(:message_declaration, 'Message Classes')
|
44
|
+
group.add_header(:options, 'File Options')
|
45
|
+
group.add_header(:message, 'Message Fields')
|
46
|
+
group.add_header(:extended_message, 'Extended Message Fields')
|
47
|
+
group.add_header(:service, 'Service Classes')
|
48
|
+
print group.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def unknown_extensions
|
55
|
+
@unknown_extensions ||= @extension_fields.map do |message_name, fields|
|
56
|
+
message_klass = modulize(message_name).safe_constantize
|
57
|
+
if message_klass
|
58
|
+
unknown_fields = fields.reject do |field|
|
59
|
+
@known_messages[message_name] && message_klass.get_field(field.name, true)
|
60
|
+
end
|
61
|
+
[message_name, unknown_fields]
|
62
|
+
else
|
63
|
+
[message_name, fields]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def generate_output_file
|
69
|
+
compile
|
70
|
+
output_file.content = to_s
|
71
|
+
output_file
|
72
|
+
end
|
73
|
+
|
74
|
+
# Recursively map out all extensions known in this file.
|
75
|
+
# The key is the type_name of the message being extended, and
|
76
|
+
# the value is an array of field descriptors.
|
77
|
+
#
|
78
|
+
def map_extensions(descriptor, namespaces)
|
79
|
+
if fully_qualified_token?(descriptor.name)
|
80
|
+
fully_qualified_namespace = descriptor.name
|
81
|
+
elsif !(namespace = namespaces.reject(&:empty?).join(".")).empty?
|
82
|
+
fully_qualified_namespace = ".#{namespace}"
|
83
|
+
end
|
84
|
+
# Record all the message descriptor name's we encounter (should be the whole tree).
|
85
|
+
if descriptor.is_a?(::Google::Protobuf::DescriptorProto)
|
86
|
+
@known_messages[fully_qualified_namespace || descriptor.name] = descriptor
|
87
|
+
elsif descriptor.is_a?(::Google::Protobuf::EnumDescriptorProto)
|
88
|
+
@known_enums[fully_qualified_namespace || descriptor.name] = descriptor
|
89
|
+
return
|
90
|
+
end
|
91
|
+
|
92
|
+
descriptor.extension.each do |field_descriptor|
|
93
|
+
unless fully_qualified_token?(field_descriptor.name) && fully_qualified_namespace
|
94
|
+
field_descriptor.name = "#{fully_qualified_namespace}.#{field_descriptor.name}"
|
95
|
+
end
|
96
|
+
@extension_fields[field_descriptor.extendee] << field_descriptor
|
97
|
+
end
|
98
|
+
|
99
|
+
[:message_type, :nested_type, :enum_type].each do |type|
|
100
|
+
next unless descriptor.respond_to_has_and_present?(type)
|
101
|
+
|
102
|
+
descriptor.public_send(type).each do |type_descriptor|
|
103
|
+
map_extensions(type_descriptor, (namespaces + [type_descriptor.name]))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def print_file_comment
|
109
|
+
puts "# encoding: utf-8"
|
110
|
+
puts
|
111
|
+
puts "##"
|
112
|
+
puts "# This file is auto-generated. DO NOT EDIT!"
|
113
|
+
puts "#"
|
114
|
+
end
|
115
|
+
|
116
|
+
def print_generic_requires
|
117
|
+
print_require("protobuf")
|
118
|
+
print_require("protobuf/rpc/service") if descriptor.service.count > 0
|
119
|
+
puts
|
120
|
+
end
|
121
|
+
|
122
|
+
def print_import_requires
|
123
|
+
return if descriptor.dependency.empty?
|
124
|
+
|
125
|
+
header "Imports"
|
126
|
+
|
127
|
+
descriptor.dependency.each do |dependency|
|
128
|
+
print_require(convert_filename(dependency), ENV.key?('PB_REQUIRE_RELATIVE'))
|
129
|
+
end
|
130
|
+
|
131
|
+
puts
|
132
|
+
end
|
133
|
+
|
134
|
+
def print_package(&block)
|
135
|
+
namespaces = descriptor.package.split('.')
|
136
|
+
if namespaces.empty? && ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')
|
137
|
+
namespaces = [File.basename(descriptor.name).sub('.proto', '')]
|
138
|
+
end
|
139
|
+
namespaces.reverse.reduce(block) do |previous, namespace|
|
140
|
+
-> { print_module(namespace, &previous) }
|
141
|
+
end.call
|
142
|
+
end
|
143
|
+
|
144
|
+
def eval_unknown_extensions!
|
145
|
+
@@evaled_dependencies ||= Set.new # rubocop:disable Style/ClassVars
|
146
|
+
@@all_messages ||= {} # rubocop:disable Style/ClassVars
|
147
|
+
@@all_enums ||= {} # rubocop:disable Style/ClassVars
|
148
|
+
|
149
|
+
map_extensions(descriptor, [descriptor.package])
|
150
|
+
@known_messages.each do |name, descriptor|
|
151
|
+
@@all_messages[name] = descriptor
|
152
|
+
end
|
153
|
+
@known_enums.each do |name, descriptor|
|
154
|
+
@@all_enums[name] = descriptor
|
155
|
+
end
|
156
|
+
|
157
|
+
# create package namespace
|
158
|
+
print_package {}
|
159
|
+
eval_code
|
160
|
+
|
161
|
+
unknown_extensions.each do |extendee, fields|
|
162
|
+
eval_dependencies(extendee)
|
163
|
+
fields.each do |field|
|
164
|
+
eval_dependencies(field.type_name)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
group = GroupGenerator.new(0)
|
168
|
+
group.add_extended_messages(unknown_extensions, false)
|
169
|
+
print group.to_s
|
170
|
+
eval_code
|
171
|
+
rescue => e
|
172
|
+
warn "Error loading unknown extensions #{descriptor.name.inspect} error=#{e}"
|
173
|
+
raise e
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def convert_filename(filename, for_require = true)
|
179
|
+
filename.sub(/\.proto/, (for_require ? '.pb' : '.pb.rb'))
|
180
|
+
end
|
181
|
+
|
182
|
+
def fully_qualified_token?(token)
|
183
|
+
token[0] == '.'
|
184
|
+
end
|
185
|
+
|
186
|
+
def eval_dependencies(name, namespace = nil)
|
187
|
+
name = "#{namespace}.#{name}" if namespace && !fully_qualified_token?(name)
|
188
|
+
return if name.empty? || @@evaled_dependencies.include?(name) || modulize(name).safe_constantize
|
189
|
+
|
190
|
+
# if name = .foo.bar.Baz look for classes / modules named ::Foo::Bar and ::Foo
|
191
|
+
# module == pure namespace (e.g. the descriptor package name)
|
192
|
+
# class == nested messages
|
193
|
+
create_ruby_namespace_heiarchy(name)
|
194
|
+
|
195
|
+
if (message = @@all_messages[name])
|
196
|
+
# Create the blank namespace in case there are nested types
|
197
|
+
eval_message_code(name)
|
198
|
+
|
199
|
+
message.nested_type.each do |nested_type|
|
200
|
+
eval_dependencies(nested_type.name, name) unless nested_type.name.empty?
|
201
|
+
end
|
202
|
+
message.field.each do |field|
|
203
|
+
eval_dependencies(field.type_name, name) unless field.type_name.empty?
|
204
|
+
end
|
205
|
+
message.enum_type.each do |enum_type|
|
206
|
+
eval_dependencies(enum_type.name, name)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Check @@evaled_dependencies again in case there was a dependency
|
210
|
+
# loop that already loaded this message
|
211
|
+
return if @@evaled_dependencies.include?(name)
|
212
|
+
eval_message_code(name, message.field)
|
213
|
+
@@evaled_dependencies << name
|
214
|
+
|
215
|
+
elsif (enum = @@all_enums[name])
|
216
|
+
# Check @@evaled_dependencies again in case there was a dependency
|
217
|
+
# loop that already loaded this enum
|
218
|
+
return if @@evaled_dependencies.include?(name)
|
219
|
+
namespace = name.split(".")
|
220
|
+
eval_enum_code(enum, namespace[0..-2].join("."))
|
221
|
+
@@evaled_dependencies << name
|
222
|
+
else
|
223
|
+
fail "Error loading unknown dependencies, could not find message or enum #{name.inspect}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def eval_message_code(fully_qualified_namespace, fields = [])
|
228
|
+
group = GroupGenerator.new(0)
|
229
|
+
group.add_extended_messages({ fully_qualified_namespace => fields }, false)
|
230
|
+
print group.to_s
|
231
|
+
eval_code
|
232
|
+
end
|
233
|
+
|
234
|
+
def eval_enum_code(enum, fully_qualified_namespace)
|
235
|
+
group = GroupGenerator.new(0)
|
236
|
+
group.add_enums([enum], :namespace => [fully_qualified_namespace])
|
237
|
+
print group.to_s
|
238
|
+
eval_code(modulize(fully_qualified_namespace).safe_constantize || Object)
|
239
|
+
end
|
240
|
+
|
241
|
+
def eval_code(context = Object)
|
242
|
+
warn "#{context.inspect}.module_eval #{print_contents.inspect}" if ENV['PB_DEBUG']
|
243
|
+
context.module_eval print_contents.to_s
|
244
|
+
@io.truncate(0)
|
245
|
+
@io.rewind
|
246
|
+
end
|
247
|
+
|
248
|
+
def create_ruby_namespace_heiarchy(namespace)
|
249
|
+
loop do
|
250
|
+
namespace, _match, _tail = namespace.rpartition(".")
|
251
|
+
break if namespace.empty?
|
252
|
+
eval_dependencies(namespace)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def inject_optionable
|
257
|
+
return if descriptor.package.empty? && !ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')
|
258
|
+
puts "::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|