flexirest 1.6.7 → 1.6.8

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.
@@ -0,0 +1,219 @@
1
+ module Flexirest
2
+ class BaseWithoutValidation
3
+ include Mapping
4
+ include Configuration
5
+ include Callbacks
6
+ include Caching
7
+ include Recording
8
+ include AttributeParsing
9
+ include Associations
10
+
11
+ attr_accessor :_status
12
+ attr_accessor :_etag
13
+ attr_accessor :_headers
14
+
15
+ instance_methods.each do |m|
16
+ next unless %w{display presence load require hash untrust trust freeze method enable_warnings with_warnings suppress capture silence quietly debugger breakpoint}.map(&:to_sym).include? m
17
+ undef_method m
18
+ end
19
+
20
+ def initialize(attrs={})
21
+ @attributes = {}
22
+ @dirty_attributes = Hash.new
23
+
24
+ raise Exception.new("Cannot instantiate Base class") if self.class == Flexirest::BaseWithoutValidation
25
+
26
+ attrs.each do |attribute_name, attribute_value|
27
+ attribute_name = attribute_name.to_sym
28
+ @attributes[attribute_name] = parse_date?(attribute_name) ? parse_attribute_value(attribute_value) : attribute_value
29
+ @dirty_attributes[attribute_name] = [nil, attribute_value]
30
+ end
31
+ end
32
+
33
+ def _clean!
34
+ @dirty_attributes = Hash.new
35
+ end
36
+
37
+ def _attributes
38
+ @attributes
39
+ end
40
+
41
+ def _copy_from(result)
42
+ @attributes = result._attributes
43
+ @_status = result._status
44
+ end
45
+
46
+ def dirty?
47
+ @dirty_attributes.size > 0
48
+ end
49
+
50
+ def changed?
51
+ dirty?
52
+ end
53
+
54
+ # Returns an array of changed fields
55
+ def changed
56
+ @dirty_attributes.keys
57
+ end
58
+
59
+ # Returns hash of old and new vaules for each changed field
60
+ def changes
61
+ @dirty_attributes
62
+ end
63
+
64
+ def self._request(request, method = :get, params = nil, options = {})
65
+ prepare_direct_request(request, method, options).call(params)
66
+ end
67
+
68
+ def self._plain_request(request, method = :get, params = nil, options = {})
69
+ prepare_direct_request(request, method, options.merge(plain:true)).call(params)
70
+ end
71
+
72
+ def self._lazy_request(request, method = :get, params = nil, options = {})
73
+ Flexirest::LazyLoader.new(prepare_direct_request(request, method, options), params)
74
+ end
75
+
76
+ def self.prepare_direct_request(request, method = :get, options={})
77
+ unless request.is_a? Flexirest::Request
78
+ options[:plain] ||= false
79
+ options[:direct] ||= true
80
+ request = Flexirest::Request.new({ url: request, method: method, options: options }, self)
81
+ end
82
+ request
83
+ end
84
+
85
+ def self._request_for(method_name, *args)
86
+ if mapped = self._mapped_method(method_name)
87
+ params = (args.first.is_a?(Hash) ? args.first : nil)
88
+ request = Request.new(mapped, self, params)
89
+ request
90
+ else
91
+ nil
92
+ end
93
+ end
94
+
95
+ def [](key)
96
+ @attributes[key.to_sym]
97
+ end
98
+
99
+ def []=(key, value)
100
+ _set_attribute(key, value)
101
+ end
102
+
103
+ def each
104
+ @attributes.each do |key, value|
105
+ yield key, value
106
+ end
107
+ end
108
+
109
+ def inspect
110
+ inspection = if @attributes.any?
111
+ @attributes.collect { |key, value|
112
+ "#{key}: #{value_for_inspect(value)}"
113
+ }.compact.join(", ")
114
+ else
115
+ "[uninitialized]"
116
+ end
117
+ inspection += "#{"," if @attributes.any?} ETag: #{@_etag}" unless @_etag.nil?
118
+ inspection += "#{"," if @attributes.any?} Status: #{@_status}" unless @_status.nil?
119
+ inspection += " (unsaved: #{@dirty_attributes.keys.map(&:to_s).join(", ")})" if @dirty_attributes.any?
120
+ "#<#{self.class} #{inspection}>"
121
+ end
122
+
123
+ def method_missing(name, *args)
124
+ if name.to_s[-1,1] == "="
125
+ name = name.to_s.chop.to_sym
126
+ _set_attribute(name, args.first)
127
+ else
128
+ name_sym = name.to_sym
129
+ name = name.to_s
130
+
131
+ if @attributes.has_key? name_sym
132
+ @attributes[name_sym]
133
+ else
134
+ if name[/^lazy_/] && mapped = self.class._mapped_method(name_sym)
135
+ if mapped[:method] != :delete
136
+ raise ValidationFailedException.new if respond_to?(:valid?) && !valid?
137
+ end
138
+
139
+ request = Request.new(mapped, self, args.first)
140
+ Flexirest::LazyLoader.new(request)
141
+ elsif mapped = self.class._mapped_method(name_sym)
142
+ if mapped[:method] != :delete
143
+ raise ValidationFailedException.new if respond_to?(:valid?) && !valid?
144
+ end
145
+
146
+ request = Request.new(mapped, self, args.first)
147
+ request.call
148
+ elsif name[/_was$/] and @attributes.has_key? (name.sub(/_was$/,'').to_sym)
149
+ k = (name.sub(/_was$/,'').to_sym)
150
+ @dirty_attributes[k][0]
151
+ elsif name[/^reset_.*!$/] and @attributes.has_key? (name.sub(/^reset_/,'').sub(/!$/,'').to_sym)
152
+ k = (name.sub(/^reset_/,'').sub(/!$/,'').to_sym)
153
+ _reset_attribute(k)
154
+ elsif self.class.whiny_missing
155
+ raise NoAttributeException.new("Missing attribute #{name_sym}")
156
+ else
157
+ nil
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ def respond_to_missing?(method_name, include_private = false)
164
+ @attributes.has_key? method_name.to_sym
165
+ end
166
+
167
+ def to_hash
168
+ output = {}
169
+ @attributes.each do |key, value|
170
+ if value.is_a? Flexirest::Base
171
+ output[key.to_s] = value.to_hash
172
+ elsif value.is_a? Array
173
+ output[key.to_s] = value.map(&:to_hash)
174
+ else
175
+ output[key.to_s] = value
176
+ end
177
+ end
178
+ output
179
+ end
180
+
181
+ def to_json
182
+ output = to_hash
183
+ output.to_json
184
+ end
185
+
186
+ private
187
+
188
+ def _set_attribute(key, value)
189
+ old_value = @dirty_attributes[key.to_sym]
190
+ old_value = @attributes[key.to_sym] unless old_value
191
+ old_value = old_value[0] if old_value and old_value.is_a? Array
192
+ @dirty_attributes[key.to_sym] = [old_value, value]
193
+ @attributes[key.to_sym] = value
194
+ end
195
+
196
+ def _reset_attribute(key)
197
+ old_value = @dirty_attributes[key.to_sym]
198
+ @attributes[key.to_sym] = old_value[0] if old_value and old_value.is_a? Array
199
+ @dirty_attributes.delete(key.to_sym)
200
+ end
201
+
202
+ def value_for_inspect(value)
203
+ if value.is_a?(String) && value.length > 50
204
+ "#{value[0..50]}...".inspect
205
+ elsif value.is_a?(Date) || value.is_a?(Time)
206
+ %("#{value.to_s(:db)}")
207
+ else
208
+ value.inspect
209
+ end
210
+ end
211
+
212
+ def parse_date?(name)
213
+ return true if self.class._date_fields.include?(name)
214
+ return true if !Flexirest::Base.disable_automatic_date_parsing && self.class._date_fields.empty?
215
+ false
216
+ end
217
+
218
+ end
219
+ end
@@ -1,3 +1,3 @@
1
1
  module Flexirest
2
- VERSION = "1.6.7"
2
+ VERSION = "1.6.8"
3
3
  end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ require 'active_model'
4
+
5
+ describe ActiveModel::Validations do
6
+ class ActiveModelValidationsExample < Flexirest::BaseWithoutValidation
7
+ include ActiveModel::Validations
8
+
9
+ validates :first_name, :last_name, presence: true
10
+ validates :password, length: { within: 6..12, message: 'Invalid password length, must be 6-12 characters' }
11
+ end
12
+
13
+ let(:first_name) { 'Foo '}
14
+ let(:last_name) { 'Bar' }
15
+ let(:password) { 'eiChahya6i' }
16
+ let(:attributes) { { first_name: first_name, last_name: last_name, password: password } }
17
+ subject(:instance) { ActiveModelValidationsExample.new(attributes) }
18
+
19
+ it { is_expected.to be_valid }
20
+
21
+ context 'when the first name is invalid' do
22
+ let(:first_name) { '' }
23
+
24
+ it { is_expected.to_not be_valid }
25
+ end
26
+
27
+ context 'when the last name is invalid' do
28
+ let(:last_name) { '' }
29
+
30
+ it { is_expected.to_not be_valid }
31
+ end
32
+
33
+ context 'when the password is invalid' do
34
+ let(:password) { 'foo' }
35
+
36
+ it { is_expected.to_not be_valid }
37
+
38
+ it 'should include the custom error message' do
39
+ instance.valid?
40
+
41
+ expect(instance.errors[:password]).to include('Invalid password length, must be 6-12 characters')
42
+ end
43
+ end
44
+ end
@@ -16,24 +16,24 @@ class AssociationExampleBase < Flexirest::Base
16
16
  has_one :association_example_other
17
17
  end
18
18
 
19
- class DeepNestedHasManyChildExample < Flexirest::Base
19
+ class DeepNestedHasManyChildExample < Flexirest::BaseWithoutValidation
20
20
  end
21
21
 
22
- class DeepNestedHasManyTopExample < Flexirest::Base
22
+ class DeepNestedHasManyTopExample < Flexirest::BaseWithoutValidation
23
23
  has_many :entries, DeepNestedHasManyChildExample
24
24
  end
25
25
 
26
- class DeepNestedHasManyExample < Flexirest::Base
26
+ class DeepNestedHasManyExample < Flexirest::BaseWithoutValidation
27
27
  has_many :results, DeepNestedHasManyTopExample
28
28
  hash = { results: [ { entries: [ { items: [ "item one", "item two" ] } ] }, { entries: [ { items: [ "item three", "item four" ] } ] } ] }
29
29
  get :find, "/iterate", fake: hash.to_json
30
30
  end
31
31
 
32
- class WhitelistedDateExample < Flexirest::Base
32
+ class WhitelistedDateExample < Flexirest::BaseWithoutValidation
33
33
  parse_date :updated_at
34
34
  end
35
35
 
36
- class WhitelistedDateMultipleExample < Flexirest::Base
36
+ class WhitelistedDateMultipleExample < Flexirest::BaseWithoutValidation
37
37
  parse_date :updated_at, :created_at
38
38
  parse_date :generated_at
39
39
  end
@@ -1,512 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
- class EmptyExample < Flexirest::Base
4
- whiny_missing true
3
+ class EmptyBaseExample < Flexirest::Base
5
4
  end
6
5
 
7
- class TranslatorExample
8
- def self.all(object)
9
- ret = {}
10
- ret["first_name"] = object["name"]
11
- ret
12
- end
13
- end
14
-
15
- class AlteringClientExample < Flexirest::Base
16
- translator TranslatorExample
17
- base_url "http://www.example.com"
18
-
19
- get :all, "/all", fake:"{\"name\":\"Billy\"}"
20
- get :list, "/list", fake:"{\"name\":\"Billy\", \"country\":\"United Kingdom\"}"
21
- get :iterate, "/iterate", fake:"{\"name\":\"Billy\", \"country\":\"United Kingdom\"}"
22
- get :find, "/find/:id"
23
- end
24
-
25
- class RecordResponseExample < Flexirest::Base
26
- base_url "http://www.example.com"
27
-
28
- record_response do |url, response|
29
- raise Exception.new("#{url}|#{response.body}")
30
- end
31
-
32
- get :all, "/all"
33
- end
34
-
35
- class NonHostnameBaseUrlExample < Flexirest::Base
36
- base_url "http://www.example.com/v1/"
37
- get :all, "/all"
38
- end
39
-
40
- class InstanceMethodExample < Flexirest::Base
41
- base_url "http://www.example.com/v1/"
42
- get :all, "/all"
43
- end
44
-
45
- class WhitelistedDateExample < Flexirest::Base
46
- parse_date :updated_at
47
- end
48
-
49
-
50
6
  describe Flexirest::Base do
51
- it 'should instantiate a new descendant' do
52
- expect{EmptyExample.new}.to_not raise_error
53
- end
54
-
55
- it "should not instantiate a new base class" do
56
- expect{Flexirest::Base.new}.to raise_error(Exception)
57
- end
58
-
59
- it "should save attributes passed in constructor" do
60
- client = EmptyExample.new(test: "Something")
61
- expect(client._attributes[:test]).to be_a(String)
62
- end
63
-
64
- it "should allow attribute reading using missing method names" do
65
- client = EmptyExample.new(test: "Something")
66
- expect(client.test).to eq("Something")
67
- end
68
-
69
- it "should allow attribute reading using [] array notation" do
70
- client = EmptyExample.new(test: "Something")
71
- expect(client["test"]).to eq("Something")
72
- end
73
-
74
- it "allows iteration over attributes using each" do
75
- client = AlteringClientExample.iterate
76
- expect(client).to be_respond_to(:each)
77
- keys = []
78
- values = []
79
- client.each do |key, value|
80
- keys << key ; values << value
81
- end
82
- expect(keys).to eq(%w{name country}.map(&:to_sym))
83
- expect(values).to eq(["Billy", "United Kingdom"])
84
- end
85
-
86
- it "should automatically parse ISO 8601 format date and time" do
87
- t = Time.now
88
- client = EmptyExample.new(test: t.iso8601)
89
- expect(client["test"]).to be_an_instance_of(DateTime)
90
- expect(client["test"].to_s).to eq(t.to_datetime.to_s)
91
- end
92
-
93
- it "should automatically parse ISO 8601 format date and time with milliseconds" do
94
- t = Time.now
95
- client = EmptyExample.new(test: t.iso8601(3))
96
- expect(client["test"]).to be_an_instance_of(DateTime)
97
- expect(client["test"].to_s).to eq(t.to_datetime.to_s)
98
- end
99
-
100
- it "should automatically parse ISO 8601 format dates" do
101
- d = Date.today
102
- client = EmptyExample.new(test: d.iso8601)
103
- expect(client["test"]).to be_an_instance_of(Date)
104
- expect(client["test"]).to eq(d)
105
- end
106
-
107
- it "should automatically parse date/time strings regardless if the date portion has no delimiters" do
108
- client = EmptyExample.new(test: "20151230T09:48:50-05:00")
109
- expect(client["test"]).to be_an_instance_of(DateTime)
110
- end
111
-
112
- it "should allow strings of 4 digits and not intepret them as dates" do
113
- client = EmptyExample.new(test: "2015")
114
- expect(client["test"]).to be_an_instance_of(String)
115
- end
116
-
117
- it "should allow strings of 8 digits and not intepret them as dates" do
118
- client = EmptyExample.new(test: "1266129")
119
- expect(client["test"]).to be_an_instance_of(String)
120
- end
121
-
122
- it "should store attributes set using missing method names and mark them as dirty" do
123
- client = EmptyExample.new()
124
- client.test = "Something"
125
- expect(client.test.to_s).to eq("Something")
126
- expect(client).to be_dirty
127
- end
128
-
129
- it "should store attribute set using []= array notation and mark them as dirty" do
130
- client = EmptyExample.new()
131
- client["test"] = "Something"
132
- expect(client["test"].to_s).to eq("Something")
133
- expect(client).to be_dirty
134
- end
135
-
136
- it "should track changed attributes and provide access to previous values (similar to ActiveRecord/Mongoid)" do
137
- client = EmptyExample.new()
138
- client["test"] = "Something"
139
-
140
- client._clean! # force a clean state so we can proceed with tests
141
-
142
- expect(client).to_not be_dirty # clean state should have set in (dirty?)
143
- expect(client).to_not be_changed # clean state should have set in (changed?)
144
- expect(client["test"].to_s).to eq("Something") # verify attribute value persists
145
-
146
- client["test"] = "SomethingElse" # change the attribute value
147
- expect(client["test"].to_s).to eq("SomethingElse") # most current set value should be returned
148
- expect(client).to be_dirty # an attribute was changed, so the entire object is dirty
149
- expect(client).to be_changed # an attribute was changed, so the entire object is changed
150
- expect(client.changed).to be_a(Array) # the list of changed attributes should be an Array
151
- expect(client.changed).to eq([:test]) # the list of changed attributes should provide the name of the changed attribute
152
- expect(client.changes).to be_a(Hash) # changes are returned as a hash
153
- expect(client.changes).to eq({test: ["Something", "SomethingElse"]}) # changes include [saved,unsaved] values, keyed by attribute name
154
- expect(client.test_was).to eq("Something") # dynamic *_was notation provides original value
155
-
156
- client["test"] = "SomethingElseAgain" # change the attribute value again
157
- expect(client.test_was).to eq("Something") # dynamic *_was notation provides original value (from most recent save/load, not most recent change)
158
- expect(client.changes).to eq({test: ["Something", "SomethingElseAgain"]}) # changes include [saved,unsaved] values, keyed by attribute name
159
-
160
- # resets the test attribute back to the original value
161
- expect( client.reset_test! ).to eq(["Something", "SomethingElseAgain"]) # reseting an attribute returns the previous pending changeset
162
- expect(client).to_not be_dirty # reseting an attribute should makeit not dirty again
163
- end
164
-
165
- it "should overwrite attributes already set and mark them as dirty" do
166
- client = EmptyExample.new(hello: "World")
167
- client._clean!
168
- expect(client).to_not be_dirty
169
-
170
- client.hello = "Everybody"
171
- expect(client).to be_dirty
172
- end
173
-
174
- it 'should respond_to? attributes defined in the response' do
175
- client = EmptyExample.new(hello: "World")
176
- expect(client.respond_to?(:hello)).to be_truthy
177
- expect(client.respond_to?(:world)).to be_falsey
178
- end
179
-
180
- it "should save the base URL for the API server" do
181
- class BaseExample < Flexirest::Base
182
- base_url "https://www.example.com/api/v1"
183
- end
184
- expect(BaseExample.base_url).to eq("https://www.example.com/api/v1")
185
- end
186
-
187
- it "should allow changing the base_url while running" do
188
- class OutsideBaseExample < Flexirest::Base ; end
189
-
190
- Flexirest::Base.base_url = "https://www.example.com/api/v1"
191
- expect(OutsideBaseExample.base_url).to eq("https://www.example.com/api/v1")
192
-
193
- Flexirest::Base.base_url = "https://www.example.com/api/v2"
194
- expect(OutsideBaseExample.base_url).to eq("https://www.example.com/api/v2")
195
- end
196
-
197
- it "should include the Mapping module" do
198
- expect(EmptyExample).to respond_to(:_calls)
199
- expect(EmptyExample).to_not respond_to(:_non_existant)
200
- end
201
-
202
- it "should be able to easily clean all attributes" do
203
- client = EmptyExample.new(hello:"World", goodbye:"Everyone")
204
- expect(client).to be_dirty
205
- client._clean!
206
- expect(client).to_not be_dirty
207
- end
208
-
209
- it "should not overly pollute the instance method namespace to reduce chances of clashing (<13 instance methods)" do
210
- instance_methods = EmptyExample.instance_methods - Object.methods
211
- instance_methods = instance_methods - instance_methods.grep(/^_/)
212
- expect(instance_methods.size).to be < 13
213
- end
214
-
215
- it "should raise an exception for missing attributes if whiny_missing is enabled" do
216
- expect{EmptyExample.new.first_name}.to raise_error(Flexirest::NoAttributeException)
217
- end
218
-
219
- it "should be able to lazy instantiate an object from a prefixed lazy_ method call" do
220
- expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/find/1', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
221
- example = AlteringClientExample.lazy_find(1)
222
- expect(example).to be_an_instance_of(Flexirest::LazyLoader)
223
- expect(example.first_name).to eq("Billy")
224
- end
225
-
226
- it "should be able to lazy instantiate an object from a prefixed lazy_ method call from an instance" do
227
- expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/find/1', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
228
- example = AlteringClientExample.new.lazy_find(1)
229
- expect(example).to be_an_instance_of(Flexirest::LazyLoader)
230
- expect(example.first_name).to eq("Billy")
231
- end
232
-
233
- context "#inspect output" do
234
- it "displays a nice version" do
235
- object = EmptyExample.new(id: 1, name: "John Smith")
236
- expect(object.inspect).to match(/#<EmptyExample id: 1, name: "John Smith"/)
237
- end
238
-
239
- it "shows dirty attributes as a list of names at the end" do
240
- object = EmptyExample.new(id: 1, name: "John Smith")
241
- expect(object.inspect).to match(/#<EmptyExample id: 1, name: "John Smith" \(unsaved: id, name\)/)
242
- end
243
-
244
- it "doesn't show an empty list of dirty attributes" do
245
- object = EmptyExample.new(id: 1, name: "John Smith")
246
- object.instance_variable_set(:@dirty_attributes, Set.new)
247
- expect(object.inspect).to_not match(/\(unsaved: id, name\)/)
248
- end
249
-
250
- it "shows dates in a nice format" do
251
- object = EmptyExample.new(dob: Time.new(2015, 01, 02, 03, 04, 05))
252
- expect(object.inspect).to match(/#<EmptyExample dob: "2015\-01\-02 03:04:05"/)
253
- end
254
-
255
- it "shows the etag if one is set" do
256
- object = EmptyExample.new(id: 1)
257
- object.instance_variable_set(:@_etag, "sample_etag")
258
- expect(object.inspect).to match(/#<EmptyExample id: 1, ETag: sample_etag/)
259
- end
260
-
261
- it "shows the HTTP status code if one is set" do
262
- object = EmptyExample.new(id: 1)
263
- object.instance_variable_set(:@_status, 200)
264
- expect(object.inspect).to match(/#<EmptyExample id: 1, Status: 200/)
265
- end
266
-
267
- it "shows [uninitialized] for new objects" do
268
- object = EmptyExample.new
269
- expect(object.inspect).to match(/#<EmptyExample \[uninitialized\]/)
270
- end
271
-
272
- end
273
-
274
- context "accepts a Translator to reformat JSON" do
275
- it "should log a deprecation warning when using a translator" do
276
- expect(Flexirest::Logger).to receive(:warn) do |message|
277
- expect(message).to start_with("DEPRECATION")
278
- end
279
- Proc.new do
280
- class DummyExample < Flexirest::Base
281
- translator TranslatorExample
282
- end
283
- end.call
284
- end
285
-
286
- it "should call Translator#method when calling the mapped method if it responds to it" do
287
- expect(TranslatorExample).to receive(:all).with(an_instance_of(Hash)).and_return({})
288
- AlteringClientExample.all
289
- end
290
-
291
- it "should not raise errors when calling Translator#method if it does not respond to it" do
292
- expect {AlteringClientExample.list}.to_not raise_error
293
- end
294
-
295
- it "should translate JSON returned through the Translator" do
296
- ret = AlteringClientExample.all
297
- expect(ret.first_name).to eq("Billy")
298
- expect(ret.name).to be_nil
299
- end
300
-
301
- it "should return original JSON for items that aren't handled by the Translator" do
302
- ret = AlteringClientExample.list
303
- expect(ret.name).to eq("Billy")
304
- expect(ret.first_name).to be_nil
305
- end
306
- end
307
-
308
- context "directly call a URL, rather than via a mapped method" do
309
- it "should be able to directly call a URL" do
310
- expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
311
- EmptyExample._request("http://api.example.com/")
312
- end
313
-
314
- it "allows already encoded bodies" do
315
- Flexirest::ConnectionManager.reset!
316
- connection = double("Connection")
317
- allow(connection).to receive(:base_url).and_return("http://api.example.com")
318
- expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://api.example.com/").and_return(connection)
319
- expect(connection).
320
- to receive(:post).
321
- with("http://api.example.com/", "{\"test\":\"value\"}",an_instance_of(Hash)).
322
- and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"John\", \"id\":1234}", response_headers:{}, status:200)))
323
- EmptyExample._request("http://api.example.com/", :post, {test: "value"}.to_json, request_body_type: :json)
324
- end
325
-
326
- it "passes headers" do
327
- stub_request(:get, "http://api.example.com/v1").
328
- with(headers: {'Accept'=>'application/hal+json, application/json;q=0.5', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Connection'=>'Keep-Alive', 'Content-Type'=>'application/x-www-form-urlencoded', 'X-Something'=>'foo/bar', 'User-Agent'=>/Flexirest\//}).
329
- to_return(status: 200, body: "", headers: {})
330
- EmptyExample._request("http://api.example.com/v1", :get, {}, {headers: {"X-Something" => "foo/bar"}})
331
- end
332
-
333
- it "passes headers if the response is unparsed" do
334
- stub_request(:get, "http://api.example.com/v1").
335
- with(headers: {'Accept'=>'application/hal+json, application/json;q=0.5', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Connection'=>'Keep-Alive', 'Content-Type'=>'application/x-www-form-urlencoded', 'X-Something'=>'foo/bar', 'User-Agent'=>/Flexirest\//}).
336
- to_return(status: 200, body: "", headers: {})
337
- EmptyExample._plain_request("http://api.example.com/v1", :get, {}, {headers: {"X-Something" => "foo/bar"}})
338
- end
339
-
340
- it "runs callbacks as usual" do
341
- expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
342
- expect(EmptyExample).to receive(:_callback_request).with(any_args).exactly(2).times
343
- EmptyExample._request("http://api.example.com/")
344
- end
345
-
346
- it "should make an HTTP request" do
347
- expect_any_instance_of(Flexirest::Connection).to receive(:get).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
348
- EmptyExample._request("http://api.example.com/")
349
- end
350
-
351
- it "should make an HTTP request including the path in the base_url" do
352
- expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/v1/all', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
353
- NonHostnameBaseUrlExample.all
354
- end
355
-
356
- it "should map the response from the directly called URL in the normal way" do
357
- expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
358
- example = EmptyExample._request("http://api.example.com/")
359
- expect(example.first_name).to eq("Billy")
360
- end
361
-
362
- it "should be able to pass the plain response from the directly called URL bypassing JSON loading" do
363
- response_body = "This is another non-JSON string"
364
- expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:response_body)))
365
- expect(EmptyExample._plain_request("http://api.example.com/", :post, {id:1234})).to eq(response_body)
366
- end
367
-
368
- it "should return a PlainResponse from the directly called URL bypassing JSON loading" do
369
- response_body = "This is another non-JSON string"
370
- expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:response_body)))
371
- expect(EmptyExample._plain_request("http://api.example.com/", :post, {id:1234})).to be_a(Flexirest::PlainResponse)
372
- end
373
-
374
- context "Simulating Faraday connection in_parallel" do
375
- it "should be able to pass the plain response from the directly called URL bypassing JSON loading" do
376
- response_body = "This is another non-JSON string"
377
- response = ::FaradayResponseMock.new(
378
- OpenStruct.new(status:200, response_headers:{}, body:response_body),
379
- false)
380
- expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(response)
381
- result = EmptyExample._plain_request("http://api.example.com/", :post, {id:1234})
382
-
383
- expect(result).to eq(nil)
384
-
385
- response.finish
386
- expect(result).to eq(response_body)
387
- end
388
- end
389
-
390
- it "should cache plain requests separately" do
391
- perform_caching = EmptyExample.perform_caching
392
- cache_store = EmptyExample.cache_store
393
- begin
394
- response = "This is a non-JSON string"
395
- other_response = "This is another non-JSON string"
396
- allow_any_instance_of(Flexirest::Connection).to receive(:get) do |instance, url, others|
397
- if url["/?test=1"]
398
- ::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:response))
399
- else
400
- ::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:other_response))
401
- end
402
- end
403
- EmptyExample.perform_caching = true
404
- EmptyExample.cache_store = TestCacheStore.new
405
- expect(EmptyExample._plain_request("http://api.example.com/?test=1")).to eq(response)
406
- expect(EmptyExample._plain_request("http://api.example.com/?test=2")).to eq(other_response)
407
- ensure
408
- EmptyExample.perform_caching = perform_caching
409
- EmptyExample.cache_store = cache_store
410
- end
411
- end
412
-
413
- it "should work with caching if instance methods are used" do
414
- perform_caching = InstanceMethodExample.perform_caching
415
- cache_store = InstanceMethodExample.cache_store
416
- begin
417
- response = "{\"id\": 1, \"name\":\"test\"}"
418
- allow_any_instance_of(Flexirest::Connection).to receive(:get).and_return( ::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{"Etag" => "12345678", "Content-type" => "application/json"}, body:response)))
419
- e = InstanceMethodExample.new
420
- e.all(1)
421
- expect(e.id).to eq(1)
422
- ensure
423
- InstanceMethodExample.perform_caching = perform_caching
424
- InstanceMethodExample.cache_store = cache_store
425
- end
426
- end
427
-
428
- it "should be able to lazy load a direct URL request" do
429
- expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
430
- example = EmptyExample._lazy_request("http://api.example.com/")
431
- expect(example).to be_an_instance_of(Flexirest::LazyLoader)
432
- expect(example.first_name).to eq("Billy")
433
- end
434
-
435
- it "should be able to specify a method and parameters for the call" do
436
- expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
437
- EmptyExample._request("http://api.example.com/", :post, {id:1234})
438
- end
439
-
440
- it "should be able to replace parameters in the URL for the call" do
441
- expect_any_instance_of(Flexirest::Connection).to receive(:post).with("http://api.example.com/1234", "", any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
442
- EmptyExample._request("http://api.example.com/:id", :post, {id:1234})
443
- end
444
-
445
- it "should be able to use mapped methods to create a request to pass in to _lazy_request" do
446
- expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/find/1', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
447
- request = AlteringClientExample._request_for(:find, id: 1)
448
- example = AlteringClientExample._lazy_request(request)
449
- expect(example.first_name).to eq("Billy")
450
- end
451
- end
452
-
453
- context "Recording a response" do
454
- it "calls back to the record_response callback with the url and response body" do
455
- expect_any_instance_of(Flexirest::Connection).to receive(:get).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"Hello world")))
456
- expect{RecordResponseExample.all}.to raise_error(Exception, "/all|Hello world")
457
- end
458
- end
459
-
460
- context "JSON output" do
461
- let(:student1) { EmptyExample.new(name:"John Smith", age:31) }
462
- let(:student2) { EmptyExample.new(name:"Bob Brown", age:29) }
463
- let(:location) { EmptyExample.new(place:"Room 1408") }
464
- let(:lazy) { Laz }
465
- let(:object) { EmptyExample.new(name:"Programming 101", location:location, students:[student1, student2]) }
466
- let(:json_parsed_object) { MultiJson.load(object.to_json) }
467
-
468
- it "should be able to export to valid json" do
469
- expect(object.to_json).to_not be_blank
470
- expect{MultiJson.load(object.to_json)}.to_not raise_error
471
- end
472
-
473
- it "should not be using Object's #to_json method" do
474
- expect(json_parsed_object["dirty_attributes"]).to be_nil
475
- end
476
-
477
- it "should recursively convert nested objects" do
478
- expect(json_parsed_object["location"]["place"]).to eq(location.place)
479
- end
480
-
481
- it "should include arrayed objects" do
482
- expect(json_parsed_object["students"]).to be_an_instance_of(Array)
483
- expect(json_parsed_object["students"].size).to eq(2)
484
- expect(json_parsed_object["students"].first["name"]).to eq(student1.name)
485
- expect(json_parsed_object["students"].second["name"]).to eq(student2.name)
486
- end
487
-
488
- it "should set integers as a native JSON type" do
489
- expect(json_parsed_object["students"].first["age"]).to eq(student1.age)
490
- expect(json_parsed_object["students"].second["age"]).to eq(student2.age)
491
- end
492
- end
493
-
494
- describe "instantiating object" do
495
- context "no whitelist specified" do
496
- it "should convert dates automatically" do
497
- client = EmptyExample.new(test: Time.now.iso8601)
498
- expect(client["test"]).to be_an_instance_of(DateTime)
499
- end
500
- end
501
-
502
- context "whitelist specified" do
503
- it "should only convert specified dates" do
504
- time = Time.now.iso8601
505
- client = WhitelistedDateExample.new(updated_at: time, created_at: time)
506
- expect(client["updated_at"]).to be_an_instance_of(DateTime)
507
- expect(client["created_at"]).to be_an_instance_of(String)
508
- end
509
- end
510
- end
7
+ subject { EmptyBaseExample.new }
511
8
 
9
+ it { is_expected.to respond_to(:valid?) }
512
10
  end