protip 0.11.2 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ab7e84f6fd394d2b5cb52c67d1a5db5f245c36a
4
- data.tar.gz: 4726d4e87f0453b0c2bd0bc55c2ac52ff23c58e3
3
+ metadata.gz: c275589cac97c73b2b4405fca77fe0c0c93a94af
4
+ data.tar.gz: 659c9ec2117a91a5d6e1e0fdff7c0b5ef91e9586
5
5
  SHA512:
6
- metadata.gz: 4721c4d9f10135735502dccfb105532d4b6b31a74dcda08b1298bb0cc9bec791897c90002997c826cf399fb3953018bfdab5f5e62710834ccf99a21d5a5c458f
7
- data.tar.gz: cde835698f8a9feb4eb3743b7c3bfdd5ab2bb0e42d0963cb0ebd1849aa96640d6f2169db6302901ca1a4e4e33c5385ce16ae2e86efb674672dbbb5ff1114aa28
6
+ metadata.gz: 48c71ba8914797e87a10363fda5c73bc1a02cc5f7a9889f86658251314489808ce733982c3104639f821b24a068708f6fb3df446c855e66e886e9fbd59a5ccb8
7
+ data.tar.gz: b567785146d15ef596bf19dffebc73f340120112821d7aca826c8f0431162e86a99bdf8429837ac6c772e9a29b0fc21fd9aa4c7d6ab866a24a9df56b3ba05f6a
@@ -165,6 +165,9 @@ module Protip
165
165
  @message.descriptor.each do |field|
166
166
  def_delegator :@wrapper, :"#{field.name}"
167
167
  def_delegator :@wrapper, :"#{field.name}="
168
+ if ::Protip::Wrapper.matchable?(field)
169
+ def_delegator :@wrapper, :"#{field.name}?"
170
+ end
168
171
  end
169
172
 
170
173
  # Validate arguments
@@ -17,10 +17,10 @@ module Protip
17
17
  if super
18
18
  true
19
19
  else
20
- if name =~ /=$/
21
- message.class.descriptor.any?{|field| :"#{field.name}=" == name.to_sym}
22
- else
23
- message.class.descriptor.any?{|field| field.name.to_sym == name.to_sym}
20
+ message.class.descriptor.any? do |field|
21
+ # getter, setter, and in the scalar enum case, query method
22
+ regex = /^#{field.name}[=#{self.class.matchable?(field) ? '\\?' : ''}]?$/
23
+ name.to_s =~ regex
24
24
  end
25
25
  end
26
26
  end
@@ -29,6 +29,9 @@ module Protip
29
29
  if (name =~ /=$/ && field = message.class.descriptor.detect{|field| :"#{field.name}=" == name})
30
30
  raise ArgumentError unless args.length == 1
31
31
  set field, args[0]
32
+ elsif (name =~ /\?$/ && field = message.class.descriptor.detect{|field| self.class.matchable?(field) && :"#{field.name}?" == name})
33
+ raise ArgumentError unless args.length == 1
34
+ matches? field, args[0]
32
35
  elsif (field = message.class.descriptor.detect{|field| field.name.to_sym == name})
33
36
  raise ArgumentError unless args.length == 0
34
37
  get field
@@ -135,6 +138,14 @@ module Protip
135
138
  converter == wrapper.converter
136
139
  end
137
140
 
141
+ class << self
142
+ # Semi-private check for whether a field should have an associated query method (e.g. +field_name?+).
143
+ # @return [Boolean] Whether the field should have an associated query method on wrappers.
144
+ def matchable?(field)
145
+ field.type == :enum && field.label != :repeated
146
+ end
147
+ end
148
+
138
149
  private
139
150
 
140
151
  def get(field)
@@ -184,5 +195,18 @@ module Protip
184
195
  value
185
196
  end
186
197
  end
198
+
199
+ def matches?(field, value)
200
+ enum = field.subtype
201
+ if value.is_a?(Fixnum)
202
+ sym = enum.lookup_value(value)
203
+ else
204
+ sym = value.to_sym
205
+ sym = nil if (nil == enum.lookup_name(sym))
206
+ end
207
+ raise RangeError.new("#{field} has no value #{value}") if nil == sym
208
+ get(field) == sym
209
+
210
+ end
187
211
  end
188
212
  end
data/test/test_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  require 'minitest/autorun'
2
2
  require 'mocha/mini_test'
3
3
  require 'webmock/minitest'
4
+
5
+ require 'minitest/pride'
@@ -9,6 +9,10 @@ module Protip::ResourceTest # Namespace for internal constants
9
9
  let :pool do
10
10
  pool = Google::Protobuf::DescriptorPool.new
11
11
  pool.build do
12
+ add_enum 'number' do
13
+ value :ZERO, 0
14
+ value :ONE, 1
15
+ end
12
16
  add_message 'nested_message' do
13
17
  optional :number, :int64, 1
14
18
  end
@@ -17,6 +21,8 @@ module Protip::ResourceTest # Namespace for internal constants
17
21
  optional :string, :string, 2
18
22
  optional :string2, :string, 3
19
23
  optional :nested_message, :message, 4, 'nested_message'
24
+ optional :number, :enum, 5, 'number'
25
+ repeated :numbers, :enum, 6, 'number'
20
26
  end
21
27
 
22
28
  add_message 'resource_query' do
@@ -124,6 +130,29 @@ module Protip::ResourceTest # Namespace for internal constants
124
130
  assert_equal nested_message_class.new(number: 100), resource.message.nested_message, 'object was not converted'
125
131
  assert_equal 'intern', resource.nested_message, 'message was not converted'
126
132
  end
133
+
134
+ describe '(query methods)' do
135
+ let(:resource) { resource_class.new }
136
+ it 'defines query methods for the scalar enums on its message' do
137
+ assert_respond_to resource, :number?
138
+ assert resource.number?(:ZERO)
139
+ refute resource.number?(:ONE)
140
+ end
141
+
142
+ it 'does not define query methods for repeated enums' do
143
+ refute_respond_to resource, :numbers?
144
+ assert_raises NoMethodError do
145
+ resource.numbers?(:ZERO)
146
+ end
147
+ end
148
+
149
+ it 'does not define query methods for non-enum fields' do
150
+ refute_respond_to resource, :inner?
151
+ assert_raises NoMethodError do
152
+ resource.inner?(:ZERO)
153
+ end
154
+ end
155
+ end
127
156
  end
128
157
 
129
158
  # index/find/member/collection actions should all convert more complex Ruby objects to submessages in their
@@ -14,6 +14,11 @@ module Protip::WrapperTest # namespace for internal constants
14
14
  let :pool do
15
15
  pool = Google::Protobuf::DescriptorPool.new
16
16
  pool.build do
17
+ add_enum 'number' do
18
+ value :ZERO, 0
19
+ value :ONE, 1
20
+ value :TWO, 2
21
+ end
17
22
  add_message 'inner_message' do
18
23
  optional :value, :int64, 1
19
24
  optional :note, :string, 2
@@ -27,6 +32,9 @@ module Protip::WrapperTest # namespace for internal constants
27
32
  repeated :strings, :string, 4
28
33
 
29
34
  optional :inner_blank, :message, 5, 'inner_message'
35
+
36
+ optional :number, :enum, 6, 'number'
37
+ repeated :numbers, :enum, 7, 'number'
30
38
  end
31
39
  end
32
40
  pool
@@ -57,12 +65,32 @@ module Protip::WrapperTest # namespace for internal constants
57
65
  assert_respond_to wrapper, :inner
58
66
  assert_respond_to wrapper, :inner_blank
59
67
  end
68
+ it 'adds queries for scalar enum fields' do
69
+ assert_respond_to wrapper, :number?
70
+ end
71
+ it 'does not add queries for repeated enum fields' do
72
+ refute_respond_to wrapper, :numbers?
73
+ end
74
+ it 'does not add queries for non-enum fields' do
75
+ refute_respond_to wrapper, :inner?
76
+ end
60
77
  it 'responds to standard defined methods' do
61
78
  assert_respond_to wrapper, :as_json
62
79
  end
63
- it 'does not add other setters/getters' do
80
+ it 'does not add other setters/getters/queries' do
64
81
  refute_respond_to wrapper, :foo=
65
82
  refute_respond_to wrapper, :foo
83
+ refute_respond_to wrapper, :foo?
84
+ end
85
+ it 'does not add methods which partially match message fields' do
86
+ refute_respond_to wrapper, :xinner
87
+ refute_respond_to wrapper, :xinner=
88
+ refute_respond_to wrapper, :xnumber?
89
+ refute_respond_to wrapper, :innerx
90
+ refute_respond_to wrapper, :innerx=
91
+ refute_respond_to wrapper, :'inner=x'
92
+ refute_respond_to wrapper, :numberx?
93
+ refute_respond_to wrapper, :'number?x'
66
94
  end
67
95
  end
68
96
 
@@ -256,7 +284,7 @@ module Protip::WrapperTest # namespace for internal constants
256
284
  end
257
285
 
258
286
  it 'contains keys for all fields of the parent message' do
259
- assert_equal %i(string strings inner inners inner_blank).sort, wrapper.to_h.keys.sort
287
+ assert_equal %i(string strings inner inners inner_blank number numbers).sort, wrapper.to_h.keys.sort
260
288
  end
261
289
  it 'assigns nil for missing nested messages' do
262
290
  hash = wrapper.to_h
@@ -344,6 +372,66 @@ module Protip::WrapperTest # namespace for internal constants
344
372
  wrapper.inner = inner_message_class.new(value: 50)
345
373
  assert_equal inner_message_class.new(value: 50), wrapper.message.inner
346
374
  end
375
+
376
+ it 'raises an error when setting an enum field to an undefined value' do
377
+ assert_raises RangeError do
378
+ wrapper.number = :NAN
379
+ end
380
+ end
381
+ end
382
+
383
+ describe '#matches?' do
384
+ it 'is not defined for non-enum fields' do
385
+ assert_raises NoMethodError do
386
+ wrapper.inner?(:test)
387
+ end
388
+ end
389
+
390
+ it 'is not defined for repeated enum fields' do
391
+ assert_raises NoMethodError do
392
+ wrapper.numbers?(:test)
393
+ end
394
+ end
395
+
396
+ describe 'when given a Fixnum' do
397
+ before do
398
+ wrapper.number = :ONE
399
+ end
400
+ it 'returns true when the number matches the value' do
401
+ assert wrapper.number?(1)
402
+ end
403
+ it 'returns false when the number does not match the value' do
404
+ refute wrapper.number?(0)
405
+ end
406
+ it 'raises an error when the number is not a valid value for the enum' do
407
+ assert_raises RangeError do
408
+ wrapper.number?(3)
409
+ end
410
+ end
411
+ end
412
+
413
+ describe 'when given a non-Fixnum' do
414
+ before do
415
+ wrapper.number = :TWO
416
+ end
417
+ it 'returns true when its symbolized argument matches the value' do
418
+ m = mock
419
+ m.expects(:to_sym).returns :TWO
420
+ assert wrapper.number?(m)
421
+ end
422
+ it 'returns false when its symbolized argument does not match the value' do
423
+ m = mock
424
+ m.expects(:to_sym).returns :ONE
425
+ refute wrapper.number?(m)
426
+ end
427
+ it 'raises an error when its symbolized argument is not a valid value for the enum' do
428
+ m = mock
429
+ m.expects(:to_sym).returns :NAN
430
+ assert_raises RangeError do
431
+ wrapper.number?(m)
432
+ end
433
+ end
434
+ end
347
435
  end
348
436
  end
349
437
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.2
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - AngelList
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-17 00:00:00.000000000 Z
11
+ date: 2015-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel