protobuf 2.1.3 → 2.2.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.
- data/lib/protobuf/field/bool_field.rb +12 -0
- data/lib/protobuf/message.rb +161 -125
- data/lib/protobuf/rpc/server.rb +1 -1
- data/lib/protobuf/rpc/service_filters.rb +49 -25
- data/lib/protobuf/version.rb +1 -1
- data/spec/lib/protobuf/message_spec.rb +72 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +95 -0
- metadata +4 -4
@@ -16,6 +16,18 @@ module Protobuf
|
|
16
16
|
value == 1
|
17
17
|
end
|
18
18
|
|
19
|
+
def define_getter
|
20
|
+
super
|
21
|
+
|
22
|
+
field = self
|
23
|
+
@message_class.class_eval do
|
24
|
+
define_method("#{field.getter_method_name}?") do
|
25
|
+
field.warn_if_deprecated
|
26
|
+
@values.fetch(field.name, field.default_value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
19
31
|
def encode(value)
|
20
32
|
[value ? 1 : 0].pack('C')
|
21
33
|
end
|
data/lib/protobuf/message.rb
CHANGED
@@ -6,11 +6,19 @@ require 'protobuf/message/encoder'
|
|
6
6
|
|
7
7
|
module Protobuf
|
8
8
|
class Message
|
9
|
-
|
9
|
+
##
|
10
|
+
# Error Classes
|
11
|
+
#
|
10
12
|
class FieldNotDefinedError < StandardError; end
|
11
13
|
|
14
|
+
##
|
15
|
+
# Constants
|
16
|
+
#
|
12
17
|
STRING_ENCODING = "ASCII-8BIT".freeze
|
13
18
|
|
19
|
+
##
|
20
|
+
# Class Methods
|
21
|
+
#
|
14
22
|
def self.all_fields
|
15
23
|
@all_fields ||= begin
|
16
24
|
all_fields_array = []
|
@@ -23,26 +31,6 @@ module Protobuf
|
|
23
31
|
end
|
24
32
|
end
|
25
33
|
|
26
|
-
# Reserve field numbers for extensions. Don't use this method directly.
|
27
|
-
def self.extensions(range)
|
28
|
-
extension_fields.add_range(range)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Define a required field. Don't use this method directly.
|
32
|
-
def self.required(type, name, tag, options = {})
|
33
|
-
define_field(:required, type, name, tag, options)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Define a optional field. Don't use this method directly.
|
37
|
-
def self.optional(type, name, tag, options = {})
|
38
|
-
define_field(:optional, type, name, tag, options)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Define a repeated field. Don't use this method directly.
|
42
|
-
def self.repeated(type, name, tag, options = {})
|
43
|
-
define_field(:repeated, type, name, tag, options)
|
44
|
-
end
|
45
|
-
|
46
34
|
# Define a field. Don't use this method directly.
|
47
35
|
def self.define_field(rule, type, fname, tag, options)
|
48
36
|
field_array = options[:extension] ? extension_fields : fields
|
@@ -57,8 +45,13 @@ module Protobuf
|
|
57
45
|
field_array[tag] = field_definition
|
58
46
|
end
|
59
47
|
|
60
|
-
|
61
|
-
|
48
|
+
# Reserve field numbers for extensions. Don't use this method directly.
|
49
|
+
def self.extensions(range)
|
50
|
+
extension_fields.add_range(range)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.extension_field_name_to_tag
|
54
|
+
@extension_fields_by_name ||= {}
|
62
55
|
end
|
63
56
|
|
64
57
|
# An extension field object.
|
@@ -66,8 +59,8 @@ module Protobuf
|
|
66
59
|
@extension_fields ||= ::Protobuf::Field::ExtensionFields.new
|
67
60
|
end
|
68
61
|
|
69
|
-
def self.
|
70
|
-
|
62
|
+
def self.extension_tag?(tag)
|
63
|
+
extension_fields.include_tag?(tag)
|
71
64
|
end
|
72
65
|
|
73
66
|
# A collection of field object.
|
@@ -79,6 +72,18 @@ module Protobuf
|
|
79
72
|
@field_name_to_tag ||= {}
|
80
73
|
end
|
81
74
|
|
75
|
+
def self.get_ext_field_by_name(name)
|
76
|
+
# Check if the name has been used before, if not then set it to the sym value
|
77
|
+
extension_fields[extension_field_name_to_tag[name.to_sym]]
|
78
|
+
rescue TypeError, NoMethodError => e
|
79
|
+
name = 'nil' if name.nil?
|
80
|
+
raise FieldNotDefinedError.new("Field '#{name}' is not defined on message '#{self.name}'")
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.get_ext_field_by_tag(tag)
|
84
|
+
extension_fields[tag]
|
85
|
+
end
|
86
|
+
|
82
87
|
# Find a field object by +name+.
|
83
88
|
def self.get_field_by_name(name)
|
84
89
|
# Check if the name has been used before, if not then set it to the sym value
|
@@ -96,16 +101,19 @@ module Protobuf
|
|
96
101
|
raise FieldNotDefinedError.new("Tag '#{tag}' does not reference a message field for '#{self.name}'")
|
97
102
|
end
|
98
103
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
rescue TypeError, NoMethodError => e
|
103
|
-
name = 'nil' if name.nil?
|
104
|
-
raise FieldNotDefinedError.new("Field '#{name}' is not defined on message '#{self.name}'")
|
104
|
+
# Define a optional field. Don't use this method directly.
|
105
|
+
def self.optional(type, name, tag, options = {})
|
106
|
+
define_field(:optional, type, name, tag, options)
|
105
107
|
end
|
106
108
|
|
107
|
-
|
108
|
-
|
109
|
+
# Define a repeated field. Don't use this method directly.
|
110
|
+
def self.repeated(type, name, tag, options = {})
|
111
|
+
define_field(:repeated, type, name, tag, options)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Define a required field. Don't use this method directly.
|
115
|
+
def self.required(type, name, tag, options = {})
|
116
|
+
define_field(:required, type, name, tag, options)
|
109
117
|
end
|
110
118
|
|
111
119
|
##
|
@@ -117,20 +125,11 @@ module Protobuf
|
|
117
125
|
values.each { |name, val| self[name] = val unless val.nil? }
|
118
126
|
end
|
119
127
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
@values.has_key?(name)
|
126
|
-
end
|
127
|
-
|
128
|
-
def ==(obj)
|
129
|
-
return false unless obj.is_a?(self.class)
|
130
|
-
each_field do |field, value|
|
131
|
-
return false unless value == obj.__send__(field.name)
|
132
|
-
end
|
133
|
-
true
|
128
|
+
##
|
129
|
+
# Public Instance Methods
|
130
|
+
#
|
131
|
+
def all_fields
|
132
|
+
self.class.all_fields
|
134
133
|
end
|
135
134
|
|
136
135
|
def clear!
|
@@ -145,121 +144,96 @@ module Protobuf
|
|
145
144
|
self
|
146
145
|
end
|
147
146
|
|
148
|
-
def dup
|
149
|
-
copy_to(super, :dup)
|
150
|
-
end
|
151
|
-
|
152
147
|
def clone
|
153
148
|
copy_to(super, :clone)
|
154
149
|
end
|
155
150
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
when Message, String then obj.__send__(method)
|
160
|
-
else obj
|
161
|
-
end
|
162
|
-
}
|
151
|
+
def dup
|
152
|
+
copy_to(super, :dup)
|
153
|
+
end
|
163
154
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
155
|
+
# Iterate over a field collection.
|
156
|
+
# message.each_field do |field_object, value|
|
157
|
+
# # do something
|
158
|
+
# end
|
159
|
+
def each_field
|
160
|
+
all_fields.each do |field|
|
161
|
+
value = __send__(field.name)
|
162
|
+
yield(field, value)
|
171
163
|
end
|
172
|
-
object
|
173
164
|
end
|
174
|
-
private :copy_to
|
175
165
|
|
176
|
-
|
177
|
-
|
166
|
+
# Returns extension fields. See Message#fields method.
|
167
|
+
def extension_fields
|
168
|
+
self.class.extension_fields
|
178
169
|
end
|
179
170
|
|
180
|
-
def
|
181
|
-
|
171
|
+
def fields
|
172
|
+
self.class.fields
|
182
173
|
end
|
183
174
|
|
184
|
-
def
|
185
|
-
|
175
|
+
def get_ext_field_by_name(name) # :nodoc:
|
176
|
+
self.class.get_ext_field_by_name(name)
|
186
177
|
end
|
187
178
|
|
188
|
-
def
|
189
|
-
|
190
|
-
serialize_to(io)
|
191
|
-
result = io.string
|
192
|
-
result.force_encoding(::Protobuf::Message::STRING_ENCODING) if result.respond_to?(:force_encoding)
|
193
|
-
result
|
179
|
+
def get_ext_field_by_tag(tag) # :nodoc:
|
180
|
+
self.class.get_ext_field_by_tag(tag)
|
194
181
|
end
|
195
|
-
alias to_s serialize_to_string
|
196
182
|
|
197
|
-
|
198
|
-
|
183
|
+
# Returns field object or +nil+.
|
184
|
+
def get_field_by_name(name)
|
185
|
+
self.class.get_field_by_name(name)
|
199
186
|
end
|
200
187
|
|
201
|
-
|
202
|
-
|
203
|
-
|
188
|
+
# Returns field object or +nil+.
|
189
|
+
def get_field_by_tag(tag)
|
190
|
+
self.class.get_field_by_tag(tag)
|
204
191
|
end
|
205
192
|
|
206
|
-
def
|
207
|
-
|
208
|
-
__send__(field.name)
|
209
|
-
else
|
210
|
-
raise NoMethodError, "No such field: #{name.inspect}"
|
211
|
-
end
|
193
|
+
def has_field?(name)
|
194
|
+
@values.has_key?(name)
|
212
195
|
end
|
213
196
|
|
214
|
-
def
|
215
|
-
|
216
|
-
__send__(field.setter_method_name, value)
|
217
|
-
else
|
218
|
-
raise NoMethodError, "No such field: #{name.inspect}"
|
219
|
-
end
|
197
|
+
def initialized?
|
198
|
+
all_fields.all? { |field| field.initialized?(self) }
|
220
199
|
end
|
221
200
|
|
222
|
-
|
223
|
-
|
224
|
-
self.class.all_fields
|
201
|
+
def inspect
|
202
|
+
to_hash.inspect
|
225
203
|
end
|
226
204
|
|
227
|
-
def
|
228
|
-
|
205
|
+
def parse_from_string(string)
|
206
|
+
parse_from(StringIO.new(string))
|
229
207
|
end
|
230
208
|
|
231
|
-
|
232
|
-
|
233
|
-
self.class.get_field_by_name(name)
|
209
|
+
def parse_from(stream)
|
210
|
+
Decoder.decode(stream, self)
|
234
211
|
end
|
235
212
|
|
236
|
-
|
237
|
-
|
238
|
-
self.class.get_field_by_tag(tag)
|
213
|
+
def respond_to_has?(key)
|
214
|
+
self.respond_to?(key) && self.has_field?(key)
|
239
215
|
end
|
240
216
|
|
241
|
-
|
242
|
-
|
243
|
-
|
217
|
+
def respond_to_has_and_present?(key)
|
218
|
+
self.respond_to_has?(key) &&
|
219
|
+
(self.__send__(key).present? || [true, false].include?(self.__send__(key)))
|
244
220
|
end
|
245
221
|
|
246
|
-
def
|
247
|
-
|
222
|
+
def serialize_to(stream)
|
223
|
+
Encoder.encode(stream, self)
|
248
224
|
end
|
249
225
|
|
250
|
-
def
|
251
|
-
|
226
|
+
def serialize_to_string(string='')
|
227
|
+
io = StringIO.new(string)
|
228
|
+
serialize_to(io)
|
229
|
+
result = io.string
|
230
|
+
result.force_encoding(::Protobuf::Message::STRING_ENCODING) if result.respond_to?(:force_encoding)
|
231
|
+
result
|
252
232
|
end
|
253
233
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
# end
|
258
|
-
def each_field
|
259
|
-
all_fields.each do |field|
|
260
|
-
value = __send__(field.name)
|
261
|
-
yield(field, value)
|
262
|
-
end
|
234
|
+
def set_field(tag, bytes)
|
235
|
+
field = (get_field_by_tag(tag) || get_ext_field_by_tag(tag))
|
236
|
+
field.set(self, bytes) if field
|
263
237
|
end
|
264
238
|
|
265
239
|
# Return a hash-representation of the given fields for this message type.
|
@@ -274,11 +248,73 @@ module Protobuf
|
|
274
248
|
|
275
249
|
return result
|
276
250
|
end
|
277
|
-
alias_method :to_hash_value, :to_hash
|
278
251
|
|
279
252
|
def to_json
|
280
253
|
to_hash.to_json
|
281
254
|
end
|
282
255
|
|
256
|
+
def ==(obj)
|
257
|
+
return false unless obj.is_a?(self.class)
|
258
|
+
each_field do |field, value|
|
259
|
+
return false unless value == obj.__send__(field.name)
|
260
|
+
end
|
261
|
+
true
|
262
|
+
end
|
263
|
+
|
264
|
+
def [](name)
|
265
|
+
if field = get_field_by_name(name) || get_ext_field_by_name(name)
|
266
|
+
__send__(field.name)
|
267
|
+
else
|
268
|
+
raise NoMethodError, "No such field: #{name.inspect}"
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def []=(name, value)
|
273
|
+
if field = get_field_by_name(name) || get_ext_field_by_name(name)
|
274
|
+
__send__(field.setter_method_name, value)
|
275
|
+
else
|
276
|
+
raise NoMethodError, "No such field: #{name.inspect}"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
##
|
281
|
+
# Instance Aliases
|
282
|
+
#
|
283
|
+
alias_method :to_hash_value, :to_hash
|
284
|
+
alias_method :to_s, :serialize_to_string
|
285
|
+
alias_method :responds_to_has?, :respond_to_has?
|
286
|
+
alias_method :respond_to_and_has?, :respond_to_has?
|
287
|
+
alias_method :responds_to_and_has?, :respond_to_has?
|
288
|
+
alias_method :respond_to_has_present?, :respond_to_has_and_present?
|
289
|
+
alias_method :respond_to_and_has_present?, :respond_to_has_and_present?
|
290
|
+
alias_method :respond_to_and_has_and_present?, :respond_to_has_and_present?
|
291
|
+
alias_method :responds_to_has_present?, :respond_to_has_and_present?
|
292
|
+
alias_method :responds_to_and_has_present?, :respond_to_has_and_present?
|
293
|
+
alias_method :responds_to_and_has_and_present?, :respond_to_has_and_present?
|
294
|
+
|
295
|
+
##
|
296
|
+
# Private Instance Methods
|
297
|
+
#
|
298
|
+
private
|
299
|
+
|
300
|
+
def copy_to(object, method)
|
301
|
+
duplicate = proc { |obj|
|
302
|
+
case obj
|
303
|
+
when Message, String then obj.__send__(method)
|
304
|
+
else obj
|
305
|
+
end
|
306
|
+
}
|
307
|
+
|
308
|
+
object.__send__(:initialize)
|
309
|
+
@values.each do |name, value|
|
310
|
+
if value.is_a?(Field::FieldArray)
|
311
|
+
object.__send__(name).replace(value.map {|v| duplicate.call(v)})
|
312
|
+
else
|
313
|
+
object.__send__("#{name}=", duplicate.call(value))
|
314
|
+
end
|
315
|
+
end
|
316
|
+
object
|
317
|
+
end
|
318
|
+
|
283
319
|
end
|
284
320
|
end
|
data/lib/protobuf/rpc/server.rb
CHANGED
@@ -26,6 +26,20 @@ module Protobuf
|
|
26
26
|
@filters ||= Hash.new { |h,k| h[k] = [] }
|
27
27
|
end
|
28
28
|
|
29
|
+
# Filters hash keyed based on filter type (e.g. :before, :after, :around),
|
30
|
+
# whose values are Sets.
|
31
|
+
#
|
32
|
+
def rescue_filters
|
33
|
+
@rescue_filters ||= {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def rescue_from(*ex_klasses, &block)
|
37
|
+
options = ex_klasses.last.is_a?(Hash) ? ex_klasses.pop : {}
|
38
|
+
callable = options.delete(:with) { block }
|
39
|
+
raise ArgumentError, 'Option :with missing from rescue_from options' if callable.nil?
|
40
|
+
ex_klasses.each { |ex_klass| rescue_filters[ex_klass] = callable }
|
41
|
+
end
|
42
|
+
|
29
43
|
private
|
30
44
|
|
31
45
|
def define_filter(type, filter, options = {})
|
@@ -146,14 +160,18 @@ module Protobuf
|
|
146
160
|
return ! skip_invoke
|
147
161
|
end
|
148
162
|
|
163
|
+
def rescue_filters
|
164
|
+
self.class.rescue_filters
|
165
|
+
end
|
166
|
+
|
149
167
|
# Loop over the unwrapped filters and invoke them. An unwrapped filter
|
150
168
|
# is either a before or after filter, not an around filter.
|
151
169
|
#
|
152
170
|
def run_unwrapped_filters(unwrapped_filters, rpc_method, stop_on_false_return = false)
|
153
171
|
unwrapped_filters.each do |filter|
|
154
172
|
if invoke_filter?(rpc_method, filter)
|
155
|
-
|
156
|
-
return false if stop_on_false_return &&
|
173
|
+
return_value = call_or_send(filter[:callable])
|
174
|
+
return false if stop_on_false_return && return_value == false
|
157
175
|
end
|
158
176
|
end
|
159
177
|
|
@@ -205,35 +223,41 @@ module Protobuf
|
|
205
223
|
# be used instead of the other run methods directly.
|
206
224
|
#
|
207
225
|
def run_filters(rpc_method)
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
226
|
+
run_rescue_filters do
|
227
|
+
continue = run_unwrapped_filters(filters[:before], rpc_method, true)
|
228
|
+
if continue
|
229
|
+
run_around_filters(rpc_method)
|
230
|
+
run_unwrapped_filters(filters[:after], rpc_method)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def run_rescue_filters
|
236
|
+
if rescue_filters.keys.empty?
|
237
|
+
yield
|
238
|
+
else
|
239
|
+
begin
|
240
|
+
yield
|
241
|
+
rescue *rescue_filters.keys => ex
|
242
|
+
call_or_send(rescue_filters[ex.class], ex)
|
243
|
+
end
|
212
244
|
end
|
213
245
|
end
|
214
246
|
|
215
247
|
# Call the object if it is callable, otherwise invoke the method using
|
216
248
|
# __send__ assuming that we respond_to it. Return the call's return value.
|
217
249
|
#
|
218
|
-
def call_or_send(callable, &block)
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
else
|
230
|
-
__send__(callable, &block)
|
231
|
-
end
|
232
|
-
else
|
233
|
-
raise "Object #{callable} is not callable"
|
234
|
-
end
|
235
|
-
|
236
|
-
return rv
|
250
|
+
def call_or_send(callable, *args, &block)
|
251
|
+
return_value = case
|
252
|
+
when callable.respond_to?(:call) then
|
253
|
+
callable.call(self, *args, &block)
|
254
|
+
when respond_to?(callable, true) then
|
255
|
+
__send__(callable, *args, &block)
|
256
|
+
else
|
257
|
+
raise "Object #{callable} is not callable"
|
258
|
+
end
|
259
|
+
|
260
|
+
return return_value
|
237
261
|
end
|
238
262
|
|
239
263
|
end
|
data/lib/protobuf/version.rb
CHANGED
@@ -20,6 +20,78 @@ describe Protobuf::Message do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
describe "boolean predicate methods" do
|
24
|
+
subject { Test::ResourceFindRequest.new(:name => "resource") }
|
25
|
+
|
26
|
+
it { should respond_to(:active?) }
|
27
|
+
|
28
|
+
it "sets the predicate to true when the boolean value is true" do
|
29
|
+
subject.active = true
|
30
|
+
subject.active?.should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "sets the predicate to false when the boolean value is false" do
|
34
|
+
subject.active = false
|
35
|
+
subject.active?.should be_false
|
36
|
+
end
|
37
|
+
|
38
|
+
it "does not put predicate methods on non-boolean fields" do
|
39
|
+
Test::ResourceFindRequest.new(:name => "resource").should_not respond_to(:name?)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#respond_to_and_has?" do
|
44
|
+
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
45
|
+
|
46
|
+
it "is false when the message does not have the field" do
|
47
|
+
subject.respond_to_and_has?(:other_field).should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "is true when the message has the field" do
|
51
|
+
subject.respond_to_and_has?(:non_default_enum).should be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#respond_to_has_and_present?" do
|
56
|
+
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
57
|
+
|
58
|
+
it "is false when the message does not have the field" do
|
59
|
+
subject.respond_to_and_has_and_present?(:other_field).should be_false
|
60
|
+
end
|
61
|
+
|
62
|
+
it "is false when the field is repeated and a value is not present" do
|
63
|
+
subject.respond_to_and_has_and_present?(:repeated_enums).should be_false
|
64
|
+
end
|
65
|
+
|
66
|
+
it "is false when the field is repeated and the value is empty array" do
|
67
|
+
subject.repeated_enums = []
|
68
|
+
subject.respond_to_and_has_and_present?(:repeated_enums).should be_false
|
69
|
+
end
|
70
|
+
|
71
|
+
it "is true when the field is repeated and a value is present" do
|
72
|
+
subject.repeated_enums = [2]
|
73
|
+
subject.respond_to_and_has_and_present?(:repeated_enums).should be_true
|
74
|
+
end
|
75
|
+
|
76
|
+
it "is true when the message has the field" do
|
77
|
+
subject.respond_to_and_has_and_present?(:non_default_enum).should be_true
|
78
|
+
end
|
79
|
+
|
80
|
+
context "#API" do
|
81
|
+
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
82
|
+
|
83
|
+
it { should respond_to(:respond_to_and_has_and_present?) }
|
84
|
+
it { should respond_to(:responds_to_and_has_and_present?) }
|
85
|
+
it { should respond_to(:responds_to_has?) }
|
86
|
+
it { should respond_to(:respond_to_has?) }
|
87
|
+
it { should respond_to(:respond_to_has_present?) }
|
88
|
+
it { should respond_to(:responds_to_has_present?) }
|
89
|
+
it { should respond_to(:respond_to_and_has_present?) }
|
90
|
+
it { should respond_to(:responds_to_and_has_present?) }
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
23
95
|
describe '#to_hash' do
|
24
96
|
context 'generating values for an ENUM field' do
|
25
97
|
it 'converts the enum to its tag representation' do
|
@@ -23,10 +23,12 @@ class FilterTest
|
|
23
23
|
def self.clear_filters!
|
24
24
|
@defined_filters = nil
|
25
25
|
@filters = nil
|
26
|
+
@rescue_filters = nil
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
30
|
describe Protobuf::Rpc::ServiceFilters do
|
31
|
+
let(:params) { {} }
|
30
32
|
subject { FilterTest.new(params) }
|
31
33
|
after(:each) { FilterTest.clear_filters! }
|
32
34
|
|
@@ -353,4 +355,97 @@ describe Protobuf::Rpc::ServiceFilters do
|
|
353
355
|
end
|
354
356
|
end
|
355
357
|
|
358
|
+
describe '#rescue_from' do
|
359
|
+
before do
|
360
|
+
class CustomError1 < StandardError; end
|
361
|
+
class CustomError2 < StandardError; end
|
362
|
+
class CustomError3 < StandardError; end
|
363
|
+
end
|
364
|
+
|
365
|
+
before do
|
366
|
+
class FilterTest
|
367
|
+
private
|
368
|
+
|
369
|
+
def filter_with_error1
|
370
|
+
@called << :filter_with_error1
|
371
|
+
raise CustomError1, 'Filter 1 failed'
|
372
|
+
end
|
373
|
+
|
374
|
+
def filter_with_error2
|
375
|
+
@called << :filter_with_error2
|
376
|
+
raise CustomError1, 'Filter 2 failed'
|
377
|
+
end
|
378
|
+
|
379
|
+
def filter_with_error3
|
380
|
+
@called << :filter_with_error3
|
381
|
+
raise CustomError3, 'Filter 3 failed'
|
382
|
+
end
|
383
|
+
|
384
|
+
def custom_error_occurred(ex)
|
385
|
+
@ex_class = ex.class
|
386
|
+
@called << :custom_error_occurred
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
let(:params) { { :ex_class => nil } }
|
392
|
+
|
393
|
+
context 'when defining multiple errors with a given callback' do
|
394
|
+
before do
|
395
|
+
FilterTest.rescue_from(CustomError1, CustomError2, CustomError3, :with => :custom_error_occurred)
|
396
|
+
end
|
397
|
+
before { FilterTest.before_filter(:filter_with_error3) }
|
398
|
+
|
399
|
+
it 'short-circuits the call stack' do
|
400
|
+
expect {
|
401
|
+
subject.should_not_receive(:endpoint)
|
402
|
+
subject.__send__(:run_filters, :endpoint)
|
403
|
+
subject.called.should eq([ :filter_with_error3, :custom_error_occurred ])
|
404
|
+
subject.ex_class.should eq CustomError3
|
405
|
+
}.to_not raise_error(CustomError3)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
context 'when defined with options' do
|
410
|
+
context 'when :with option is not given' do
|
411
|
+
specify do
|
412
|
+
expect { FilterTest.rescue_from(CustomError1) }.to raise_error(ArgumentError, /with/)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
context 'when error occurs inside filter' do
|
417
|
+
before { FilterTest.rescue_from(CustomError1, :with => :custom_error_occurred) }
|
418
|
+
before { FilterTest.before_filter(:filter_with_error1) }
|
419
|
+
|
420
|
+
it 'short-circuits the call stack' do
|
421
|
+
expect {
|
422
|
+
subject.should_not_receive(:endpoint)
|
423
|
+
subject.__send__(:run_filters, :endpoint)
|
424
|
+
subject.called.should eq([ :filter_with_error1, :custom_error_occurred ])
|
425
|
+
subject.ex_class.should eq CustomError1
|
426
|
+
}.to_not raise_error(CustomError1)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
context 'when defined with block' do
|
432
|
+
before do
|
433
|
+
FilterTest.rescue_from(CustomError1) do |service, ex|
|
434
|
+
service.ex_class = ex.class
|
435
|
+
service.called << :block_rescue_handler
|
436
|
+
end
|
437
|
+
end
|
438
|
+
before { FilterTest.before_filter(:filter_with_error1) }
|
439
|
+
|
440
|
+
it 'short-circuits the call stack' do
|
441
|
+
expect {
|
442
|
+
subject.should_not_receive(:endpoint)
|
443
|
+
subject.__send__(:run_filters, :endpoint)
|
444
|
+
subject.called.should eq([ :filter_with_error1, :block_rescue_handler ])
|
445
|
+
subject.ex_class.should eq CustomError1
|
446
|
+
}.to_not raise_error(CustomError1)
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
356
451
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protobuf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-11-
|
13
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -516,7 +516,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
516
516
|
version: '0'
|
517
517
|
segments:
|
518
518
|
- 0
|
519
|
-
hash:
|
519
|
+
hash: 510252424392908935
|
520
520
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
521
521
|
none: false
|
522
522
|
requirements:
|
@@ -525,7 +525,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
525
525
|
version: '0'
|
526
526
|
segments:
|
527
527
|
- 0
|
528
|
-
hash:
|
528
|
+
hash: 510252424392908935
|
529
529
|
requirements: []
|
530
530
|
rubyforge_project:
|
531
531
|
rubygems_version: 1.8.24
|