flexirest 1.2.17 → 1.2.18

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: 74460a02097196ff9ac4e73815ad1be63f1664dd
4
- data.tar.gz: 6b138a264aeb07a1012ccfbfbca944f0074f27bf
3
+ metadata.gz: 951a773aca32f3710bae2ee3ed2f4a34c4ee9232
4
+ data.tar.gz: d0857284056ec1f1c6b563e1d67f92c8fcae81bd
5
5
  SHA512:
6
- metadata.gz: cd6868bc4b2de02129bb7078fdd5742a32246ad7275af9d9811dc6f2c2ed005ead6bcc243eff491e6240f05852614dad1899ce529526e21a9c2a6ceb497081cd
7
- data.tar.gz: 94548faeb9a21ce22b6227ef3f3ccf100357f090b71a177b393a893e19c37b7c8113a16f148fe5f26e6750ac5020a2b5b13e6e3a67b7416b7e09343c6ea8ac44
6
+ metadata.gz: 29904f4d2b02428fbb1d056667c3ade2bf42cae9f859e4f328c4cd3ebde47a57160f6c8df00fab0f4967e23cc734bbd26f27e54714b6ebbdb4b46a53986f92fa
7
+ data.tar.gz: bf945048697c7dc7aa235cc4ef4fffe6a5d6260731d806395f413b797f05e95aa4b1d5f1ab9d1b58f02880bf5c53dd3ca5a14bf4dda1a0673eba34d7c4eac522
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.18
4
+
5
+ Features:
6
+
7
+ - Allow nil option in validators (thanks to Jurgen Jocubeit)
8
+ - Added array feature for returning simple scalar values (thanks to Jurgen Jocubeit)
9
+
3
10
  ## 1.2.17
4
11
 
5
12
  Bugfixes:
data/README.md CHANGED
@@ -176,6 +176,34 @@ puts @person.expenses.reduce {|e| e.inc_vat}
176
176
  puts @person.address.full_string
177
177
  ```
178
178
 
179
+ Sometimes we want attributes to just return a simple Ruby Array. To achieve this we can add an `:array` option to the method. This is especially useful when the attribute contains an array of scalar values. If you don't specify the `:array` option Flexirest will return a `Flexirest::ResultIterator`. To illustrate the difference consider the following example:
180
+
181
+ ```ruby
182
+ class Book < Flexirest::Base
183
+ # :authors attribute ["Robert T. Kiyosaki", "Sharon L. Lechter C.P.A"]
184
+ # :genres attribute ["self-help", "finance", "education"]
185
+ get :find, "/books/:name", array: [:authors]
186
+ end
187
+ ```
188
+
189
+ In the example above, the following results can be observed:
190
+
191
+ ```ruby
192
+ @book = Book.find("rich-dad-poor-dad")
193
+ puts @book.authors
194
+ #=> ["Robert T. Kiyosaki", "Sharon L. Lechter C.P.A"]
195
+ puts @book.authors.class
196
+ #=> Array
197
+ puts @book.genres
198
+ #=> #<Flexirest::ResultIterator:0x007ff420fe7a88 @_status=nil, @_headers=nil, @items=["self-help", "finance", "education"]>
199
+ puts @books.genres.class
200
+ #=> Flexirest::ResultIterator
201
+ puts @books.genres.items
202
+ #=> ["self-help", "finance", "education"]
203
+ ```
204
+
205
+ When the `:array` option includes an attribute, it is assumed the values were returned with the request, and they will not be lazily loaded. It is also assumed the attribute values do not map to a Flexirest resource.
206
+
179
207
  #### Association Type 2 - Lazy Loading From Other URLs
180
208
 
181
209
  When mapping the method, passing a list of attributes will cause any requests for those attributes to mapped to the URLs given in their responses. The response for the attribute may be one of the following:
@@ -773,6 +801,54 @@ Validations are run when calling `valid?` or when calling any API on an instance
773
801
 
774
802
  `full_error_messages` returns an array of attributes with their associated error messages, i.e. `["age must be at least 18"]`
775
803
 
804
+ #### Permitting nil values
805
+ The default behavior for `:length`, `:numericality` and `:inclusion` validators is to fail when a `nil` value is encountered. You can prevent `nil` attribute values from triggering validation errors for attributes that may permit `nil` by adding the `:allow_nil => true` option. Adding this option with a `true` value to `:length`, `:numericality` and `:inclusion` validators will permit `nil` values and not trigger errors. Some examples are:
806
+
807
+ ```ruby
808
+ class Person < Flexirest::Base
809
+ validates :first_name, presence: true
810
+ validates :middle_name, length: { minimum: 2, maximum: 30 }, allow_nil: true
811
+ validates :last_name, existence: true
812
+ validates :nick_name, length: { minimum: 2, maximum: 30 }
813
+ validates :alias, length: { minimum: 2, maximum: 30 }, allow_nil: false
814
+ validates :password, length: { within: 6..12 }
815
+ validates :post_code, length: { minimum: 6, maximum: 8 }
816
+ validates :salary, numericality: true, minimum: 20_000, maximum: 50_000
817
+ validates :age, numericality: { minimum: 18, maximum: 65 }
818
+ validates :suffix, inclusion: { in: %w{Dr. Mr. Mrs. Ms.}}
819
+ validates :golf_score, numericality: true, allow_nil: true
820
+ validates :retirement_age, numericality: { minimum: 65 }, allow_nil: true
821
+ validates :cars_owned, numericality: true
822
+ validates :houses_owned, numericality: true, allow_nil: false
823
+ validates :favorite_authors, inclusion: { in: ["George S. Klason", "Robert T. Kiyosaki", "Lee Child"] }, allow_nil: true
824
+ validates :favorite_artists, inclusion: { in: ["Claude Monet", "Vincent Van Gogh", "Andy Warhol"] }
825
+ validates :favorite_composers, inclusion: { in: ["Mozart", "Bach", "Pachelbel", "Beethoven"] }, allow_nil: false
826
+ end
827
+ ```
828
+
829
+ In the example above, the following results would occur when calling `valid?` on an instance where all attributes have `nil` values:
830
+
831
+ - `:first_name` must be present
832
+ - `:last_name` must be not be nil
833
+ - `:nick_name` must be not be nil
834
+ - `:alias` must not be nil
835
+ - `:password` must not be nil
836
+ - `:post_code` must not be nil
837
+ - `:salary` must not be nil
838
+ - `:age` must not be nil
839
+ - `:suffix` must not be nil
840
+ - `:cars_owned` must not be nil
841
+ - `:houses_owned` must not be nil
842
+ - `:favorite_artists` must not be nil
843
+ - `:favorite_composers` must not be nil
844
+
845
+ The following attributes will pass validation since they explicitly `allow_nil`:
846
+
847
+ - `:middle_name`
848
+ - `:golf_score`
849
+ - `:retirement_age`
850
+ - `:favorite_authors`
851
+
776
852
  ### Debugging
777
853
 
778
854
  You can turn on verbose debugging to see what is sent to the API server and what is returned in one of these two ways:
@@ -13,8 +13,9 @@ module Flexirest
13
13
  @method = method
14
14
  @method[:options] ||= {}
15
15
  @method[:options][:lazy] ||= []
16
+ @method[:options][:array] ||= []
16
17
  @method[:options][:has_one] ||= {}
17
- @overridden_name = @method[:options][:overridden_name]
18
+ @overridden_name = @method[:options][:overridden_name]
18
19
  @object = object
19
20
  @response_delegate = Flexirest::RequestDelegator.new(nil)
20
21
  @params = params
@@ -440,7 +441,11 @@ module Flexirest
440
441
  elsif v.is_a? Hash
441
442
  object._attributes[k] = new_object(v, overridden_name )
442
443
  elsif v.is_a? Array
443
- object._attributes[k] = Flexirest::ResultIterator.new
444
+ if @method[:options][:array].include?(k)
445
+ object._attributes[k] = Array.new
446
+ else
447
+ object._attributes[k] = Flexirest::ResultIterator.new
448
+ end
444
449
  v.each do |item|
445
450
  if item.is_a? Hash
446
451
  object._attributes[k] << new_object(item, overridden_name)
@@ -514,7 +519,7 @@ module Flexirest
514
519
  if @method[:options][:has_many][name] || @method[:options][:has_one][name]
515
520
  return name
516
521
  end
517
-
522
+
518
523
  parent_name || name
519
524
  end
520
525
 
@@ -20,6 +20,7 @@ module Flexirest
20
20
  @errors = Hash.new {|h,k| h[k] = []}
21
21
  self.class._validations.each do |validation|
22
22
  value = self.send(validation[:field_name])
23
+ allow_nil = validation[:options].fetch(:allow_nil, false)
23
24
  validation[:options].each do |type, options|
24
25
  if type == :presence
25
26
  if value.nil?
@@ -32,35 +33,55 @@ module Flexirest
32
33
  @errors[validation[:field_name]] << "must be not be nil"
33
34
  end
34
35
  elsif type == :length
35
- if options[:within]
36
- @errors[validation[:field_name]] << "must be within range #{options[:within]}" unless options[:within].include?(value.to_s.length )
37
- end
38
- if options[:minimum]
39
- @errors[validation[:field_name]] << "must be at least #{options[:minimum]} characters long" unless value.to_s.length >= options[:minimum]
40
- end
41
- if options[:maximum]
42
- @errors[validation[:field_name]] << "must be no more than #{options[:maximum]} characters long" unless value.to_s.length <= options[:maximum]
36
+ if value.nil?
37
+ @errors[validation[:field_name]] << "must be not be nil" unless allow_nil
38
+ else
39
+ if options[:within]
40
+ @errors[validation[:field_name]] << "must be within range #{options[:within]}" unless options[:within].include?(value.to_s.length )
41
+ end
42
+ if options[:minimum]
43
+ @errors[validation[:field_name]] << "must be at least #{options[:minimum]} characters long" unless value.to_s.length >= options[:minimum]
44
+ end
45
+ if options[:maximum]
46
+ @errors[validation[:field_name]] << "must be no more than #{options[:maximum]} characters long" unless value.to_s.length <= options[:maximum]
47
+ end
43
48
  end
44
49
  elsif type == :numericality
45
- numeric = (true if Float(value) rescue false)
46
- if !numeric
47
- @errors[validation[:field_name]] << "must be numeric"
50
+ if value.nil?
51
+ @errors[validation[:field_name]] << "must be not be nil" unless allow_nil
48
52
  else
49
- if options.is_a?(Hash)
50
- if options[:minimum]
51
- @errors[validation[:field_name]] << "must be at least #{options[:minimum]}" unless value.to_f >= options[:minimum]
52
- end
53
- if options[:maximum]
54
- @errors[validation[:field_name]] << "must be no more than #{options[:maximum]}" unless value.to_f <= options[:maximum]
53
+ numeric = (true if Float(value) rescue false)
54
+ if !numeric
55
+ @errors[validation[:field_name]] << "must be numeric"
56
+ else
57
+ if options.is_a?(Hash)
58
+ if options[:minimum]
59
+ @errors[validation[:field_name]] << "must be at least #{options[:minimum]}" unless value.to_f >= options[:minimum]
60
+ end
61
+ if options[:maximum]
62
+ @errors[validation[:field_name]] << "must be no more than #{options[:maximum]}" unless value.to_f <= options[:maximum]
63
+ end
55
64
  end
56
65
  end
57
66
  end
58
- elsif type == :minimum && !value.nil?
59
- @errors[validation[:field_name]] << "must be at least #{options}" unless value.to_f >= options.to_f
60
- elsif type == :maximum && !value.nil?
61
- @errors[validation[:field_name]] << "must be no more than #{options}" unless value.to_f <= options.to_f
67
+ elsif type == :minimum
68
+ if value.nil?
69
+ @errors[validation[:field_name]] << "must be not be nil" unless allow_nil
70
+ else
71
+ @errors[validation[:field_name]] << "must be at least #{options}" unless value.to_f >= options.to_f
72
+ end
73
+ elsif type == :maximum
74
+ if value.nil?
75
+ @errors[validation[:field_name]] << "must be not be nil" unless allow_nil
76
+ else
77
+ @errors[validation[:field_name]] << "must be no more than #{options}" unless value.to_f <= options.to_f
78
+ end
62
79
  elsif type == :inclusion
63
- @errors[validation[:field_name]] << "must be included in #{options[:in].join(", ")}" unless options[:in].include?(value)
80
+ if value.nil?
81
+ @errors[validation[:field_name]] << "must be not be nil" unless allow_nil
82
+ else
83
+ @errors[validation[:field_name]] << "must be included in #{options[:in].join(", ")}" unless options[:in].include?(value)
84
+ end
64
85
  end
65
86
  end
66
87
  if validation[:block]
@@ -1,3 +1,3 @@
1
1
  module Flexirest
2
- VERSION = "1.2.17"
2
+ VERSION = "1.2.18"
3
3
  end
@@ -22,6 +22,7 @@ describe Flexirest::Request do
22
22
  end
23
23
 
24
24
  get :all, "/", :has_many => {:expenses => ExampleOtherClient}
25
+ get :array, "/johnny", array: [:likes, :dislikes]
25
26
  get :babies, "/babies", :has_many => {:children => ExampleOtherClient}
26
27
  get :single_association, "/single", :has_one => {:single => ExampleSingleClient}, :has_many => {:children => ExampleOtherClient}
27
28
  get :headers, "/headers"
@@ -261,6 +262,21 @@ describe Flexirest::Request do
261
262
  expect(object[1].first_name).to eq("Billy")
262
263
  expect(object._status).to eq(200)
263
264
  end
265
+
266
+ it "should parse an attribute to be an array if attribute included in array option" do
267
+ expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/johnny", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"Johnny\", \"likes\":[\"donuts\", \"bacon\"], \"dislikes\":[\"politicians\", \"lawyers\", \"taxes\"]}", status:200, response_headers:{})))
268
+ object = ExampleClient.array
269
+ expect(object.likes).to be_instance_of(Array)
270
+ expect(object.likes.size).to eq(2)
271
+ expect(object.likes[0]).to eq("donuts")
272
+ expect(object.likes[1]).to eq("bacon")
273
+ expect(object.dislikes).to be_instance_of(Array)
274
+ expect(object.dislikes.size).to eq(3)
275
+ expect(object.dislikes[0]).to eq("politicians")
276
+ expect(object.dislikes[1]).to eq("lawyers")
277
+ expect(object.dislikes[2]).to eq("taxes")
278
+ #TODO
279
+ end
264
280
 
265
281
  it "should instantiate other classes using has_many when required to do so" do
266
282
  expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"Johnny\", \"expenses\":[{\"amount\":1}, {\"amount\":2}]}", status:200, response_headers:{})))
@@ -4,20 +4,29 @@ describe "Flexirest::Validation" do
4
4
  class SimpleValidationExample < OpenStruct
5
5
  include Flexirest::Validation
6
6
  validates :first_name, presence: true
7
+ validates :middle_name, length: { minimum: 2, maximum: 30 }, allow_nil: true
7
8
  validates :last_name, existence: true
9
+ validates :nick_name, length: { minimum: 2, maximum: 30 }
10
+ validates :alias, length: { minimum: 2, maximum: 30 }, allow_nil: false
8
11
  validates :password, length: { within: 6..12 }
9
12
  validates :post_code, length: { minimum: 6, maximum: 8 }
10
13
  validates :salary, numericality: true, minimum: 20_000, maximum: 50_000
11
14
  validates :age, numericality: { minimum: 18, maximum: 65 }
12
15
  validates :suffix, inclusion: { in: %w{Dr. Mr. Mrs. Ms.}}
16
+ validates :golf_score, numericality: true, allow_nil: true
17
+ validates :retirement_age, numericality: { minimum: 65 }, allow_nil: true
18
+ validates :cars_owned, numericality: true
19
+ validates :houses_owned, numericality: true, allow_nil: false
20
+ validates :favorite_authors, inclusion: { in: ["George S. Klason", "Robert T. Kiyosaki", "Lee Child"] }, allow_nil: true
21
+ validates :favorite_artists, inclusion: { in: ["Claude Monet", "Vincent Van Gogh", "Andy Warhol"] }
22
+ validates :favorite_composers, inclusion: { in: ["Mozart", "Bach", "Pachelbel", "Beethoven"] }, allow_nil: false
13
23
  end
14
24
 
15
25
  it "should be able to register a validation" do
16
- expect(SimpleValidationExample._validations.size).to eq(7)
26
+ expect(SimpleValidationExample._validations.size).to eq(17)
17
27
  end
18
28
 
19
29
  context "when validating presence" do
20
-
21
30
  it "should be invalid if a required value isn't present" do
22
31
  a = SimpleValidationExample.new
23
32
  a.first_name = nil
@@ -107,6 +116,24 @@ describe "Flexirest::Validation" do
107
116
  a.valid?
108
117
  expect(a._errors[:post_code].size).to eq(1)
109
118
  end
119
+
120
+ it "should be valid if a length is nil and allow_nil option is true" do
121
+ a = SimpleValidationExample.new
122
+ a.valid?
123
+ expect(a._errors[:middle_name]).to be_empty
124
+ end
125
+
126
+ it "should be invalid if a length is nil and allow_nil option is not provided" do
127
+ a = SimpleValidationExample.new
128
+ a.valid?
129
+ expect(a._errors[:nick_name].size).to eq(1)
130
+ end
131
+
132
+ it "should be invalid if a length is nil and allow_nil option is false" do
133
+ a = SimpleValidationExample.new
134
+ a.valid?
135
+ expect(a._errors[:alias].size).to eq(1)
136
+ end
110
137
  end
111
138
 
112
139
 
@@ -136,6 +163,29 @@ describe "Flexirest::Validation" do
136
163
  expect(a._errors[:salary].size).to eq(0)
137
164
  end
138
165
 
166
+ it "should be valid if a value is nil and allow_nil option is true" do
167
+ a = SimpleValidationExample.new
168
+ a.valid?
169
+ expect(a._errors[:golf_score]).to be_empty
170
+ end
171
+
172
+ it "should be valid if a value is nil and allow_nil option is true and a hash of options is passed to numericality" do
173
+ a = SimpleValidationExample.new
174
+ a.valid?
175
+ expect(a._errors[:retirement_age]).to be_empty
176
+ end
177
+
178
+ it "should be invalid if a value is nil and allow_nil option is not provided" do
179
+ a = SimpleValidationExample.new
180
+ a.valid?
181
+ expect(a._errors[:cars_owned].size).to eq(1)
182
+ end
183
+
184
+ it "should be invalid if a value is nil and allow_nil option is false" do
185
+ a = SimpleValidationExample.new
186
+ a.valid?
187
+ expect(a._errors[:houses_owned].size).to eq(1)
188
+ end
139
189
  end
140
190
 
141
191
  context "using the original format with min and max as types" do
@@ -162,7 +212,6 @@ describe "Flexirest::Validation" do
162
212
  a.valid?
163
213
  expect(a._errors[:age].size).to eq(0)
164
214
  end
165
-
166
215
  end
167
216
  end
168
217
 
@@ -178,6 +227,24 @@ describe "Flexirest::Validation" do
178
227
  a.valid?
179
228
  expect(a._errors[:suffix].size).to eq(0)
180
229
  end
230
+
231
+ it "should be valid if the value is nil and allow_nil option is true" do
232
+ a = SimpleValidationExample.new
233
+ a.valid?
234
+ expect(a._errors[:favorite_authors]).to be_empty
235
+ end
236
+
237
+ it "should be invalid if the value is nil and allow_nil option is not provided" do
238
+ a = SimpleValidationExample.new
239
+ a.valid?
240
+ expect(a._errors[:favorite_artists].size).to eq(1)
241
+ end
242
+
243
+ it "should be invalid if the value is nil and allow_nil option is false" do
244
+ a = SimpleValidationExample.new
245
+ a.valid?
246
+ expect(a._errors[:favorite_composers].size).to eq(1)
247
+ end
181
248
  end
182
249
 
183
250
  context "when passing a block" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flexirest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.17
4
+ version: 1.2.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jeffries
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-05 00:00:00.000000000 Z
11
+ date: 2016-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler