protobuf 2.1.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|