protip 0.11.2 → 0.12.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.
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