flexirest 1.2.1 → 1.2.2

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: 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: