flexirest 1.2.1 → 1.2.2

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: 4da568b8c28266cae1d7a558ac054680514a16f6
4
- data.tar.gz: bedf4e0b825d1fb5847b4342bfc2c1fa2b8604e4
3
+ metadata.gz: f549201f0bdade7d62e8972d7015cdf04f0f2aaa
4
+ data.tar.gz: b5ed62790c87fd8253bdb1d18bca02dfcbc8331c
5
5
  SHA512:
6
- metadata.gz: ffc0a1c9d7115f009e1ae929784ce54accd3a904e8d5a040841959ace5d08e21b85c126650f43b09032aa6a365a3ec66d45b45dc50a0685f01f2d9cd07cffa49
7
- data.tar.gz: 7414812a6efe50781c389235154a1b6971306cb316c5be20b5c60858946946d860c3487cb79468edb9df7c4e30ed8cee9c01e7489b1798602ec66650887be70a
6
+ metadata.gz: 4b6d0e9794750161edab543b97aec47a956f3bc570fa65e35c5216ed857fa8ed7830c661ce1fbc0092d0743298c68fc0734db9d38932597a9d3470d5164036a9
7
+ data.tar.gz: 5297d2f938e3777a5264212465270792dbe7202f758d5c4cfa572ad7e6fa32fc244f66931623933e8bbc0cd7a62ac5202051245c2cd4b10fdfffbdf3216e6140
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.2
4
+
5
+ Features:
6
+
7
+ - Adds `existence`, `numericality`, `presence` and `inclusion` validations (thanks Tom Hoen)
8
+ - Adds `full_error_messages` method (thanks Tom Hoen)
9
+ - Adds `requires` options to the method mapping
10
+
11
+ ## 1.2.1
12
+
13
+ **Forked Which's ActiveRestClient to be Flexirest**
14
+
3
15
  ## 1.2.0
4
16
 
5
17
  Features:
data/README.md CHANGED
@@ -241,8 +241,8 @@ end
241
241
  You can then access Ads by specifying their magazine IDs:
242
242
 
243
243
  ```ruby
244
- Add.all(magazine_id: 1)
245
- Add.create(magazine_id: 1, title: "My Add Title")
244
+ Ad.all(magazine_id: 1)
245
+ Ad.create(magazine_id: 1, title: "My Add Title")
246
246
  ```
247
247
 
248
248
  #### Combined Example
@@ -708,6 +708,19 @@ end
708
708
  @people = Person.all(active:false)
709
709
  ```
710
710
 
711
+ ### Required Parameters
712
+
713
+ If you want to specify that certain parameters are required for a specific call, you can specify them like:
714
+
715
+ ```ruby
716
+ class Person < Flexirest::Base
717
+ get :all, '/people', :requires => [:active]
718
+ end
719
+
720
+ @people = Person.all # raises Flexirest::MissingParametersException
721
+ @people = Person.all(active:false)
722
+ ```
723
+
711
724
  ### HTTP/Parse Error Handling
712
725
 
713
726
  Sometimes the backend server may respond with a non-200/304 header, in which case the code will raise an `Flexirest::HTTPClientException` for 4xx errors or an `Flexirest::HTTPServerException` for 5xx errors. These both have a `status` accessor and a `result` accessor (for getting access to the parsed body):
@@ -728,10 +741,13 @@ You can create validations on your objects just like Rails' built in ActiveModel
728
741
 
729
742
  ```ruby
730
743
  class Person < Flexirest::Base
731
- validates :first_name, presence:true
732
- validates :password, length:{within:6..12}
733
- validates :post_code, length:{minimum:6, maximum:8}
734
- validates :salary, numericality:true, minimum:20_000, maximum:50_000
744
+ validates :first_name, presence: true #ensures that the value is present and not blank
745
+ validates :last_name, existence: true #ensures that the value is non-nil only
746
+ validates :password, length: {within:6..12}
747
+ validates :post_code, length: {minimum:6, maximum:8}
748
+ validates :salary, numericality: true, minimum: 20_000, maximum: 50_000
749
+ validates :age, numericality: { minumum: 18, maximum: 65 }
750
+ validates :suffix, inclusion: { in: %w{Dr. Mr. Mrs. Ms.}}
735
751
 
736
752
  validates :first_name do |object, name, value|
737
753
  object.errors[name] << "must be over 4 chars long" if value.length <= 4
@@ -745,6 +761,8 @@ Note the block based validation is responsible for adding errors to `object.erro
745
761
 
746
762
  Validations are run when calling `valid?` or when calling any API on an instance (and then only if it is `valid?` will the API go on to be called).
747
763
 
764
+ `full_error_messages` returns an array of attributes with their associated error messages, i.e. `["age must be at least 18"]`
765
+
748
766
  ### Debugging
749
767
 
750
768
  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:
@@ -225,6 +225,20 @@ module Flexirest
225
225
  @post_params = default_params.merge(params || {})
226
226
  @get_params = {}
227
227
  end
228
+
229
+ if @method[:options][:requires]
230
+ requires = @method[:options][:requires].dup
231
+ merged_params = @get_params.merge(@post_params || {})
232
+ missing = []
233
+ requires.each do |key|
234
+ if merged_params[key.to_sym].blank? && ![true, false].include?(merged_params[key.to_sym])
235
+ missing << key
236
+ end
237
+ end
238
+ if missing.any?
239
+ raise Flexirest::MissingParametersException.new("The following parameters weren't specifed: #{missing.join(", ")}")
240
+ end
241
+ end
228
242
  end
229
243
 
230
244
  def prepare_url
@@ -547,6 +561,7 @@ module Flexirest
547
561
  class RequestException < StandardError ; end
548
562
 
549
563
  class InvalidRequestException < RequestException ; end
564
+ class MissingParametersException < RequestException ; end
550
565
  class ResponseParseException < RequestException
551
566
  attr_accessor :status, :body
552
567
  def initialize(options)
@@ -24,7 +24,13 @@ module Flexirest
24
24
  if type == :presence
25
25
  if value.nil?
26
26
  @errors[validation[:field_name]] << "must be present"
27
+ elsif value.blank?
28
+ @errors[validation[:field_name]] << "must be present"
27
29
  end
30
+ elsif type == :existence
31
+ if value.nil?
32
+ @errors[validation[:field_name]] << "must be not be nil"
33
+ end
28
34
  elsif type == :length
29
35
  if options[:within]
30
36
  @errors[validation[:field_name]] << "must be within range #{options[:within]}" unless options[:within].include?(value.to_s.length )
@@ -37,11 +43,24 @@ module Flexirest
37
43
  end
38
44
  elsif type == :numericality
39
45
  numeric = (true if Float(value) rescue false)
40
- @errors[validation[:field_name]] << "must be numeric" unless numeric
46
+ if !numeric
47
+ @errors[validation[:field_name]] << "must be numeric"
48
+ 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[:minimum]}" unless value.to_f <= options[:maximum]
55
+ end
56
+ end
57
+ end
41
58
  elsif type == :minimum && !value.nil?
42
59
  @errors[validation[:field_name]] << "must be at least #{options}" unless value.to_f >= options.to_f
43
60
  elsif type == :maximum && !value.nil?
44
61
  @errors[validation[:field_name]] << "must be no more than #{options}" unless value.to_f <= options.to_f
62
+ elsif type == :inclusion
63
+ @errors[validation[:field_name]] << "must be included in #{options[:in].join(", ")}" unless options[:in].include?(value)
45
64
  end
46
65
  end
47
66
  if validation[:block]
@@ -51,6 +70,13 @@ module Flexirest
51
70
  @errors.empty?
52
71
  end
53
72
 
73
+ def full_error_messages
74
+ return "" unless _errors.present?
75
+ _errors.reduce([]) do |memo, (field, errors)|
76
+ memo << "#{field.to_s} #{errors.join(' and ')}"
77
+ end
78
+ end
79
+
54
80
  def _errors
55
81
  @errors ||= Hash.new {|h,k| h[k] = []}
56
82
  @errors
@@ -1,3 +1,3 @@
1
1
  module Flexirest
2
- VERSION = "1.2.1"
2
+ VERSION = "1.2.2"
3
3
  end
@@ -37,6 +37,7 @@ describe Flexirest::Request do
37
37
  get :fake, "/fake", fake:"{\"result\":true, \"list\":[1,2,3,{\"test\":true}], \"child\":{\"grandchild\":{\"test\":true}}}"
38
38
  get :fake_proc, "/fake", fake:->(request) { "{\"result\":#{request.get_params[:id]}}" }
39
39
  get :defaults, "/defaults", defaults:{overwrite:"no", persist:"yes"}
40
+ get :requires, "/requires", requires:[:name, :age]
40
41
  end
41
42
 
42
43
  class AuthenticatedExampleClient < Flexirest::Base
@@ -113,6 +114,24 @@ describe Flexirest::Request do
113
114
  ExampleClient.defaults overwrite:"yes"
114
115
  end
115
116
 
117
+ it "should ensure any required parameters are specified" do
118
+ expect_any_instance_of(Flexirest::Connection).to_not receive(:get)
119
+ expect{ExampleClient.requires}.to raise_error(Flexirest::MissingParametersException)
120
+ expect{ExampleClient.requires name: "John"}.to raise_error(Flexirest::MissingParametersException)
121
+ expect{ExampleClient.requires age: 21}.to raise_error(Flexirest::MissingParametersException)
122
+ expect{ExampleClient.requires name: nil, age: nil}.to raise_error(Flexirest::MissingParametersException)
123
+ end
124
+
125
+ it "should makes the request if all required parameters are specified" do
126
+ expect_any_instance_of(Flexirest::Connection).to receive(:get).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
127
+ expect{ExampleClient.requires name: "John", age: 21}.not_to raise_error
128
+ end
129
+
130
+ it "should makes the request if all required parameters are specified, even if boolean" do
131
+ expect_any_instance_of(Flexirest::Connection).to receive(:get).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
132
+ expect{ExampleClient.requires name: true, age: false}.not_to raise_error
133
+ end
134
+
116
135
  it "should pass through url parameters" do
117
136
  expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/1234", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
118
137
  ExampleClient.find id:1234
@@ -3,100 +3,216 @@ require 'spec_helper'
3
3
  describe "Flexirest::Validation" do
4
4
  class SimpleValidationExample < OpenStruct
5
5
  include Flexirest::Validation
6
- validates :first_name, presence:true
7
- validates :password, length:{within:6..12}
8
- validates :post_code, length:{minimum:6, maximum:8}
9
- validates :salary, numericality:true, minimum:20_000, maximum:50_000
6
+ validates :first_name, presence: true
7
+ validates :last_name, existence: true
8
+ validates :password, length: { within: 6..12 }
9
+ validates :post_code, length: { minimum: 6, maximum: 8 }
10
+ validates :salary, numericality: true, minimum: 20_000, maximum: 50_000
11
+ validates :age, numericality: { minimum: 18, maximum: 65 }
12
+ validates :suffix, inclusion: { in: %w{Dr. Mr. Mrs. Ms.}}
10
13
  end
11
14
 
12
15
  it "should be able to register a validation" do
13
- expect(SimpleValidationExample._validations.size).to eq(4)
16
+ expect(SimpleValidationExample._validations.size).to eq(7)
14
17
  end
15
18
 
16
- it "should be invalid if a required value isn't present" do
17
- a = SimpleValidationExample.new
18
- a.first_name = nil
19
- a.valid?
20
- expect(a._errors[:first_name].size).to eq(1)
21
- end
19
+ context "when validating presence" do
22
20
 
23
- it "should be valid if a required value is present" do
24
- a = SimpleValidationExample.new
25
- a.first_name = "John"
26
- a.valid?
27
- expect(a._errors[:first_name]).to be_empty
28
- end
21
+ it "should be invalid if a required value isn't present" do
22
+ a = SimpleValidationExample.new
23
+ a.first_name = nil
24
+ a.valid?
25
+ expect(a._errors[:first_name].size).to eq(1)
26
+ end
29
27
 
30
- it "should be invalid if a length within value is outside the range" do
31
- a = SimpleValidationExample.new(password:"12345")
32
- a.valid?
33
- expect(a._errors[:password].size).to eq(1)
34
- end
28
+ it "should be invalid if a required value is present but blank" do
29
+ a = SimpleValidationExample.new
30
+ a.first_name = ""
31
+ a.valid?
32
+ expect(a._errors[:first_name].size).to eq(1)
33
+ end
35
34
 
36
- it "should be valid if a length within value is inside the range" do
37
- a = SimpleValidationExample.new(password:"123456")
38
- a.valid?
39
- expect(a._errors[:password].size).to eq(0)
40
- end
35
+ it "should be invalid if a required value is present but is an empty array" do
36
+ a = SimpleValidationExample.new
37
+ a.first_name = []
38
+ a.valid?
39
+ expect(a._errors[:first_name].size).to eq(1)
40
+ end
41
41
 
42
- it "should be invalid if a length is below the minimum" do
43
- a = SimpleValidationExample.new(post_code:"12345")
44
- a.valid?
45
- expect(a._errors[:post_code].size).to eq(1)
46
- end
42
+ it "should be invalid if a required value is present but is an empty hash" do
43
+ a = SimpleValidationExample.new
44
+ a.first_name = {}
45
+ a.valid?
46
+ expect(a._errors[:first_name].size).to eq(1)
47
+ end
47
48
 
48
- it "should be valid if a length is above or equal to the minimum and below the maximum" do
49
- a = SimpleValidationExample.new(post_code:"123456")
50
- a.valid?
51
- expect(a._errors[:post_code].size).to eq(0)
49
+ it "should be valid if a required value is present" do
50
+ a = SimpleValidationExample.new
51
+ a.first_name = "John"
52
+ a.valid?
53
+ expect(a._errors[:first_name]).to be_empty
54
+ end
52
55
  end
53
56
 
54
- it "should be invalid if a length is above the maximum" do
55
- a = SimpleValidationExample.new(post_code:"123456789")
56
- a.valid?
57
- expect(a._errors[:post_code].size).to eq(1)
57
+ context "when validating existence" do
58
+ it "should be invalid if a required value isn't present" do
59
+ a = SimpleValidationExample.new
60
+ a.last_name = nil
61
+ a.valid?
62
+ expect(a._errors[:last_name].size).to eq(1)
63
+ end
64
+
65
+ it "should be valid if a required value is present but blank" do
66
+ a = SimpleValidationExample.new
67
+ a.last_name = ""
68
+ a.valid?
69
+ expect(a._errors[:last_name]).to be_empty
70
+ end
71
+
72
+ it "should be valid if a required value is present" do
73
+ a = SimpleValidationExample.new
74
+ a.last_name = "John"
75
+ a.valid?
76
+ expect(a._errors[:last_name]).to be_empty
77
+ end
58
78
  end
59
79
 
60
- it "should be able to validate that a field is numeric" do
61
- a = SimpleValidationExample.new(salary:"Bob")
62
- a.valid?
63
- expect(a._errors[:salary].size).to be > 0
80
+ context "when validating length" do
81
+ it "should be invalid if a length within value is outside the range" do
82
+ a = SimpleValidationExample.new(password:"12345")
83
+ a.valid?
84
+ expect(a._errors[:password].size).to eq(1)
85
+ end
86
+
87
+ it "should be valid if a length within value is inside the range" do
88
+ a = SimpleValidationExample.new(password:"123456")
89
+ a.valid?
90
+ expect(a._errors[:password].size).to eq(0)
91
+ end
92
+
93
+ it "should be invalid if a length is below the minimum" do
94
+ a = SimpleValidationExample.new(post_code:"12345")
95
+ a.valid?
96
+ expect(a._errors[:post_code].size).to eq(1)
97
+ end
98
+
99
+ it "should be valid if a length is above or equal to the minimum and below the maximum" do
100
+ a = SimpleValidationExample.new(post_code:"123456")
101
+ a.valid?
102
+ expect(a._errors[:post_code].size).to eq(0)
103
+ end
104
+
105
+ it "should be invalid if a length is above the maximum" do
106
+ a = SimpleValidationExample.new(post_code:"123456789")
107
+ a.valid?
108
+ expect(a._errors[:post_code].size).to eq(1)
109
+ end
64
110
  end
65
111
 
66
- it "should be able to validate that a numeric field is above or equal to a minimum" do
67
- a = SimpleValidationExample.new(salary:10_000)
68
- a.valid?
69
- expect(a._errors[:salary].size).to be > 0
112
+
113
+ context "when validating numericality" do
114
+ context "using the original format with min and max as types" do
115
+ it "should be able to validate that a field is numeric" do
116
+ a = SimpleValidationExample.new(salary:"Bob")
117
+ a.valid?
118
+ expect(a._errors[:salary].size).to be > 0
119
+ end
120
+
121
+ it "should be able to validate that a numeric field is above or equal to a minimum" do
122
+ a = SimpleValidationExample.new(salary:10_000)
123
+ a.valid?
124
+ expect(a._errors[:salary].size).to be > 0
125
+ end
126
+
127
+ it "should be able to validate that a numeric field is above or equal to a minimum" do
128
+ a = SimpleValidationExample.new(salary:100_000)
129
+ a.valid?
130
+ expect(a._errors[:salary].size).to be > 0
131
+ end
132
+
133
+ it "should be valid that a numeric field is above or equal to a minimum" do
134
+ a = SimpleValidationExample.new(salary:30_000)
135
+ a.valid?
136
+ expect(a._errors[:salary].size).to eq(0)
137
+ end
138
+
139
+ end
140
+
141
+ context "using the original format with min and max as types" do
142
+ it "should be able to validate that a field is numeric" do
143
+ a = SimpleValidationExample.new(age:"Bob")
144
+ a.valid?
145
+ expect(a._errors[:age].size).to be > 0
146
+ end
147
+
148
+ it "should be able to validate that a numeric field is above or equal to a minimum" do
149
+ a = SimpleValidationExample.new(age: 17)
150
+ a.valid?
151
+ expect(a._errors[:age].size).to be > 0
152
+ end
153
+
154
+ it "should be able to validate that a numeric field is above or equal to a minimum" do
155
+ a = SimpleValidationExample.new(age: 70)
156
+ a.valid?
157
+ expect(a._errors[:age].size).to be > 0
158
+ end
159
+
160
+ it "should be valid that a numeric field is above or equal to a minimum" do
161
+ a = SimpleValidationExample.new(age: 30)
162
+ a.valid?
163
+ expect(a._errors[:age].size).to eq(0)
164
+ end
165
+
166
+ end
70
167
  end
71
168
 
72
- it "should be able to validate that a numeric field is above or equal to a minimum" do
73
- a = SimpleValidationExample.new(salary:100_000)
74
- a.valid?
75
- expect(a._errors[:salary].size).to be > 0
169
+ context "when validating inclusion" do
170
+ it "should be invalid if the value is not contained in the list" do
171
+ a = SimpleValidationExample.new(suffix: "Baz")
172
+ a.valid?
173
+ expect(a._errors[:suffix].size).to be > 0
174
+ end
175
+
176
+ it "should be valid if the value is contained in the list" do
177
+ a = SimpleValidationExample.new(suffix: "Dr.")
178
+ a.valid?
179
+ expect(a._errors[:suffix].size).to eq(0)
180
+ end
76
181
  end
77
182
 
78
- it "should be invalid when a block adds an error" do
79
- class ValidationExample1 < OpenStruct
80
- include Flexirest::Validation
81
- validates :first_name do |object, name, value|
82
- object._errors[name] << "must be over 4 chars long" if value.length <= 4
183
+ context "when passing a block" do
184
+ it "should be invalid when a block adds an error" do
185
+ class ValidationExample1 < OpenStruct
186
+ include Flexirest::Validation
187
+ validates :first_name do |object, name, value|
188
+ object._errors[name] << "must be over 4 chars long" if value.length <= 4
189
+ end
83
190
  end
191
+ a = ValidationExample1.new(first_name:"John")
192
+ a.valid?
193
+ expect(a._errors[:first_name].size).to eq(1)
84
194
  end
85
- a = ValidationExample1.new(first_name:"John")
86
- a.valid?
87
- expect(a._errors[:first_name].size).to eq(1)
88
- end
89
195
 
90
- it "should be valid when a block doesn't add an error" do
91
- class ValidationExample2 < OpenStruct
92
- include Flexirest::Validation
93
- validates :first_name do |object, name, value|
94
- object._errors[name] << "must be over 4 chars long" if value.length <= 4
196
+ it "should be valid when a block doesn't add an error" do
197
+ class ValidationExample2 < OpenStruct
198
+ include Flexirest::Validation
199
+ validates :first_name do |object, name, value|
200
+ object._errors[name] << "must be over 4 chars long" if value.length <= 4
201
+ end
95
202
  end
203
+ a = ValidationExample2.new(first_name:"Johnny")
204
+ a.valid?
205
+ expect(a._errors[:first_name]).to be_empty
206
+ end
207
+ end
208
+
209
+ describe "#full_error_messages" do
210
+ it "should return an array of strings that combines the attribute name and the error message" do
211
+ a = SimpleValidationExample.new(age:"Bob", suffix: "Baz")
212
+ a.valid?
213
+ expect(a.full_error_messages).to include("age must be numeric")
214
+ expect(a.full_error_messages).to include("suffix must be included in Dr., Mr., Mrs., Ms.")
96
215
  end
97
- a = ValidationExample2.new(first_name:"Johnny")
98
- a.valid?
99
- expect(a._errors[:first_name]).to be_empty
100
216
  end
101
217
 
102
218
  it "should call valid? before making a request" 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.1
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jeffries
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-22 00:00:00.000000000 Z
11
+ date: 2015-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -315,7 +315,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
315
315
  version: '0'
316
316
  requirements: []
317
317
  rubyforge_project:
318
- rubygems_version: 2.4.6
318
+ rubygems_version: 2.4.5
319
319
  signing_key:
320
320
  specification_version: 4
321
321
  summary: This gem is for accessing REST services in a flexible way. ActiveResource
@@ -342,4 +342,3 @@ test_files:
342
342
  - spec/lib/validation_spec.rb
343
343
  - spec/lib/xml_spec.rb
344
344
  - spec/spec_helper.rb
345
- has_rdoc: