protobuf-cucumber 3.10.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rubocop.yml +70 -0
  4. data/.rubocop_todo.yml +145 -0
  5. data/.travis.yml +40 -0
  6. data/.yardopts +5 -0
  7. data/CHANGES.md +344 -0
  8. data/CONTRIBUTING.md +16 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +33 -0
  12. data/Rakefile +64 -0
  13. data/bin/protoc-gen-ruby +22 -0
  14. data/bin/rpc_server +5 -0
  15. data/install-protobuf.sh +28 -0
  16. data/lib/protobuf.rb +129 -0
  17. data/lib/protobuf/cli.rb +257 -0
  18. data/lib/protobuf/code_generator.rb +120 -0
  19. data/lib/protobuf/decoder.rb +28 -0
  20. data/lib/protobuf/deprecation.rb +117 -0
  21. data/lib/protobuf/descriptors.rb +3 -0
  22. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +62 -0
  23. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +301 -0
  24. data/lib/protobuf/encoder.rb +11 -0
  25. data/lib/protobuf/enum.rb +365 -0
  26. data/lib/protobuf/exceptions.rb +9 -0
  27. data/lib/protobuf/field.rb +74 -0
  28. data/lib/protobuf/field/base_field.rb +380 -0
  29. data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
  30. data/lib/protobuf/field/bool_field.rb +64 -0
  31. data/lib/protobuf/field/bytes_field.rb +78 -0
  32. data/lib/protobuf/field/double_field.rb +25 -0
  33. data/lib/protobuf/field/enum_field.rb +61 -0
  34. data/lib/protobuf/field/field_array.rb +104 -0
  35. data/lib/protobuf/field/field_hash.rb +122 -0
  36. data/lib/protobuf/field/fixed32_field.rb +25 -0
  37. data/lib/protobuf/field/fixed64_field.rb +28 -0
  38. data/lib/protobuf/field/float_field.rb +43 -0
  39. data/lib/protobuf/field/int32_field.rb +21 -0
  40. data/lib/protobuf/field/int64_field.rb +34 -0
  41. data/lib/protobuf/field/integer_field.rb +23 -0
  42. data/lib/protobuf/field/message_field.rb +51 -0
  43. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  44. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  45. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  46. data/lib/protobuf/field/sint32_field.rb +21 -0
  47. data/lib/protobuf/field/sint64_field.rb +21 -0
  48. data/lib/protobuf/field/string_field.rb +51 -0
  49. data/lib/protobuf/field/uint32_field.rb +21 -0
  50. data/lib/protobuf/field/uint64_field.rb +21 -0
  51. data/lib/protobuf/field/varint_field.rb +77 -0
  52. data/lib/protobuf/generators/base.rb +85 -0
  53. data/lib/protobuf/generators/enum_generator.rb +39 -0
  54. data/lib/protobuf/generators/extension_generator.rb +27 -0
  55. data/lib/protobuf/generators/field_generator.rb +193 -0
  56. data/lib/protobuf/generators/file_generator.rb +262 -0
  57. data/lib/protobuf/generators/group_generator.rb +122 -0
  58. data/lib/protobuf/generators/message_generator.rb +104 -0
  59. data/lib/protobuf/generators/option_generator.rb +17 -0
  60. data/lib/protobuf/generators/printable.rb +160 -0
  61. data/lib/protobuf/generators/service_generator.rb +50 -0
  62. data/lib/protobuf/lifecycle.rb +33 -0
  63. data/lib/protobuf/logging.rb +39 -0
  64. data/lib/protobuf/message.rb +260 -0
  65. data/lib/protobuf/message/fields.rb +233 -0
  66. data/lib/protobuf/message/serialization.rb +85 -0
  67. data/lib/protobuf/optionable.rb +70 -0
  68. data/lib/protobuf/rpc/buffer.rb +78 -0
  69. data/lib/protobuf/rpc/client.rb +140 -0
  70. data/lib/protobuf/rpc/connectors/base.rb +221 -0
  71. data/lib/protobuf/rpc/connectors/ping.rb +89 -0
  72. data/lib/protobuf/rpc/connectors/socket.rb +78 -0
  73. data/lib/protobuf/rpc/connectors/zmq.rb +319 -0
  74. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +50 -0
  75. data/lib/protobuf/rpc/env.rb +60 -0
  76. data/lib/protobuf/rpc/error.rb +28 -0
  77. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  78. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  79. data/lib/protobuf/rpc/middleware.rb +25 -0
  80. data/lib/protobuf/rpc/middleware/exception_handler.rb +40 -0
  81. data/lib/protobuf/rpc/middleware/logger.rb +95 -0
  82. data/lib/protobuf/rpc/middleware/request_decoder.rb +79 -0
  83. data/lib/protobuf/rpc/middleware/response_encoder.rb +83 -0
  84. data/lib/protobuf/rpc/middleware/runner.rb +18 -0
  85. data/lib/protobuf/rpc/rpc.pb.rb +64 -0
  86. data/lib/protobuf/rpc/rpc_method.rb +16 -0
  87. data/lib/protobuf/rpc/server.rb +39 -0
  88. data/lib/protobuf/rpc/servers/socket/server.rb +121 -0
  89. data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
  90. data/lib/protobuf/rpc/servers/socket_runner.rb +46 -0
  91. data/lib/protobuf/rpc/servers/zmq/broker.rb +194 -0
  92. data/lib/protobuf/rpc/servers/zmq/server.rb +321 -0
  93. data/lib/protobuf/rpc/servers/zmq/util.rb +48 -0
  94. data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
  95. data/lib/protobuf/rpc/servers/zmq_runner.rb +70 -0
  96. data/lib/protobuf/rpc/service.rb +172 -0
  97. data/lib/protobuf/rpc/service_directory.rb +261 -0
  98. data/lib/protobuf/rpc/service_dispatcher.rb +45 -0
  99. data/lib/protobuf/rpc/service_filters.rb +250 -0
  100. data/lib/protobuf/rpc/stat.rb +119 -0
  101. data/lib/protobuf/socket.rb +21 -0
  102. data/lib/protobuf/tasks.rb +1 -0
  103. data/lib/protobuf/tasks/compile.rake +80 -0
  104. data/lib/protobuf/varint.rb +20 -0
  105. data/lib/protobuf/varint_pure.rb +31 -0
  106. data/lib/protobuf/version.rb +3 -0
  107. data/lib/protobuf/wire_type.rb +10 -0
  108. data/lib/protobuf/zmq.rb +21 -0
  109. data/profile.html +5103 -0
  110. data/proto/dynamic_discovery.proto +44 -0
  111. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  112. data/proto/google/protobuf/descriptor.proto +779 -0
  113. data/proto/rpc.proto +69 -0
  114. data/protobuf-cucumber.gemspec +57 -0
  115. data/spec/benchmark/tasks.rb +143 -0
  116. data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
  117. data/spec/encoding/all_types_spec.rb +103 -0
  118. data/spec/encoding/extreme_values_spec.rb +0 -0
  119. data/spec/functional/class_inheritance_spec.rb +52 -0
  120. data/spec/functional/code_generator_spec.rb +58 -0
  121. data/spec/functional/socket_server_spec.rb +59 -0
  122. data/spec/functional/zmq_server_spec.rb +105 -0
  123. data/spec/lib/protobuf/cli_spec.rb +317 -0
  124. data/spec/lib/protobuf/code_generator_spec.rb +87 -0
  125. data/spec/lib/protobuf/enum_spec.rb +307 -0
  126. data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
  127. data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
  128. data/spec/lib/protobuf/field/enum_field_spec.rb +44 -0
  129. data/spec/lib/protobuf/field/field_array_spec.rb +105 -0
  130. data/spec/lib/protobuf/field/field_hash_spec.rb +168 -0
  131. data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
  132. data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
  133. data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
  134. data/spec/lib/protobuf/field/int32_field_spec.rb +120 -0
  135. data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
  136. data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
  137. data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
  138. data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
  139. data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
  140. data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
  141. data/spec/lib/protobuf/field/string_field_spec.rb +79 -0
  142. data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
  143. data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
  144. data/spec/lib/protobuf/field_spec.rb +192 -0
  145. data/spec/lib/protobuf/generators/base_spec.rb +154 -0
  146. data/spec/lib/protobuf/generators/enum_generator_spec.rb +82 -0
  147. data/spec/lib/protobuf/generators/extension_generator_spec.rb +42 -0
  148. data/spec/lib/protobuf/generators/field_generator_spec.rb +197 -0
  149. data/spec/lib/protobuf/generators/file_generator_spec.rb +119 -0
  150. data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
  151. data/spec/lib/protobuf/generators/service_generator_spec.rb +99 -0
  152. data/spec/lib/protobuf/lifecycle_spec.rb +94 -0
  153. data/spec/lib/protobuf/message_spec.rb +944 -0
  154. data/spec/lib/protobuf/optionable_spec.rb +265 -0
  155. data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
  156. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +226 -0
  157. data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
  158. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +34 -0
  159. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +110 -0
  160. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
  161. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
  162. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
  163. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +91 -0
  164. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
  165. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +43 -0
  166. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
  167. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
  168. data/spec/lib/protobuf/rpc/service_directory_spec.rb +293 -0
  169. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +35 -0
  170. data/spec/lib/protobuf/rpc/service_filters_spec.rb +517 -0
  171. data/spec/lib/protobuf/rpc/service_spec.rb +162 -0
  172. data/spec/lib/protobuf/rpc/stat_spec.rb +101 -0
  173. data/spec/lib/protobuf/varint_spec.rb +29 -0
  174. data/spec/lib/protobuf_spec.rb +105 -0
  175. data/spec/spec_helper.rb +42 -0
  176. data/spec/support/all.rb +6 -0
  177. data/spec/support/packed_field.rb +23 -0
  178. data/spec/support/protos/all_types.data.bin +0 -0
  179. data/spec/support/protos/all_types.data.txt +119 -0
  180. data/spec/support/protos/enum.pb.rb +63 -0
  181. data/spec/support/protos/enum.proto +37 -0
  182. data/spec/support/protos/extreme_values.data.bin +0 -0
  183. data/spec/support/protos/google_unittest.bin +0 -0
  184. data/spec/support/protos/google_unittest.pb.rb +798 -0
  185. data/spec/support/protos/google_unittest.proto +884 -0
  186. data/spec/support/protos/google_unittest_custom_options.bin +0 -0
  187. data/spec/support/protos/google_unittest_custom_options.pb.rb +361 -0
  188. data/spec/support/protos/google_unittest_custom_options.proto +424 -0
  189. data/spec/support/protos/google_unittest_import.pb.rb +55 -0
  190. data/spec/support/protos/google_unittest_import.proto +73 -0
  191. data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
  192. data/spec/support/protos/google_unittest_import_public.proto +41 -0
  193. data/spec/support/protos/map-test.bin +157 -0
  194. data/spec/support/protos/map-test.pb.rb +85 -0
  195. data/spec/support/protos/map-test.proto +68 -0
  196. data/spec/support/protos/multi_field_extensions.pb.rb +59 -0
  197. data/spec/support/protos/multi_field_extensions.proto +35 -0
  198. data/spec/support/protos/resource.pb.rb +172 -0
  199. data/spec/support/protos/resource.proto +137 -0
  200. data/spec/support/resource_service.rb +23 -0
  201. data/spec/support/server.rb +65 -0
  202. data/spec/support/test_app_file.rb +2 -0
  203. data/varint_prof.rb +82 -0
  204. metadata +579 -0
@@ -0,0 +1,33 @@
1
+ module Protobuf
2
+ class Lifecycle
3
+ class << self
4
+ def register(event_name)
5
+ fail "Lifecycle register must have a block" unless block_given?
6
+ event_name = normalized_event_name(event_name)
7
+
8
+ ::ActiveSupport::Notifications.subscribe(event_name) do |_name, _start, _finish, _id, args|
9
+ yield(*args)
10
+ end
11
+ end
12
+ alias :on register
13
+
14
+ def trigger(event_name, *args)
15
+ event_name = normalized_event_name(event_name)
16
+
17
+ ::ActiveSupport::Notifications.instrument(event_name, args)
18
+ end
19
+
20
+ replacement = ::ActiveSupport::Notifications
21
+
22
+ ::Protobuf.deprecator.deprecate_methods(
23
+ self,
24
+ :register => "#{replacement}.#{replacement.method(:subscribe).name}".to_sym,
25
+ :trigger => "#{replacement}.#{replacement.method(:instrument).name}".to_sym,
26
+ )
27
+
28
+ def normalized_event_name(event_name)
29
+ event_name.to_s.downcase
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ require 'logger'
2
+
3
+ module Protobuf
4
+ module Logging
5
+ def self.initialize_logger(log_target = $stdout, log_level = ::Logger::INFO)
6
+ @logger = Logger.new(log_target)
7
+ @logger.level = log_level
8
+ @logger
9
+ end
10
+
11
+ def self.logger
12
+ defined?(@logger) ? @logger : initialize_logger
13
+ end
14
+
15
+ class << self
16
+ attr_writer :logger
17
+ end
18
+
19
+ def logger
20
+ ::Protobuf::Logging.logger
21
+ end
22
+
23
+ def log_exception(ex)
24
+ logger.error { ex.message }
25
+ logger.error { ex.backtrace[0..5].join("\n") }
26
+ logger.debug { ex.backtrace.join("\n") }
27
+ end
28
+
29
+ def log_signature
30
+ @_log_signature ||= "[#{self.class == Class ? name : self.class.name}]"
31
+ end
32
+
33
+ def sign_message(message)
34
+ "#{log_signature} #{message}"
35
+ end
36
+ end
37
+ end
38
+
39
+ # Inspired by [mperham](https://github.com/mperham/sidekiq)
@@ -0,0 +1,260 @@
1
+ require 'protobuf/message/fields'
2
+ require 'protobuf/message/serialization'
3
+ require 'protobuf/varint'
4
+
5
+ module Protobuf
6
+ class Message
7
+
8
+ ##
9
+ # Includes & Extends
10
+ #
11
+
12
+ extend ::Protobuf::Message::Fields
13
+ include ::Protobuf::Message::Serialization
14
+ ::Protobuf::Optionable.inject(self) { ::Google::Protobuf::MessageOptions }
15
+
16
+ ##
17
+ # Class Methods
18
+ #
19
+
20
+ def self.to_json
21
+ name
22
+ end
23
+
24
+ def self.from_json(json)
25
+ fields = normalize_json(JSON.parse(json))
26
+ new(fields)
27
+ end
28
+
29
+ def self.normalize_json(ob)
30
+ case ob
31
+ when Array
32
+ ob.map { |value| normalize_json(value) }
33
+ when Hash
34
+ Hash[*ob.flat_map { |key, value| [key.underscore, normalize_json(value)] }]
35
+ else
36
+ ob
37
+ end
38
+ end
39
+
40
+ ##
41
+ # Constructor
42
+ #
43
+
44
+ def initialize(fields = {})
45
+ @values = {}
46
+ fields.to_hash.each do |name, value|
47
+ set_field(name, value, true)
48
+ end
49
+
50
+ yield self if block_given?
51
+ end
52
+
53
+ ##
54
+ # Public Instance Methods
55
+ #
56
+
57
+ def clear!
58
+ @values.delete_if do |_, value|
59
+ if value.is_a?(::Protobuf::Field::FieldArray) || value.is_a?(::Protobuf::Field::FieldHash)
60
+ value.clear
61
+ false
62
+ else
63
+ true
64
+ end
65
+ end
66
+ self
67
+ end
68
+
69
+ def clone
70
+ copy_to(super, :clone)
71
+ end
72
+
73
+ def dup
74
+ copy_to(super, :dup)
75
+ end
76
+
77
+ # Iterate over every field, invoking the given block
78
+ #
79
+ def each_field
80
+ return to_enum(:each_field) unless block_given?
81
+
82
+ self.class.all_fields.each do |field|
83
+ value = self[field.name]
84
+ yield(field, value)
85
+ end
86
+ end
87
+
88
+ def each_field_for_serialization
89
+ _protobuf_message_unset_required_field_tags.each do |tag|
90
+ fail ::Protobuf::SerializationError, "Required field #{self.class.name}##{_protobuf_message_field[tag].name} does not have a value."
91
+ end
92
+
93
+ @values.each_key do |fully_qualified_name|
94
+ field = _protobuf_message_field[fully_qualified_name]
95
+ yield(field, field.value_from_values_for_serialization(@values))
96
+ end
97
+ end
98
+
99
+ def field?(name)
100
+ field = _protobuf_message_field[name]
101
+
102
+ if field
103
+ field.field?(@values)
104
+ else
105
+ false
106
+ end
107
+ end
108
+ alias :respond_to_has? field?
109
+ ::Protobuf.deprecator.define_deprecated_methods(self, :has_field? => :field?)
110
+
111
+ def inspect
112
+ attrs = self.class.fields.map do |field|
113
+ [field.name, self[field.name].inspect].join('=')
114
+ end.join(' ')
115
+
116
+ "#<#{self.class} #{attrs}>"
117
+ end
118
+
119
+ def respond_to_has_and_present?(key)
120
+ field = _protobuf_message_field[key]
121
+
122
+ if field
123
+ field.field_and_present?(@values)
124
+ else
125
+ false
126
+ end
127
+ end
128
+
129
+ # Return a hash-representation of the given fields for this message type.
130
+ def to_hash
131
+ result = {}
132
+
133
+ @values.each_key do |field_name|
134
+ field = _protobuf_message_field[field_name]
135
+ field.to_message_hash(@values, result)
136
+ end
137
+
138
+ result
139
+ end
140
+
141
+ def to_hash_with_string_keys
142
+ result = {}
143
+
144
+ @values.each_key do |field_name|
145
+ field = _protobuf_message_field[field_name]
146
+ field.to_message_hash_with_string_key(@values, result)
147
+ end
148
+
149
+ result
150
+ end
151
+
152
+ def to_json(options = {})
153
+ to_json_hash(options).to_json(options)
154
+ end
155
+
156
+ # Return a hash-representation of the given fields for this message type that
157
+ # is safe to convert to JSON.
158
+ def to_json_hash(options = {})
159
+ result = {}
160
+
161
+ lower_camel_case = options[:lower_camel_case]
162
+
163
+ @values.each_key do |field_name|
164
+ value = self[field_name]
165
+ field = self.class.get_field(field_name, true)
166
+
167
+ # NB: to_json_hash_value should come before json_encode so as to handle
168
+ # repeated fields without extra logic.
169
+ hashed_value = if value.respond_to?(:to_json_hash_value) && !field.is_a?(::Protobuf::Field::EnumField)
170
+ value.to_json_hash_value(options)
171
+ elsif field.respond_to?(:json_encode)
172
+ field.json_encode(value)
173
+ else
174
+ value
175
+ end
176
+
177
+ key = lower_camel_case ? field.name.to_s.camelize(:lower).to_sym : field.name
178
+ result[key] = hashed_value
179
+ end
180
+
181
+ result
182
+ end
183
+
184
+ def to_proto
185
+ self
186
+ end
187
+
188
+ def ==(other)
189
+ return false unless other.is_a?(self.class)
190
+ each_field do |field, value|
191
+ return false unless value == other[field.name]
192
+ end
193
+ true
194
+ end
195
+
196
+ def [](name)
197
+ field = _protobuf_message_field[name]
198
+ field.value_from_values(@values)
199
+ rescue # not having a field should be the exceptional state
200
+ raise if field
201
+ fail ArgumentError, "invalid field name=#{name.inspect}"
202
+ end
203
+
204
+ def []=(name, value)
205
+ set_field(name, value, true)
206
+ end
207
+
208
+ def set_field(name, value, ignore_nil_for_repeated, field = nil)
209
+ field ||= _protobuf_message_field[name]
210
+
211
+ if field
212
+ field.set_field(@values, value, ignore_nil_for_repeated, self)
213
+ else
214
+ fail(::Protobuf::FieldNotDefinedError, name) unless ::Protobuf.ignore_unknown_fields?
215
+ end
216
+ end
217
+
218
+ ##
219
+ # Instance Aliases
220
+ #
221
+ alias :to_hash_value to_hash
222
+ alias :to_json_hash_value to_json_hash
223
+ alias :to_proto_hash to_hash
224
+ alias :responds_to_has? respond_to_has?
225
+ alias :respond_to_and_has? respond_to_has?
226
+ alias :responds_to_and_has? respond_to_has?
227
+ alias :respond_to_has_present? respond_to_has_and_present?
228
+ alias :respond_to_and_has_present? respond_to_has_and_present?
229
+ alias :respond_to_and_has_and_present? respond_to_has_and_present?
230
+ alias :responds_to_has_present? respond_to_has_and_present?
231
+ alias :responds_to_and_has_present? respond_to_has_and_present?
232
+ alias :responds_to_and_has_and_present? respond_to_has_and_present?
233
+
234
+ ##
235
+ # Private Instance Methods
236
+ #
237
+
238
+ private
239
+
240
+ def copy_to(object, method)
241
+ duplicate = proc do |obj|
242
+ case obj
243
+ when Message, String then obj.__send__(method)
244
+ else obj
245
+ end
246
+ end
247
+
248
+ object.__send__(:initialize)
249
+ @values.each do |name, value|
250
+ if value.is_a?(::Protobuf::Field::FieldArray)
251
+ object[name].replace(value.map { |v| duplicate.call(v) })
252
+ else
253
+ object[name] = duplicate.call(value)
254
+ end
255
+ end
256
+ object
257
+ end
258
+
259
+ end
260
+ end
@@ -0,0 +1,233 @@
1
+ require "set"
2
+
3
+ module Protobuf
4
+ class Message
5
+ module Fields
6
+
7
+ ACCESSOR_SUFFIXES = ["", "=", "!", "?"].freeze
8
+
9
+ def self.extended(other)
10
+ other.extend(ClassMethods)
11
+ ::Protobuf.deprecator.define_deprecated_methods(
12
+ other.singleton_class,
13
+ :get_ext_field_by_name => :get_extension_field,
14
+ :get_ext_field_by_tag => :get_extension_field,
15
+ :get_field_by_name => :get_field,
16
+ :get_field_by_tag => :get_field,
17
+ )
18
+ end
19
+
20
+ module ClassMethods
21
+ def inherited(subclass)
22
+ inherit_fields!(subclass)
23
+ subclass.const_set("PROTOBUF_MESSAGE_REQUIRED_FIELD_TAGS", subclass.required_field_tags)
24
+ subclass.const_set("PROTOBUF_MESSAGE_GET_FIELD", subclass.field_store)
25
+ subclass.class_eval <<-RUBY, __FILE__, __LINE__
26
+ def _protobuf_message_field
27
+ PROTOBUF_MESSAGE_GET_FIELD
28
+ end
29
+
30
+ def _protobuf_message_unset_required_field_tags
31
+ @_protobuf_message_unset_required_field_tags ||= PROTOBUF_MESSAGE_REQUIRED_FIELD_TAGS.dup
32
+ end
33
+ RUBY
34
+ end
35
+
36
+ ##
37
+ # Field Definition Methods
38
+ #
39
+
40
+ # Define an optional field.
41
+ #
42
+ def optional(type_class, name, tag, options = {})
43
+ define_field(:optional, type_class, name, tag, options)
44
+ end
45
+
46
+ # Define a repeated field.
47
+ #
48
+ def repeated(type_class, name, tag, options = {})
49
+ define_field(:repeated, type_class, name, tag, options)
50
+ end
51
+
52
+ # Define a required field.
53
+ #
54
+ def required(type_class, name, tag, options = {})
55
+ required_field_tags << tag
56
+ define_field(:required, type_class, name, tag, options)
57
+ end
58
+
59
+ # Define a map field.
60
+ #
61
+ def map(key_type_class, value_type_class, name, tag, options = {})
62
+ # manufacture a message that represents the map entry, used for
63
+ # serialization and deserialization
64
+ entry_type = Class.new(::Protobuf::Message) do
65
+ set_option :map_entry, true
66
+ optional key_type_class, :key, 1
67
+ optional value_type_class, :value, 2
68
+ end
69
+ define_field(:repeated, entry_type, name, tag, options)
70
+ end
71
+
72
+ # Define an extension range.
73
+ #
74
+ def extensions(range)
75
+ extension_ranges << range
76
+ end
77
+
78
+ ##
79
+ # Field Access Methods
80
+ #
81
+ def all_fields
82
+ @all_fields ||= field_store.values.uniq.sort_by(&:tag)
83
+ end
84
+
85
+ def extension_fields
86
+ @extension_fields ||= all_fields.select(&:extension?)
87
+ end
88
+
89
+ def extension_ranges
90
+ @extension_ranges ||= []
91
+ end
92
+
93
+ def required_field_tags
94
+ @required_field_tags ||= []
95
+ end
96
+
97
+ def extension_tag?(tag)
98
+ tag.respond_to?(:to_i) && get_extension_field(tag).present?
99
+ end
100
+
101
+ def field_store
102
+ @field_store ||= {}
103
+ end
104
+
105
+ def fields
106
+ @fields ||= all_fields.reject(&:extension?)
107
+ end
108
+
109
+ def field_tag?(tag, allow_extension = false)
110
+ tag.respond_to?(:to_i) && get_field(tag, allow_extension).present?
111
+ end
112
+
113
+ def get_extension_field(name_or_tag)
114
+ field = field_store[name_or_tag]
115
+ field if field.try(:extension?) { false }
116
+ end
117
+
118
+ def get_field(name_or_tag, allow_extension = false)
119
+ field = field_store[name_or_tag]
120
+
121
+ if field && (allow_extension || !field.extension?)
122
+ field
123
+ else
124
+ nil
125
+ end
126
+ end
127
+
128
+ def define_field(rule, type_class, fully_qualified_field_name, tag, options)
129
+ raise_if_tag_collision(tag, fully_qualified_field_name)
130
+ raise_if_name_collision(fully_qualified_field_name)
131
+
132
+ # Determine appropirate accessor for fields depending on name collisions via extensions:
133
+
134
+ # Case 1: Base field = "string_field" and no extensions of the same name
135
+ # Result:
136
+ # message.string_field #=> @values["string_field"]
137
+ # message[:string_field] #=> @values["string_field"]
138
+ # message['string_field'] #=> @values["string_field"]
139
+
140
+ # Case 2: Base field = "string_field" and extension 1 = ".my_package.string_field", extension N = ".package_N.string_field"...
141
+ # Result:
142
+ # message.string_field #=> @values["string_field"]
143
+ # message[:string_field] #=> @values["string_field"]
144
+ # message['string_field'] #=> @values["string_field"]
145
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
146
+ # message['.my_package.string_field'] #=> @values[".my_package.string_field"]
147
+
148
+ # Case 3: No base field, extension 1 = ".my_package.string_field", extension 2 = ".other_package.string_field", extension N...
149
+ # Result:
150
+ # message.string_field #=> raise NoMethodError (no simple accessor allowed)
151
+ # message[:string_field] #=> raise NoMethodError (no simple accessor allowed)
152
+ # message['string_field'] #=> raise NoMethodError (no simple accessor allowed)
153
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
154
+ # message['.my_package.string_field'] #=> @values[".my_package.string_field"]
155
+ # message[:'.other_package.string_field'] #=> @values[".other_package.string_field"]
156
+ # message['.other_package.string_field'] #=> @values[".other_package.string_field"]
157
+
158
+ # Case 4: No base field, extension = ".my_package.string_field", no other extensions
159
+ # Result:
160
+ # message.string_field #=> @values[".my_package.string_field"]
161
+ # message[:string_field] #=> @values[".my_package.string_field"]
162
+ # message['string_field'] #=> @values[".my_package.string_field"]
163
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
164
+ # message[:'.my_package.string_field'] #=> @values[".my_package.string_field"]
165
+
166
+ simple_name =
167
+ if options[:extension]
168
+ base_name = fully_qualified_field_name.to_s.split('.').last.to_sym
169
+ if field_store[base_name]
170
+ # Case 3
171
+ if field_store[base_name].extension?
172
+ remove_existing_accessors(base_name)
173
+ end
174
+ nil
175
+ # Case 4
176
+ else
177
+ base_name
178
+ end
179
+ else
180
+ # Case 1
181
+ fully_qualified_field_name
182
+ end
183
+
184
+ field = ::Protobuf::Field.build(self, rule, type_class, fully_qualified_field_name,
185
+ tag, simple_name, options)
186
+ field_store[tag] = field
187
+ field_store[fully_qualified_field_name.to_sym] = field
188
+ field_store[fully_qualified_field_name.to_s] = field
189
+ if simple_name && simple_name != fully_qualified_field_name
190
+ field_store[simple_name.to_sym] = field
191
+ field_store[simple_name.to_s] = field
192
+ end
193
+ # defining a new field for the message will cause cached @all_fields, @extension_fields,
194
+ # and @fields to be incorrect; reset them
195
+ @all_fields = @extension_fields = @fields = nil
196
+ end
197
+
198
+ def remove_existing_accessors(accessor)
199
+ field_store.delete(accessor.to_sym).try(:fully_qualified_name_only!)
200
+ field_store.delete(accessor.to_s)
201
+ ACCESSOR_SUFFIXES.each do |modifier|
202
+ begin
203
+ remove_method("#{accessor}#{modifier}")
204
+ # rubocop: disable Lint/HandleExceptions
205
+ rescue NameError
206
+ # Do not remove the method
207
+ end
208
+ end
209
+ end
210
+
211
+ def raise_if_tag_collision(tag, field_name)
212
+ if get_field(tag, true)
213
+ fail TagCollisionError, %(Field number #{tag} has already been used in "#{name}" by field "#{field_name}".)
214
+ end
215
+ end
216
+
217
+ def raise_if_name_collision(field_name)
218
+ if get_field(field_name, true)
219
+ fail DuplicateFieldNameError, %(Field name #{field_name} has already been used in "#{name}".)
220
+ end
221
+ end
222
+
223
+ def inherit_fields!(subclass)
224
+ instance_variables.each do |iv|
225
+ subclass.instance_variable_set(iv, instance_variable_get(iv))
226
+ end
227
+ end
228
+ private :inherit_fields!
229
+
230
+ end
231
+ end
232
+ end
233
+ end