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.
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