flexirest 1.6.7 → 1.6.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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