protobuffy 3.6.0 → 4.0.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.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +67 -0
  4. data/.rubocop_todo.yml +145 -0
  5. data/.travis.yml +25 -5
  6. data/CHANGES.md +55 -0
  7. data/CONTRIBUTING.md +1 -1
  8. data/LICENSE.txt +17 -9
  9. data/README.md +13 -12
  10. data/Rakefile +15 -11
  11. data/bin/protoc-gen-ruby +8 -3
  12. data/bin/rpc_server +1 -0
  13. data/examples/lib/example/reverse-client.rb +2 -2
  14. data/install-protobuf.sh +28 -0
  15. data/lib/protobuf.rb +57 -53
  16. data/lib/protobuf/cli.rb +94 -74
  17. data/lib/protobuf/code_generator.rb +60 -9
  18. data/lib/protobuf/decoder.rb +19 -65
  19. data/lib/protobuf/deprecation.rb +117 -0
  20. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +11 -1
  21. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +55 -3
  22. data/lib/protobuf/encoder.rb +13 -53
  23. data/lib/protobuf/enum.rb +58 -63
  24. data/lib/protobuf/field.rb +4 -4
  25. data/lib/protobuf/field/base_field.rb +101 -173
  26. data/lib/protobuf/field/bool_field.rb +17 -11
  27. data/lib/protobuf/field/bytes_field.rb +21 -35
  28. data/lib/protobuf/field/double_field.rb +0 -1
  29. data/lib/protobuf/field/enum_field.rb +23 -22
  30. data/lib/protobuf/field/field_array.rb +5 -4
  31. data/lib/protobuf/field/fixed32_field.rb +1 -1
  32. data/lib/protobuf/field/fixed64_field.rb +0 -1
  33. data/lib/protobuf/field/float_field.rb +4 -1
  34. data/lib/protobuf/field/int32_field.rb +0 -1
  35. data/lib/protobuf/field/int64_field.rb +0 -1
  36. data/lib/protobuf/field/integer_field.rb +0 -1
  37. data/lib/protobuf/field/message_field.rb +13 -28
  38. data/lib/protobuf/field/sfixed32_field.rb +0 -1
  39. data/lib/protobuf/field/sfixed64_field.rb +0 -1
  40. data/lib/protobuf/field/signed_integer_field.rb +0 -1
  41. data/lib/protobuf/field/sint32_field.rb +0 -1
  42. data/lib/protobuf/field/sint64_field.rb +0 -1
  43. data/lib/protobuf/field/string_field.rb +2 -4
  44. data/lib/protobuf/field/uint32_field.rb +0 -1
  45. data/lib/protobuf/field/uint64_field.rb +0 -1
  46. data/lib/protobuf/field/varint_field.rb +30 -13
  47. data/lib/protobuf/generators/base.rb +30 -16
  48. data/lib/protobuf/generators/enum_generator.rb +6 -9
  49. data/lib/protobuf/generators/extension_generator.rb +1 -2
  50. data/lib/protobuf/generators/field_generator.rb +25 -13
  51. data/lib/protobuf/generators/file_generator.rb +157 -35
  52. data/lib/protobuf/generators/group_generator.rb +22 -17
  53. data/lib/protobuf/generators/message_generator.rb +13 -14
  54. data/lib/protobuf/generators/option_generator.rb +17 -0
  55. data/lib/protobuf/generators/printable.rb +12 -13
  56. data/lib/protobuf/generators/service_generator.rb +2 -3
  57. data/lib/protobuf/http.rb +2 -2
  58. data/lib/protobuf/lifecycle.rb +20 -33
  59. data/lib/protobuf/logging.rb +39 -0
  60. data/lib/protobuf/message.rb +114 -47
  61. data/lib/protobuf/message/fields.rb +170 -88
  62. data/lib/protobuf/message/serialization.rb +19 -18
  63. data/lib/protobuf/optionable.rb +53 -6
  64. data/lib/protobuf/rpc/buffer.rb +18 -19
  65. data/lib/protobuf/rpc/client.rb +22 -50
  66. data/lib/protobuf/rpc/connectors/base.rb +177 -12
  67. data/lib/protobuf/rpc/connectors/http.rb +14 -9
  68. data/lib/protobuf/rpc/connectors/ping.rb +89 -0
  69. data/lib/protobuf/rpc/connectors/socket.rb +13 -8
  70. data/lib/protobuf/rpc/connectors/zmq.rb +178 -73
  71. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +4 -1
  72. data/lib/protobuf/rpc/env.rb +12 -12
  73. data/lib/protobuf/rpc/error.rb +3 -3
  74. data/lib/protobuf/rpc/error/client_error.rb +4 -4
  75. data/lib/protobuf/rpc/error/server_error.rb +9 -9
  76. data/lib/protobuf/rpc/middleware/exception_handler.rb +6 -2
  77. data/lib/protobuf/rpc/middleware/logger.rb +8 -4
  78. data/lib/protobuf/rpc/middleware/request_decoder.rb +17 -21
  79. data/lib/protobuf/rpc/middleware/response_encoder.rb +22 -27
  80. data/lib/protobuf/rpc/middleware/statsd.rb +3 -3
  81. data/lib/protobuf/rpc/rpc.pb.rb +4 -1
  82. data/lib/protobuf/rpc/server.rb +1 -1
  83. data/lib/protobuf/rpc/servers/http/server.rb +19 -17
  84. data/lib/protobuf/rpc/servers/socket/server.rb +78 -70
  85. data/lib/protobuf/rpc/servers/socket/worker.rb +4 -4
  86. data/lib/protobuf/rpc/servers/socket_runner.rb +27 -15
  87. data/lib/protobuf/rpc/servers/zmq/broker.rb +70 -31
  88. data/lib/protobuf/rpc/servers/zmq/server.rb +55 -47
  89. data/lib/protobuf/rpc/servers/zmq/util.rb +14 -13
  90. data/lib/protobuf/rpc/servers/zmq/worker.rb +16 -16
  91. data/lib/protobuf/rpc/servers/zmq_runner.rb +26 -7
  92. data/lib/protobuf/rpc/service.rb +21 -27
  93. data/lib/protobuf/rpc/service_directory.rb +43 -27
  94. data/lib/protobuf/rpc/service_dispatcher.rb +9 -10
  95. data/lib/protobuf/rpc/service_filters.rb +32 -55
  96. data/lib/protobuf/rpc/stat.rb +4 -8
  97. data/lib/protobuf/socket.rb +1 -2
  98. data/lib/protobuf/tasks/compile.rake +3 -4
  99. data/lib/protobuf/varint.rb +9 -0
  100. data/lib/protobuf/varint_pure.rb +13 -0
  101. data/lib/protobuf/version.rb +1 -1
  102. data/lib/protobuf/zmq.rb +2 -2
  103. data/proto/google/protobuf/descriptor.proto +190 -31
  104. data/protobuffy.gemspec +30 -17
  105. data/spec/benchmark/tasks.rb +27 -19
  106. data/spec/bin/protoc-gen-ruby_spec.rb +11 -6
  107. data/spec/encoding/all_types_spec.rb +96 -84
  108. data/spec/encoding/extreme_values_spec.rb +0 -0
  109. data/spec/functional/class_inheritance_spec.rb +52 -0
  110. data/spec/functional/code_generator_spec.rb +38 -0
  111. data/spec/functional/socket_server_spec.rb +15 -15
  112. data/spec/functional/zmq_server_spec.rb +29 -27
  113. data/spec/lib/protobuf/cli_spec.rb +82 -67
  114. data/spec/lib/protobuf/code_generator_spec.rb +37 -10
  115. data/spec/lib/protobuf/enum_spec.rb +77 -46
  116. data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
  117. data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
  118. data/spec/lib/protobuf/field/enum_field_spec.rb +26 -0
  119. data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
  120. data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
  121. data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
  122. data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
  123. data/spec/lib/protobuf/field/int32_field_spec.rb +114 -1
  124. data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
  125. data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
  126. data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
  127. data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
  128. data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
  129. data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
  130. data/spec/lib/protobuf/field/string_field_spec.rb +44 -11
  131. data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
  132. data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
  133. data/spec/lib/protobuf/field_spec.rb +4 -6
  134. data/spec/lib/protobuf/generators/base_spec.rb +80 -13
  135. data/spec/lib/protobuf/generators/enum_generator_spec.rb +35 -21
  136. data/spec/lib/protobuf/generators/extension_generator_spec.rb +12 -13
  137. data/spec/lib/protobuf/generators/field_generator_spec.rb +73 -21
  138. data/spec/lib/protobuf/generators/file_generator_spec.rb +89 -6
  139. data/spec/lib/protobuf/generators/service_generator_spec.rb +25 -13
  140. data/spec/lib/protobuf/lifecycle_spec.rb +25 -20
  141. data/spec/lib/protobuf/message_spec.rb +578 -79
  142. data/spec/lib/protobuf/optionable_spec.rb +202 -26
  143. data/spec/lib/protobuf/rpc/client_spec.rb +16 -16
  144. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +167 -13
  145. data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +4 -5
  146. data/spec/lib/protobuf/rpc/connectors/http_spec.rb +13 -11
  147. data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
  148. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +6 -7
  149. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +35 -52
  150. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +10 -10
  151. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +11 -11
  152. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +23 -23
  153. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +11 -11
  154. data/spec/lib/protobuf/rpc/middleware/statsd_spec.rb +6 -6
  155. data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +47 -44
  156. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +6 -6
  157. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +12 -10
  158. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +11 -11
  159. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +7 -7
  160. data/spec/lib/protobuf/rpc/service_directory_spec.rb +47 -49
  161. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +8 -25
  162. data/spec/lib/protobuf/rpc/service_filters_spec.rb +102 -69
  163. data/spec/lib/protobuf/rpc/service_spec.rb +37 -36
  164. data/spec/lib/protobuf/rpc/stat_spec.rb +7 -9
  165. data/spec/lib/protobuf/varint_spec.rb +29 -0
  166. data/spec/lib/protobuf_spec.rb +55 -28
  167. data/spec/spec_helper.rb +12 -27
  168. data/spec/support/all.rb +0 -1
  169. data/spec/support/packed_field.rb +4 -3
  170. data/spec/support/{test → protos}/all_types.data.bin +0 -0
  171. data/spec/support/{test → protos}/all_types.data.txt +0 -0
  172. data/spec/support/{test → protos}/enum.pb.rb +8 -4
  173. data/spec/support/{test → protos}/enum.proto +4 -1
  174. data/spec/support/{test → protos}/extreme_values.data.bin +0 -0
  175. data/spec/support/protos/google_unittest.bin +0 -0
  176. data/spec/support/protos/google_unittest.pb.rb +798 -0
  177. data/spec/support/{test → protos}/google_unittest.proto +237 -66
  178. data/spec/support/protos/google_unittest_custom_options.bin +0 -0
  179. data/spec/support/protos/google_unittest_custom_options.pb.rb +268 -0
  180. data/spec/support/protos/google_unittest_custom_options.proto +424 -0
  181. data/spec/support/protos/google_unittest_import.pb.rb +55 -0
  182. data/spec/support/{test → protos}/google_unittest_import.proto +19 -10
  183. data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
  184. data/spec/support/{test → protos}/google_unittest_import_public.proto +8 -5
  185. data/spec/support/{test → protos}/multi_field_extensions.pb.rb +5 -2
  186. data/spec/support/{test → protos}/multi_field_extensions.proto +2 -0
  187. data/spec/support/{test → protos}/resource.pb.rb +47 -11
  188. data/spec/support/{test → protos}/resource.proto +24 -1
  189. data/spec/support/resource_service.rb +23 -0
  190. data/spec/support/server.rb +32 -61
  191. metadata +119 -59
  192. data/lib/protobuf/deprecator.rb +0 -42
  193. data/lib/protobuf/logger.rb +0 -93
  194. data/lib/protobuf/rpc/connector.rb +0 -21
  195. data/lib/protobuf/rpc/connectors/common.rb +0 -172
  196. data/spec/data/data.bin +0 -3
  197. data/spec/data/types.bin +0 -0
  198. data/spec/lib/protobuf/logger_spec.rb +0 -145
  199. data/spec/lib/protobuf/rpc/connector_spec.rb +0 -26
  200. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +0 -170
  201. data/spec/support/test/defaults.pb.rb +0 -25
  202. data/spec/support/test/defaults.proto +0 -9
  203. data/spec/support/test/extended.pb.rb +0 -22
  204. data/spec/support/test/extended.proto +0 -10
  205. data/spec/support/test/google_unittest.pb.rb +0 -543
  206. data/spec/support/test/google_unittest_import.pb.rb +0 -37
  207. data/spec/support/test/google_unittest_import_public.pb.rb +0 -8
  208. data/spec/support/test/resource_service.rb +0 -26
  209. data/spec/support/tolerance_matcher.rb +0 -40
@@ -19,4 +19,3 @@ module Protobuf
19
19
  end
20
20
  end
21
21
  end
22
-
@@ -8,6 +8,7 @@ module Protobuf
8
8
  # Constants
9
9
  #
10
10
 
11
+ CACHE_LIMIT = 2048
11
12
  INT32_MAX = 2**31 - 1
12
13
  INT32_MIN = -2**31
13
14
  INT64_MAX = 2**63 - 1
@@ -23,7 +24,16 @@ module Protobuf
23
24
  0
24
25
  end
25
26
 
26
- def self.encode(value)
27
+ # Because all tags and enums are calculated as VarInt it is "most common" to have
28
+ # values < CACHE_LIMIT (low numbers) which is defaulting to 1024
29
+ def self.cached_varint(value)
30
+ @_varint_cache ||= {}
31
+ (@_varint_cache[value] ||= encode(value, false)).dup
32
+ end
33
+
34
+ def self.encode(value, use_cache = true)
35
+ return cached_varint(value) if use_cache && value >= 0 && value <= CACHE_LIMIT
36
+
27
37
  bytes = []
28
38
  until value < 128
29
39
  bytes << (0x80 | (value & 0x7f))
@@ -32,30 +42,38 @@ module Protobuf
32
42
  (bytes << value).pack('C*')
33
43
  end
34
44
 
45
+ # Load the cache of VarInts on load of file
46
+ (0..CACHE_LIMIT).each do |cached_value|
47
+ cached_varint(cached_value)
48
+ end
49
+
35
50
  ##
36
51
  # Public Instance Methods
37
52
  #
38
-
39
53
  def acceptable?(val)
40
- (val > self.class.min || val < self.class.max)
54
+ int_val = if val.is_a?(Integer)
55
+ return true if val >= 0 && val < INT32_MAX # return quickly for smallest integer size, hot code path
56
+ val
57
+ else
58
+ coerce!(val)
59
+ end
60
+
61
+ int_val >= self.class.min && int_val <= self.class.max
41
62
  rescue
42
63
  false
43
64
  end
44
65
 
66
+ def coerce!(val)
67
+ return val.to_i if val.is_a?(Numeric)
68
+ Integer(val, 10)
69
+ end
70
+
45
71
  def decode(value)
46
72
  value
47
73
  end
48
74
 
49
75
  def encode(value)
50
- return [value].pack('C') if value < 128
51
-
52
- bytes = []
53
- until value == 0
54
- bytes << (0x80 | (value & 0x7f))
55
- value >>= 7
56
- end
57
- bytes[-1] &= 0x7f
58
- bytes.pack('C*')
76
+ ::Protobuf::Field::VarintField.encode(value)
59
77
  end
60
78
 
61
79
  def wire_type
@@ -65,4 +83,3 @@ module Protobuf
65
83
  end
66
84
  end
67
85
  end
68
-
@@ -15,16 +15,10 @@ module Protobuf
15
15
  end
16
16
 
17
17
  unless ENV.key?('PB_NO_TAG_WARNINGS')
18
- range = (tags.min)..(tags.max)
19
- if range.respond_to?(:size)
20
- expected_size = range.size
21
- else
22
- expected_size = range.to_a.size
23
- end
24
-
18
+ expected_size = tags.max - tags.min + 1
25
19
  if tags.size < expected_size
26
20
  ::Protobuf::CodeGenerator.print_tag_warning_suppress
27
- ::Protobuf::CodeGenerator.warn("#{type_name} object should have #{expected_size} tags (#{range.begin}..#{range.end}), but found #{tags.size} tags.")
21
+ ::Protobuf::CodeGenerator.warn("#{type_name} object should have #{expected_size} tags (#{tags.min}..#{tags.max}), but found #{tags.size} tags.")
28
22
  end
29
23
  end
30
24
  end
@@ -42,18 +36,18 @@ module Protobuf
42
36
  ".#{type_namespace.join('.')}"
43
37
  end
44
38
 
45
- def run_once(label, &block)
39
+ def run_once(label)
46
40
  tracker_ivar = "@_#{label}_compiled"
47
41
  value_ivar = "@_#{label}_compiled_value"
48
42
 
49
43
  if instance_variable_get(tracker_ivar)
50
44
  return instance_variable_get(value_ivar)
51
- else
52
- return_value = block.call
53
- instance_variable_set(tracker_ivar, true)
54
- instance_variable_set(value_ivar, return_value)
55
- return return_value
56
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
57
51
  end
58
52
 
59
53
  def to_s
@@ -62,10 +56,30 @@ module Protobuf
62
56
  end
63
57
 
64
58
  def type_namespace
65
- @type_namespace ||= @namespace + [ descriptor.name ]
59
+ @type_namespace ||= @namespace + [descriptor.name]
66
60
  end
67
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
68
83
  end
69
84
  end
70
85
  end
71
-
@@ -1,20 +1,17 @@
1
1
  require 'protobuf/generators/base'
2
+ require 'protobuf/generators/option_generator'
2
3
 
3
4
  module Protobuf
4
5
  module Generators
5
6
  class EnumGenerator < Base
6
7
 
7
- def allow_alias?
8
- descriptor.options.try(:allow_alias!) { false }
9
- end
10
-
11
8
  def compile
12
9
  run_once(:compile) do
13
10
  tags = []
14
11
 
15
12
  print_class(descriptor.name, :enum) do
16
- if allow_alias?
17
- puts "set_option :allow_alias"
13
+ if descriptor.options
14
+ print OptionGenerator.new(descriptor.options, current_indent).to_s
18
15
  puts
19
16
  end
20
17
 
@@ -24,7 +21,7 @@ module Protobuf
24
21
  end
25
22
  end
26
23
 
27
- unless allow_alias?
24
+ unless descriptor.options.try(:allow_alias)
28
25
  self.class.validate_tags(fully_qualified_type_namespace, tags)
29
26
  end
30
27
  end
@@ -32,11 +29,11 @@ module Protobuf
32
29
 
33
30
  def build_value(enum_value_descriptor)
34
31
  name = enum_value_descriptor.name
32
+ name.upcase! if ENV.key?('PB_UPCASE_ENUMS')
35
33
  number = enum_value_descriptor.number
36
- return "define :#{name}, #{number}"
34
+ "define :#{name}, #{number}"
37
35
  end
38
36
 
39
37
  end
40
38
  end
41
39
  end
42
-
@@ -16,7 +16,7 @@ module Protobuf
16
16
  print_class(@message_type, :message) do
17
17
  group = GroupGenerator.new(current_indent)
18
18
  group.add_extension_fields(@field_descriptors)
19
- group.order = [ :extension_field ]
19
+ group.order = [:extension_field]
20
20
  print group.to_s
21
21
  end
22
22
  end
@@ -25,4 +25,3 @@ module Protobuf
25
25
  end
26
26
  end
27
27
  end
28
-
@@ -7,9 +7,9 @@ module Protobuf
7
7
  ##
8
8
  # Constants
9
9
  #
10
- PROTO_INFINITY_DEFAULT = /^inf$/i.freeze
11
- PROTO_NEGATIVE_INFINITY_DEFAULT = /^-inf$/i.freeze
12
- PROTO_NAN_DEFAULT = /^nan$/i.freeze
10
+ PROTO_INFINITY_DEFAULT = /^inf$/i
11
+ PROTO_NEGATIVE_INFINITY_DEFAULT = /^-inf$/i
12
+ PROTO_NAN_DEFAULT = /^nan$/i
13
13
  RUBY_INFINITY_DEFAULT = '::Float::INFINITY'.freeze
14
14
  RUBY_NEGATIVE_INFINITY_DEFAULT = '-::Float::INFINITY'.freeze
15
15
  RUBY_NAN_DEFAULT = '::Float::NAN'.freeze
@@ -20,18 +20,24 @@ module Protobuf
20
20
  attr_reader :field_options
21
21
 
22
22
  def applicable_options
23
- @applicable_options ||= field_options.map { |k, v| ":#{k} => #{v}" }
23
+ # Note on the strange use of `#inspect`:
24
+ # :boom.inspect #=> ":boom"
25
+ # :".boom.foo".inspect #=> ":\".boom.foo\""
26
+ # An alternative to `#inspect` would be always adding double quotes,
27
+ # but the generatated code looks un-idiomatic:
28
+ # ":\"#{:boom}\"" #=> ":\"boom\"" <-- Note the unnecessary double quotes
29
+ @applicable_options ||= field_options.map { |k, v| "#{k.inspect} => #{v}" }
24
30
  end
25
31
 
26
32
  def default_value
27
33
  @default_value ||= begin
28
34
  if defaulted?
29
35
  case descriptor.type.name
30
- when :TYPE_ENUM then
36
+ when :TYPE_ENUM
31
37
  enum_default_value
32
- when :TYPE_STRING, :TYPE_BYTES then
38
+ when :TYPE_STRING, :TYPE_BYTES
33
39
  string_default_value
34
- when :TYPE_FLOAT, :TYPE_DOUBLE then
40
+ when :TYPE_FLOAT, :TYPE_DOUBLE
35
41
  float_double_default_value
36
42
  else
37
43
  verbatim_default_value
@@ -54,7 +60,7 @@ module Protobuf
54
60
 
55
61
  def compile
56
62
  run_once(:compile) do
57
- field_definition = [ "#{label} #{type_name}", name, number, applicable_options ]
63
+ field_definition = ["#{label} #{type_name}", name, number, applicable_options]
58
64
  puts field_definition.flatten.compact.join(', ')
59
65
  end
60
66
  end
@@ -64,7 +70,7 @@ module Protobuf
64
70
  end
65
71
 
66
72
  def name
67
- @name ||= ":#{descriptor.name}"
73
+ @name ||= descriptor.name.to_sym.inspect
68
74
  end
69
75
 
70
76
  def number
@@ -78,6 +84,13 @@ module Protobuf
78
84
  opts[:packed] = 'true' if packed?
79
85
  opts[:deprecated] = 'true' if deprecated?
80
86
  opts[:extension] = 'true' if extension?
87
+ if descriptor.options
88
+ descriptor.options.each_field do |field_option|
89
+ next unless descriptor.options.field?(field_option.name)
90
+ option_value = descriptor.options[field_option.name]
91
+ opts[field_option.fully_qualified_name] = serialize_value(option_value)
92
+ end
93
+ end
81
94
  opts
82
95
  end
83
96
  end
@@ -91,10 +104,10 @@ module Protobuf
91
104
  @type_name ||= begin
92
105
  case descriptor.type.name
93
106
  when :TYPE_MESSAGE, :TYPE_ENUM, :TYPE_GROUP then
94
- type_name = modulize(descriptor.type_name)
107
+ modulize(descriptor.type_name)
95
108
  else
96
109
  type_name = descriptor.type.name.to_s.downcase.sub(/type_/, '')
97
- type_name = ":#{type_name}"
110
+ ":#{type_name}"
98
111
  end
99
112
  end
100
113
  end
@@ -119,7 +132,7 @@ module Protobuf
119
132
  end
120
133
 
121
134
  def string_default_value
122
- %Q{"#{verbatim_default_value.gsub(/'/, '\\\\\'')}"}
135
+ %("#{verbatim_default_value.gsub(/'/, '\\\\\'')}")
123
136
  end
124
137
 
125
138
  def verbatim_default_value
@@ -129,4 +142,3 @@ module Protobuf
129
142
  end
130
143
  end
131
144
  end
132
-
@@ -12,7 +12,8 @@ module Protobuf
12
12
  super
13
13
  @output_file = ::Google::Protobuf::Compiler::CodeGeneratorResponse::File.new(:name => file_name)
14
14
  @extension_fields = Hash.new { |h, k| h[k] = [] }
15
- @known_messages = []
15
+ @known_messages = {}
16
+ @known_enums = {}
16
17
  @dangling_messages = {}
17
18
  end
18
19
 
@@ -22,23 +23,25 @@ module Protobuf
22
23
 
23
24
  def compile
24
25
  run_once(:compile) do
25
- map_extensions(descriptor, [ descriptor.package ])
26
- extract_dangling_extensions
26
+ map_extensions(descriptor, [descriptor.package])
27
27
 
28
28
  print_file_comment
29
29
  print_generic_requires
30
30
  print_import_requires
31
31
 
32
32
  print_package do
33
+ inject_optionable
33
34
  group = GroupGenerator.new(current_indent)
34
- group.add_enums(descriptor.enum_type, :namespace => [ descriptor.package ])
35
+ group.add_options(descriptor.options) if descriptor.options
36
+ group.add_enums(descriptor.enum_type, :namespace => [descriptor.package])
35
37
  group.add_message_declarations(descriptor.message_type)
36
- group.add_messages(descriptor.message_type, :extension_fields => @extension_fields, :namespace => [ descriptor.package ])
37
- group.add_extended_messages(@unknown_extensions)
38
+ group.add_messages(descriptor.message_type, :extension_fields => @extension_fields, :namespace => [descriptor.package])
39
+ group.add_extended_messages(unknown_extensions)
38
40
  group.add_services(descriptor.service)
39
41
 
40
42
  group.add_header(:enum, 'Enum Classes')
41
43
  group.add_header(:message_declaration, 'Message Classes')
44
+ group.add_header(:options, 'File Options')
42
45
  group.add_header(:message, 'Message Fields')
43
46
  group.add_header(:extended_message, 'Extended Message Fields')
44
47
  group.add_header(:service, 'Service Classes')
@@ -48,9 +51,17 @@ module Protobuf
48
51
  end
49
52
  end
50
53
 
51
- def extract_dangling_extensions
52
- @unknown_extensions = @extension_fields.select do |k, v|
53
- ! @known_messages.include?(k)
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
54
65
  end
55
66
  end
56
67
 
@@ -65,63 +76,101 @@ module Protobuf
65
76
  # the value is an array of field descriptors.
66
77
  #
67
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
68
84
  # Record all the message descriptor name's we encounter (should be the whole tree).
69
85
  if descriptor.is_a?(::Google::Protobuf::DescriptorProto)
70
- if fully_qualified_token?(descriptor.name)
71
- @known_messages << descriptor.name
72
- else
73
- fully_qualified_namespace = ".#{namespaces.join('.')}"
74
- @known_messages << fully_qualified_namespace
75
- end
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
76
90
  end
77
91
 
78
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
79
96
  @extension_fields[field_descriptor.extendee] << field_descriptor
80
97
  end
81
98
 
82
- if descriptor.respond_to_has_and_present?(:message_type)
83
- descriptor.message_type.each do |message_descriptor|
84
- map_extensions(message_descriptor, (namespaces + [ message_descriptor.name ]))
85
- end
86
- end
99
+ [:message_type, :nested_type, :enum_type].each do |type|
100
+ next unless descriptor.respond_to_has_and_present?(type)
87
101
 
88
- if descriptor.respond_to_has_and_present?(:nested_type)
89
- descriptor.nested_type.each do |nested_descriptor|
90
- map_extensions(nested_descriptor, (namespaces + [ nested_descriptor.name ]))
102
+ descriptor.public_send(type).each do |type_descriptor|
103
+ map_extensions(type_descriptor, (namespaces + [type_descriptor.name]))
91
104
  end
92
105
  end
93
106
  end
94
107
 
95
108
  def print_file_comment
109
+ puts "# encoding: utf-8"
110
+ puts
96
111
  puts "##"
97
112
  puts "# This file is auto-generated. DO NOT EDIT!"
98
113
  puts "#"
99
114
  end
100
115
 
101
116
  def print_generic_requires
102
- print_require("protobuf/message")
117
+ print_require("protobuf")
103
118
  print_require("protobuf/rpc/service") if descriptor.service.count > 0
104
119
  puts
105
120
  end
106
121
 
107
122
  def print_import_requires
108
- if descriptor.dependency.count > 0
109
- header "Imports"
123
+ return if descriptor.dependency.empty?
110
124
 
111
- descriptor.dependency.each do |dependency|
112
- print_require(convert_filename(dependency))
113
- end
125
+ header "Imports"
114
126
 
115
- puts
127
+ descriptor.dependency.each do |dependency|
128
+ print_require(convert_filename(dependency))
116
129
  end
130
+
131
+ puts
117
132
  end
118
133
 
119
134
  def print_package(&block)
120
- final = lambda { block.call }
121
135
  namespaces = descriptor.package.split('.')
122
- namespaces.reverse.inject(final) { |previous, namespace|
123
- lambda { print_module(namespace, &previous) }
124
- }.call
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
125
174
  end
126
175
 
127
176
  private
@@ -134,7 +183,80 @@ module Protobuf
134
183
  token[0] == '.'
135
184
  end
136
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
137
260
  end
138
261
  end
139
262
  end
140
-