protobuf 3.10.8 → 3.10.10

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +106 -22
  3. data/.rubocop.yml +30 -11
  4. data/.rubocop_todo.yml +462 -60
  5. data/CHANGES.md +31 -0
  6. data/Gemfile +22 -0
  7. data/lib/protobuf/code_generator.rb +17 -5
  8. data/lib/protobuf/decoder.rb +33 -2
  9. data/lib/protobuf/field/base_field.rb +13 -5
  10. data/lib/protobuf/field/base_field_object_definitions.rb +40 -6
  11. data/lib/protobuf/field/bool_field.rb +2 -1
  12. data/lib/protobuf/field/int32_field.rb +12 -0
  13. data/lib/protobuf/field/sint32_field.rb +10 -0
  14. data/lib/protobuf/field/uint32_field.rb +9 -0
  15. data/lib/protobuf/generators/printable.rb +10 -1
  16. data/lib/protobuf/message/serialization.rb +4 -4
  17. data/lib/protobuf/railtie.rb +48 -0
  18. data/lib/protobuf/rpc/application_service.rb +12 -0
  19. data/lib/protobuf/rpc/buffer.rb +2 -2
  20. data/lib/protobuf/rpc/service.rb +7 -3
  21. data/lib/protobuf/rpc/service_filters.rb +35 -5
  22. data/lib/protobuf/service_loader.rb +21 -0
  23. data/lib/protobuf/version.rb +1 -1
  24. data/lib/protobuf.rb +5 -0
  25. data/protobuf.gemspec +9 -27
  26. data/spec/encoding/packed_decoding_spec.rb +233 -0
  27. data/spec/encoding/wire_compat_decoding_spec.rb +113 -0
  28. data/spec/functional/railtie_boot_spec.rb +84 -0
  29. data/spec/lib/protobuf/field/bool_field_spec.rb +21 -0
  30. data/spec/lib/protobuf/field/string_field_spec.rb +0 -2
  31. data/spec/lib/protobuf/generators/service_generator_spec.rb +23 -0
  32. data/spec/lib/protobuf/message_spec.rb +0 -2
  33. data/spec/lib/protobuf/railtie_spec.rb +86 -0
  34. data/spec/lib/protobuf/rpc/application_service_spec.rb +57 -0
  35. data/spec/lib/protobuf/rpc/service_filters_inheritance_spec.rb +105 -0
  36. data/spec/lib/protobuf/service_loader_spec.rb +88 -0
  37. metadata +49 -77
@@ -63,7 +63,14 @@ module Protobuf
63
63
  def define_set_method!
64
64
  end
65
65
 
66
- def set_without_options(message_instance, bytes)
66
+ # Same rules as the set methods in BaseFieldObjectDefinitions: a packable
67
+ # repeated field decodes by the record's wire type, not its declaration.
68
+ def set_without_options(message_instance, bytes, record_wire_type = nil)
69
+ if repeated? && packable?
70
+ return set_packable_without_options(message_instance[name], bytes, record_wire_type)
71
+ end
72
+
73
+ return if record_wire_type && record_wire_type != wire_type
67
74
  return message_instance[name] = decode(bytes) unless repeated?
68
75
 
69
76
  if map?
@@ -75,9 +82,14 @@ module Protobuf
75
82
  return hash[entry.key]
76
83
  end
77
84
 
78
- return message_instance[name] << decode(bytes) unless packed?
85
+ message_instance[name] << decode(bytes)
86
+ end
87
+
88
+ def set_packable_without_options(array, bytes, record_wire_type)
89
+ record_wire_type ||= packed? ? ::Protobuf::WireType::LENGTH_DELIMITED : wire_type
90
+ return array << decode(bytes) if record_wire_type == wire_type
91
+ return unless record_wire_type == ::Protobuf::WireType::LENGTH_DELIMITED
79
92
 
80
- array = message_instance[name]
81
93
  stream = StringIO.new(bytes)
82
94
 
83
95
  if wire_type == ::Protobuf::WireType::VARINT
@@ -92,7 +104,7 @@ module Protobuf
92
104
  # Sets a MessageField that is known to be an option.
93
105
  # We must allow fields to be set one at a time, as option syntax allows us to
94
106
  # set each field within the option using a separate "option" line.
95
- def set_with_options(message_instance, bytes)
107
+ def set_with_options(message_instance, bytes, record_wire_type = nil)
96
108
  if message_instance[name].is_a?(::Protobuf::Message)
97
109
  gp = Google::Protobuf
98
110
  if message_instance.is_a?(gp::EnumOptions) || message_instance.is_a?(gp::EnumValueOptions) ||
@@ -109,7 +121,7 @@ module Protobuf
109
121
  end
110
122
  end
111
123
 
112
- set_without_options(message_instance, bytes)
124
+ set_without_options(message_instance, bytes, record_wire_type)
113
125
  end
114
126
  alias_method :set, :set_with_options
115
127
 
@@ -1,7 +1,8 @@
1
1
  module Protobuf
2
2
  class Decoder
3
3
 
4
- # Read bytes from +stream+ and pass to +message+ object.
4
+ # Read bytes from +stream+ and yield (tag, bytes, wire_type) for each field.
5
+ # A block that takes only (tag, bytes) still works: blocks drop extra arguments.
5
6
  def self.decode_each_field(stream)
6
7
  until stream.eof?
7
8
  bits = Varint.decode(stream)
@@ -17,12 +18,42 @@ module Protobuf
17
18
  stream.read(8)
18
19
  elsif wire_type == ::Protobuf::WireType::FIXED32
19
20
  stream.read(4)
21
+ elsif wire_type == ::Protobuf::WireType::START_GROUP
22
+ skip_group(stream, tag)
23
+ next
20
24
  else
21
25
  fail InvalidWireType, wire_type
22
26
  end
23
27
 
24
- yield(tag, bytes)
28
+ yield(tag, bytes, wire_type)
25
29
  end
26
30
  end
31
+
32
+ # Skip a group (wire types 3 and 4), with any groups inside it. This gem
33
+ # has no group fields, so the rule for an unknown field applies, as in the
34
+ # reference parsers: skip it. A group without its end raises InvalidWireType.
35
+ def self.skip_group(stream, group_tag)
36
+ open_tags = [group_tag]
37
+ until open_tags.empty?
38
+ fail InvalidWireType, ::Protobuf::WireType::START_GROUP if stream.eof?
39
+
40
+ bits = Varint.decode(stream)
41
+ wire_type = bits & 0x07
42
+ tag = bits >> 3
43
+
44
+ case wire_type
45
+ when ::Protobuf::WireType::VARINT then Varint.decode(stream)
46
+ when ::Protobuf::WireType::LENGTH_DELIMITED then stream.read(Varint.decode(stream))
47
+ when ::Protobuf::WireType::FIXED64 then stream.read(8)
48
+ when ::Protobuf::WireType::FIXED32 then stream.read(4)
49
+ when ::Protobuf::WireType::START_GROUP then open_tags.push(tag)
50
+ when ::Protobuf::WireType::END_GROUP
51
+ fail InvalidWireType, wire_type unless open_tags.pop == tag
52
+ else
53
+ fail InvalidWireType, wire_type
54
+ end
55
+ end
56
+ end
57
+ private_class_method :skip_group
27
58
  end
28
59
  end
@@ -287,8 +287,8 @@ module Protobuf
287
287
  def define_set_method!
288
288
  @set_method = if map?
289
289
  OBJECT_MODULE::MapSetMethod.new(self)
290
- elsif repeated? && packed?
291
- OBJECT_MODULE::RepeatedPackedSetMethod.new(self)
290
+ elsif repeated? && packable?
291
+ OBJECT_MODULE::RepeatedPackableSetMethod.new(self)
292
292
  elsif repeated?
293
293
  OBJECT_MODULE::RepeatedNotPackedSetMethod.new(self)
294
294
  else
@@ -296,8 +296,16 @@ module Protobuf
296
296
  end
297
297
  end
298
298
 
299
- def set(message_instance, bytes)
300
- @set_method.call(message_instance, bytes)
299
+ # Whether the field's type can use the packed encoding (scalar numeric
300
+ # types). This is about the type, not about the `packed` option.
301
+ def packable?
302
+ ::Protobuf::Field::BaseField::PACKED_TYPES.include?(wire_type)
303
+ end
304
+
305
+ # +wire_type+ is the wire type of the record that +bytes+ came from. It is
306
+ # nil for callers that do not know it; then the field declaration decides.
307
+ def set(message_instance, bytes, wire_type = nil)
308
+ @set_method.call(message_instance, bytes, wire_type)
301
309
  end
302
310
 
303
311
  def tag_encoded
@@ -372,7 +380,7 @@ module Protobuf
372
380
  end
373
381
 
374
382
  def validate_packed_field
375
- if packed? && ! ::Protobuf::Field::BaseField::PACKED_TYPES.include?(wire_type)
383
+ if packed? && !packable?
376
384
  fail "Can't use packed encoding for '#{type_class}' type"
377
385
  end
378
386
  end
@@ -116,9 +116,13 @@ module Protobuf
116
116
  def initialize(selph)
117
117
  @selph = selph
118
118
  @name = selph.name
119
+ @wire_type = selph.wire_type
119
120
  end
120
121
 
121
- def call(message_instance, bytes)
122
+ # A record whose wire type differs from the field's is skipped, as the
123
+ # protobuf spec and the reference parsers do.
124
+ def call(message_instance, bytes, wire_type = nil)
125
+ return if wire_type && wire_type != @wire_type
122
126
  message_instance.set_field(@name, @selph.decode(bytes), true, @selph)
123
127
  end
124
128
  end
@@ -127,9 +131,11 @@ module Protobuf
127
131
  def initialize(selph)
128
132
  @selph = selph
129
133
  @name = selph.name
134
+ @wire_type = selph.wire_type
130
135
  end
131
136
 
132
- def call(message_instance, bytes)
137
+ def call(message_instance, bytes, wire_type = nil)
138
+ return if wire_type && wire_type != @wire_type
133
139
  hash = message_instance[@name]
134
140
  entry = @selph.decode(bytes)
135
141
  # decoded value could be nil for an
@@ -139,26 +145,54 @@ module Protobuf
139
145
  end
140
146
  end
141
147
 
148
+ # Repeated string, bytes, and message fields. These are never packed.
142
149
  class RepeatedNotPackedSetMethod
143
150
  def initialize(selph)
144
151
  @selph = selph
145
152
  @name = selph.name
153
+ @wire_type = selph.wire_type
146
154
  end
147
155
 
148
- def call(message_instance, bytes)
156
+ def call(message_instance, bytes, wire_type = nil)
157
+ return if wire_type && wire_type != @wire_type
149
158
  message_instance[@name] << @selph.decode(bytes)
150
159
  end
151
160
  end
152
161
 
153
- class RepeatedPackedSetMethod
162
+ # Repeated scalar numeric fields (varint, fixed32, fixed64). The protobuf
163
+ # spec requires a parser to accept both the packed and the unpacked
164
+ # encoding, whatever the field declares. The wire type of each record
165
+ # selects the decoding: LENGTH_DELIMITED is a packed run, and the field's
166
+ # own wire type is one value. A record without a wire type (an old
167
+ # caller of BaseField#set) falls back to the declaration.
168
+ class RepeatedPackableSetMethod
169
+ LENGTH_DELIMITED = ::Protobuf::WireType::LENGTH_DELIMITED
170
+
154
171
  def initialize(selph)
155
172
  @selph = selph
156
173
  @name = selph.name
157
174
  @wire_type = selph.wire_type
175
+ @packed = selph.packed?
176
+ end
177
+
178
+ def call(message_instance, bytes, wire_type = nil)
179
+ # Most common first: one unpacked value, as this gem encodes by default.
180
+ if wire_type == @wire_type
181
+ message_instance[@name] << @selph.decode(bytes)
182
+ elsif wire_type == LENGTH_DELIMITED
183
+ decode_packed(message_instance[@name], bytes)
184
+ elsif wire_type.nil?
185
+ if @packed
186
+ decode_packed(message_instance[@name], bytes)
187
+ else
188
+ message_instance[@name] << @selph.decode(bytes)
189
+ end
190
+ end
158
191
  end
159
192
 
160
- def call(message_instance, bytes)
161
- array = message_instance[@name]
193
+ private
194
+
195
+ def decode_packed(array, bytes)
162
196
  stream = ::StringIO.new(bytes)
163
197
 
164
198
  if @wire_type == ::Protobuf::WireType::VARINT
@@ -38,8 +38,9 @@ module Protobuf
38
38
  end
39
39
  end
40
40
 
41
+ # Any non-zero varint is true, as in the reference parsers.
41
42
  def decode(value)
42
- value == ONE
43
+ value != 0
43
44
  end
44
45
 
45
46
  def encode(value)
@@ -16,6 +16,18 @@ module Protobuf
16
16
  INT32_MIN
17
17
  end
18
18
 
19
+ ##
20
+ # Public Instance Methods
21
+ #
22
+
23
+ # Keep the low 32 bits, as the reference parsers do. A peer that sends
24
+ # an int64 or uint64 value for this field (a compatible schema change)
25
+ # then decodes instead of raising.
26
+ def decode(value)
27
+ value &= 0xffff_ffff
28
+ value >= 0x8000_0000 ? value - 0x1_0000_0000 : value
29
+ end
30
+
19
31
  end
20
32
  end
21
33
  end
@@ -16,6 +16,16 @@ module Protobuf
16
16
  INT32_MIN
17
17
  end
18
18
 
19
+ ##
20
+ # Public Instance Methods
21
+ #
22
+
23
+ # Keep the low 32 bits before the zigzag decode, as the reference
24
+ # parsers do. A peer that sends a sint64 value then decodes.
25
+ def decode(value)
26
+ super(value & 0xffff_ffff)
27
+ end
28
+
19
29
  end
20
30
  end
21
31
  end
@@ -16,6 +16,15 @@ module Protobuf
16
16
  0
17
17
  end
18
18
 
19
+ ##
20
+ # Public Instance Methods
21
+ #
22
+
23
+ # Keep the low 32 bits, as the reference parsers do.
24
+ def decode(value)
25
+ value & 0xffff_ffff
26
+ end
27
+
19
28
  end
20
29
  end
21
30
  end
@@ -82,12 +82,21 @@ module Protobuf
82
82
  when :enum then
83
83
  PARENT_CLASS_ENUM
84
84
  when :service then
85
- PARENT_CLASS_SERVICE
85
+ service_parent_class
86
86
  else
87
87
  fail "Unknown parent class type #{type}: #{caller[0..5].join("\n")}"
88
88
  end
89
89
  end
90
90
 
91
+ # PB_SERVICE_PARENT sets the parent class of generated services, for
92
+ # example `ApplicationService` or `::Protobuf::Rpc::ApplicationService`.
93
+ # The parent class must be loaded before the generated file.
94
+ #
95
+ def service_parent_class
96
+ parent = ENV['PB_SERVICE_PARENT'].to_s.strip
97
+ parent.empty? ? PARENT_CLASS_SERVICE : parent
98
+ end
99
+
91
100
  # Print a class or module block, indicated by type.
92
101
  # If a class, can be given a parent class to inherit from.
93
102
  # If a block is given, call the block from within an indent block.
@@ -38,8 +38,8 @@ module Protobuf
38
38
  # Decode the given stream into this message.
39
39
  #
40
40
  def decode_from(stream)
41
- ::Protobuf::Decoder.decode_each_field(stream) do |tag, bytes|
42
- set_field_bytes(tag, bytes)
41
+ ::Protobuf::Decoder.decode_each_field(stream) do |tag, bytes, wire_type|
42
+ set_field_bytes(tag, bytes, wire_type)
43
43
  end
44
44
 
45
45
  self
@@ -75,9 +75,9 @@ module Protobuf
75
75
 
76
76
  private
77
77
 
78
- def set_field_bytes(tag, bytes)
78
+ def set_field_bytes(tag, bytes, wire_type = nil)
79
79
  field = _protobuf_message_field[tag]
80
- field.set(self, bytes) if field
80
+ field.set(self, bytes, wire_type) if field
81
81
  end
82
82
 
83
83
  end
@@ -0,0 +1,48 @@
1
+ require 'rails/railtie'
2
+ require 'protobuf/service_loader'
3
+
4
+ module Protobuf
5
+ # RPC discovery (`Service.implemented_services`) walks `descendants`, which
6
+ # only sees loaded classes, and Zeitwerk loads lazily. This railtie loads the
7
+ # configured services directory one time, when the RPC server is about to
8
+ # bind. Web, console, and test processes never pay that cost.
9
+ #
10
+ # Opt in from config/application.rb:
11
+ #
12
+ # config.protobuf.services_path = 'app/services/rpc'
13
+ #
14
+ # A relative path resolves against Rails.root.
15
+ class Railtie < ::Rails::Railtie
16
+ config.protobuf = ::ActiveSupport::OrderedOptions.new
17
+ config.protobuf.services_path = nil
18
+
19
+ initializer 'protobuf.load_services' do |app|
20
+ ::ActiveSupport::Notifications.subscribe('before_server_bind') do
21
+ ::Protobuf::Railtie.load_services(app)
22
+ end
23
+ end
24
+
25
+ def self.services_path(app)
26
+ configured = app.config.protobuf.services_path.to_s
27
+ return if configured.empty?
28
+
29
+ ::File.expand_path(configured, app.root.to_s)
30
+ end
31
+
32
+ def self.load_services(app)
33
+ path = services_path(app)
34
+ return unless path && ::File.directory?(path)
35
+
36
+ loader = ::Rails.autoloaders.main # nil with the classic autoloader
37
+ if loader.respond_to?(:eager_load_dir) # Zeitwerk 2.6.2+
38
+ begin
39
+ return loader.eager_load_dir(path)
40
+ rescue ::Zeitwerk::Error
41
+ # The main autoloader does not manage this path. Fall through.
42
+ end
43
+ end
44
+
45
+ ::Protobuf::ServiceLoader.load_services(path)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,12 @@
1
+ require 'protobuf/rpc/service'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+ # Base class for application services, like `ApplicationController`.
6
+ # Filters and `rescue_from` handlers defined here pass to every subclass.
7
+ # Generate services with `PB_SERVICE_PARENT=::Protobuf::Rpc::ApplicationService`
8
+ # to inherit from it.
9
+ class ApplicationService < Service
10
+ end
11
+ end
12
+ end
@@ -44,7 +44,7 @@ module Protobuf
44
44
  end
45
45
  end
46
46
 
47
- def set_data(data) # rubocop:disable Style/AccessorMethodName
47
+ def set_data(data) # rubocop:disable Naming/AccessorMethodName
48
48
  @data = data.to_s
49
49
  @size = @data.size
50
50
  end
@@ -61,7 +61,7 @@ module Protobuf
61
61
  @flush
62
62
  end
63
63
 
64
- def get_data_size # rubocop:disable Style/AccessorMethodName
64
+ def get_data_size # rubocop:disable Naming/AccessorMethodName
65
65
  if @size == 0 || @data.match(SIZE_REGEX)
66
66
  sliced_size = @data.slice!(SIZE_REGEX)
67
67
  @size = sliced_size.delete('-').to_i unless sliced_size.nil?
@@ -1,3 +1,4 @@
1
+ require 'active_support/core_ext/class/subclasses'
1
2
  require 'protobuf/logging'
2
3
  require 'protobuf/message'
3
4
  require 'protobuf/rpc/client'
@@ -65,15 +66,18 @@ module Protobuf
65
66
  end
66
67
 
67
68
  # An array of defined service classes that contain implementation
68
- # code
69
+ # code. Walks the full descendant tree so intermediate parents
70
+ # (e.g. ApplicationService) don't hide the real services from
71
+ # discovery.
69
72
  def self.implemented_services
70
- classes = (subclasses || []).select do |subclass|
73
+ classes = descendants.select do |subclass|
71
74
  subclass.rpcs.any? do |(name, _)|
72
75
  subclass.method_defined? name
73
76
  end
74
77
  end
75
78
 
76
- classes.map(&:name)
79
+ # Dev reloads can leave nameless/duplicate classes in `descendants`.
80
+ classes.map(&:name).compact.uniq
77
81
  end
78
82
 
79
83
  # Shorthand call to configure, passing a string formatted as hostname:port
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/class/subclasses'
2
+
1
3
  module Protobuf
2
4
  module Rpc
3
5
  module ServiceFilters
@@ -34,23 +36,51 @@ module Protobuf
34
36
  @rescue_filters ||= {}
35
37
  end
36
38
 
39
+ # A subclass gets the filters of its parent, so a base class such as
40
+ # ApplicationService can hold shared filters. A filter that the parent
41
+ # adds later also goes to existing subclasses (after their own filters).
42
+ def inherited(subclass)
43
+ super
44
+ subclass.inherit_filters_from(self)
45
+ end
46
+
37
47
  def rescue_from(*ex_klasses, &block)
38
48
  options = ex_klasses.last.is_a?(Hash) ? ex_klasses.pop : {}
39
49
  callable = options.delete(:with) { block }
40
50
  fail ArgumentError, 'Option :with missing from rescue_from options' if callable.nil?
41
- ex_klasses.each { |ex_klass| rescue_filters[ex_klass] = callable }
51
+ ex_klasses.each do |ex_klass|
52
+ inherited_callable = rescue_filters[ex_klass]
53
+ rescue_filters[ex_klass] = callable
54
+ descendants.each do |klass|
55
+ # A subclass keeps a handler that it defined itself.
56
+ current = klass.rescue_filters[ex_klass]
57
+ klass.rescue_filters[ex_klass] = callable if current.nil? || current.equal?(inherited_callable)
58
+ end
59
+ end
42
60
  end
43
61
 
44
- private
62
+ protected
45
63
 
46
- def define_filter(type, filter, options = {})
64
+ def inherit_filters_from(parent)
65
+ parent.filters.each { |type, list| filters[type] = list.dup }
66
+ parent.defined_filters.each { |type, set| defined_filters[type] = set.dup }
67
+ rescue_filters.merge!(parent.rescue_filters)
68
+ end
69
+
70
+ def defined_filters
71
+ @defined_filters ||= Hash.new { |h, k| h[k] = Set.new }
72
+ end
73
+
74
+ def add_filter(type, filter, options)
47
75
  return if filter_defined?(type, filter)
48
76
  filters[type] << options.merge(:callable => filter)
49
77
  remember_filter(type, filter)
50
78
  end
51
79
 
52
- def defined_filters
53
- @defined_filters ||= Hash.new { |h, k| h[k] = Set.new }
80
+ private
81
+
82
+ def define_filter(type, filter, options = {})
83
+ ([self] + descendants).each { |klass| klass.add_filter(type, filter, options) }
54
84
  end
55
85
 
56
86
  # Check to see if the filter has been defined.
@@ -0,0 +1,21 @@
1
+ module Protobuf
2
+ # Requires every Ruby file below a directory, in sorted order. Protobuf::Railtie
3
+ # uses it when the main autoloader cannot eager-load the services directory
4
+ # (classic autoloader, Zeitwerk < 2.6.2, or a path outside the main loader).
5
+ #
6
+ # It uses `require`, not `load`. Zeitwerk tracks `require` of the files it
7
+ # manages, and a file never executes two times.
8
+ module ServiceLoader
9
+ DEFAULT_GLOB = '**/*.rb'.freeze
10
+
11
+ def self.load_services(path, glob = DEFAULT_GLOB)
12
+ return [] if path.nil?
13
+ dir = ::File.expand_path(path.to_s)
14
+ return [] unless ::File.directory?(dir)
15
+
16
+ ::Dir.glob(::File.join(dir, glob)).sort.each do |file|
17
+ require file
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Protobuf
2
- VERSION = '3.10.8' # rubocop:disable Style/MutableConstant
2
+ VERSION = '3.10.10' # rubocop:disable Style/MutableConstant
3
3
  end
data/lib/protobuf.rb CHANGED
@@ -44,6 +44,10 @@ require 'protobuf/enum'
44
44
  require 'protobuf/message'
45
45
  require 'protobuf/descriptors'
46
46
 
47
+ # Rails runs this hook when the application class is defined. That works even
48
+ # when protobuf loads before Rails, as `rpc_server` does.
49
+ ::ActiveSupport.on_load(:before_configuration) { require 'protobuf/railtie' }
50
+
47
51
  module Protobuf
48
52
 
49
53
  class << self
@@ -114,6 +118,7 @@ end
114
118
  unless ENV.key?('PB_NO_NETWORKING')
115
119
  require 'protobuf/rpc/client'
116
120
  require 'protobuf/rpc/service'
121
+ require 'protobuf/rpc/application_service'
117
122
 
118
123
  env_connector_type = ENV.fetch('PB_CLIENT_TYPE') do
119
124
  :socket
data/protobuf.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  $LOAD_PATH.push ::File.expand_path("../lib", __FILE__)
3
2
  require "protobuf/version"
4
3
 
@@ -19,39 +18,22 @@ require "protobuf/version"
19
18
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
20
19
  s.require_paths = ["lib"]
21
20
 
22
- # Hack, as Rails 5 requires Ruby version >= 2.2.2.
23
- active_support_max_version = "< 5" if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.2.2")
24
- s.add_dependency "activesupport", '>= 3.2', active_support_max_version
21
+ s.required_ruby_version = '>= 3.1'
22
+
23
+ s.add_dependency "activesupport", '>= 6.0'
25
24
  s.add_dependency 'middleware'
26
25
  s.add_dependency 'thor'
27
26
  s.add_dependency 'thread_safe'
28
27
 
28
+ # Ruby 4.0 no longer loads benchmark from the standard library.
29
+ s.add_development_dependency 'benchmark'
29
30
  s.add_development_dependency 'benchmark-ips'
30
31
  s.add_development_dependency 'ffi-rzmq'
31
- s.add_development_dependency 'rake', '< 11.0' # Rake 11.0.1 removes the last_comment method which rspec-core (< 3.4.4) uses
32
- s.add_development_dependency 'rspec', '>= 3.0'
33
- s.add_development_dependency "rubocop", "~> 0.38.0"
34
- s.add_development_dependency "parser", "2.3.0.6" # Locked this down since 2.3.0.7 causes issues. https://github.com/bbatsov/rubocop/pull/2984
32
+ s.add_development_dependency 'railties', '>= 6.0'
33
+ s.add_development_dependency 'rake', '~> 13.0'
34
+ s.add_development_dependency 'rspec', '~> 3.5'
35
+ s.add_development_dependency "rubocop", "~> 0.81.0"
35
36
  s.add_development_dependency 'simplecov'
36
37
  s.add_development_dependency 'timecop'
37
38
  s.add_development_dependency 'yard'
38
-
39
- # debuggers only work in MRI
40
- if RUBY_ENGINE.to_sym == :ruby
41
- # we don't support MRI < 1.9.3
42
- pry_debugger = if RUBY_VERSION < '2.0.0'
43
- 'pry-debugger'
44
- else
45
- 'pry-byebug'
46
- end
47
-
48
- s.add_development_dependency pry_debugger
49
- s.add_development_dependency 'pry-stack_explorer'
50
-
51
- s.add_development_dependency 'varint'
52
- s.add_development_dependency 'ruby-prof'
53
- elsif RUBY_PLATFORM =~ /java/i
54
- s.add_development_dependency 'fast_blank_java'
55
- s.add_development_dependency 'pry'
56
- end
57
39
  end