flexirest 1.2.19 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Migrating-from-ActiveRestClient.md +33 -0
- data/README.md +27 -0
- data/lib/flexirest.rb +9 -1
- data/lib/flexirest/associations.rb +57 -0
- data/lib/flexirest/base.rb +1 -0
- data/lib/flexirest/caching.rb +2 -2
- data/lib/flexirest/instrumentation.rb +2 -2
- data/lib/flexirest/request.rb +7 -7
- data/lib/flexirest/version.rb +1 -1
- data/spec/lib/associations_spec.rb +87 -0
- data/spec/lib/flexirest_spec.rb +19 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd8c9e532875def5d80496e08867b0f12579dc1d
|
4
|
+
data.tar.gz: f4e81c7652797f5fc3dac4c02870691b2b356583
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80628e8db4f74a856ba72a017d74f2bbd0225fe4bc5088f06b20e8a7e9b4d6a18f8132ff3adb43b14c2d7fc1e08571c3a3e9a3dc78a0ae3208146eaeb2f4fb19
|
7
|
+
data.tar.gz: 5599b5a95be27c4c391a7cd60654cc0329d32e1f1faad43696b24c4baef0762ec2d907cd945250d74bdedaf50273c2919166e631277754b40986094051420cdc
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.3.1
|
4
|
+
|
5
|
+
Features:
|
6
|
+
|
7
|
+
- You can now use has_many/has_one on the class live, more like ActiveRecord
|
8
|
+
|
9
|
+
## 1.3.0
|
10
|
+
|
11
|
+
Features:
|
12
|
+
|
13
|
+
- Allow a custom name to be set to be used in logging (thanks to Lewis Buckley)
|
14
|
+
|
3
15
|
## 1.2.19
|
4
16
|
|
5
17
|
Features:
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Migrating from ActiveRestClient
|
2
|
+
|
3
|
+
While contracting at Which? Ltd I wrote a library in Ruby to access REST APIs in a very flexible, almost ActiveRecord style. This was agreed (after long discussions with the legal department) to be released as open source.
|
4
|
+
|
5
|
+
Unfortunately after leaving Which? the gem was used less and less as I believe they were re-architecting to not rely on backend servers built in Java anymore.
|
6
|
+
|
7
|
+
In October 2015 I decided that I didn't want this gem that I'd built to fall by the wayside, so I forked under the name Flexirest (which wasn't listed as a gem at RubyGems.org) and released it.
|
8
|
+
|
9
|
+
Since then I've continued to update the library with fixes and some minor new features (it's working really well and is pretty functionally complete, so there isn't much to add there at this point), but some people continue to post bugs/pull requests on the ActiveRestClient GitHub page.
|
10
|
+
|
11
|
+
So, if you've seen this link on https://github.com/whichdigital/active-rest-client/ the chances are I've sent you a link to it to show you the reasons why you should switch to Flexirest and how...
|
12
|
+
|
13
|
+
## How to change
|
14
|
+
|
15
|
+
The first step is to change the line in your Gemfile from:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem "active-rest-client"
|
19
|
+
```
|
20
|
+
|
21
|
+
to read:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'flexirest'
|
25
|
+
```
|
26
|
+
|
27
|
+
and then re-run `bundle install`.
|
28
|
+
|
29
|
+
The second step is to find and replace across your codebase all instances of `ActiveRestClient` with `Flexirest`.
|
30
|
+
|
31
|
+
The third and final step is to clear your Rails cache. The easiest way of doing this is to type `Rails.cache.clear` in a Rails console.
|
32
|
+
|
33
|
+
That's it, you've now switched over to Flexirest with a)lots of bug fixes, b)support for PATCH requests and c)someone actively continuing to support it!
|
data/README.md
CHANGED
@@ -176,6 +176,33 @@ puts @person.expenses.reduce {|e| e.inc_vat}
|
|
176
176
|
puts @person.address.full_string
|
177
177
|
```
|
178
178
|
|
179
|
+
You can also use `has_one`/`has_many` on the class level to allow chaining of classes. You can specify the class name or allow the system to automatically convert it to the singular class. For example:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
class Expense < Flexirest::Base
|
183
|
+
def inc_vat
|
184
|
+
ex_vat * 1.20
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class Address < Flexirest::Base
|
189
|
+
def full_string
|
190
|
+
return "#{self.street}, #{self.city}, #{self.region}, #{self.country}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class Person < Flexirest::Base
|
195
|
+
has_one :addresses
|
196
|
+
has_many :expenses, Expense
|
197
|
+
get :find, "/people/:id"
|
198
|
+
end
|
199
|
+
|
200
|
+
class Company < Flexirest::Base
|
201
|
+
has_many :people
|
202
|
+
get :find, "/companies/:id"
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
179
206
|
Sometimes we want attributes to just return a simple Ruby Array. To achieve this we can add an `:array` option to the method. This is especially useful when the attribute contains an array of scalar values. If you don't specify the `:array` option Flexirest will return a `Flexirest::ResultIterator`. To illustrate the difference consider the following example:
|
180
207
|
|
181
208
|
```ruby
|
data/lib/flexirest.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_support/all'
|
2
2
|
require "flexirest/version"
|
3
3
|
require "flexirest/attribute_parsing"
|
4
|
+
require "flexirest/associations"
|
4
5
|
require "flexirest/mapping"
|
5
6
|
require "flexirest/caching"
|
6
7
|
require "flexirest/logger"
|
@@ -22,5 +23,12 @@ require "flexirest/base"
|
|
22
23
|
require "flexirest/monkey_patching"
|
23
24
|
|
24
25
|
module Flexirest
|
25
|
-
|
26
|
+
@@name = "Flexirest"
|
27
|
+
|
28
|
+
def self.name
|
29
|
+
@@name
|
30
|
+
end
|
31
|
+
def self.name=(value)
|
32
|
+
@@name = value
|
33
|
+
end
|
26
34
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Flexirest
|
2
|
+
module Associations
|
3
|
+
module ClassMethods
|
4
|
+
include ActiveSupport::Inflector
|
5
|
+
|
6
|
+
def has_many(key, klass = nil)
|
7
|
+
if klass.nil?
|
8
|
+
klass = key.to_s.classify.constantize
|
9
|
+
end
|
10
|
+
|
11
|
+
@_associations ||= {}
|
12
|
+
@_associations[key] = klass
|
13
|
+
define_method(key) do
|
14
|
+
unless _attributes[key].is_a?(Array) || _attributes[key].is_a?(Flexirest::ResultIterator)
|
15
|
+
return _attributes[key]
|
16
|
+
end
|
17
|
+
|
18
|
+
if _attributes[key].size == 0
|
19
|
+
return _attributes[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
if _attributes[key][0].is_a?(klass)
|
23
|
+
return _attributes[key]
|
24
|
+
end
|
25
|
+
|
26
|
+
_attributes[key].each_with_index do |v, k|
|
27
|
+
_attributes[key][k] = klass.new(v)
|
28
|
+
end
|
29
|
+
|
30
|
+
_attributes[key]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_one(key, klass = nil)
|
35
|
+
if klass.nil?
|
36
|
+
klass = key.to_s.classify.constantize
|
37
|
+
end
|
38
|
+
|
39
|
+
@_associations ||= {}
|
40
|
+
@_associations[key] = klass
|
41
|
+
define_method(key) do
|
42
|
+
if _attributes[key].is_a?(klass)
|
43
|
+
return _attributes[key]
|
44
|
+
end
|
45
|
+
|
46
|
+
_attributes[key] = klass.new(_attributes[key])
|
47
|
+
|
48
|
+
_attributes[key]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.included(base)
|
54
|
+
base.extend(ClassMethods)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/flexirest/base.rb
CHANGED
data/lib/flexirest/caching.rb
CHANGED
@@ -46,7 +46,7 @@ module Flexirest
|
|
46
46
|
def read_cached_response(request)
|
47
47
|
if cache_store && perform_caching
|
48
48
|
key = "#{request.class_name}:#{request.original_url}"
|
49
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
49
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{key} - Trying to read from cache"
|
50
50
|
value = cache_store.read(key)
|
51
51
|
value = Marshal.load(value) rescue value
|
52
52
|
end
|
@@ -64,7 +64,7 @@ module Flexirest
|
|
64
64
|
|
65
65
|
if cache_store && (headers[:etag] || headers[:expires])
|
66
66
|
key = "#{request.class_name}:#{request.original_url}"
|
67
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
67
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{key} - Writing to cache"
|
68
68
|
cached_response = CachedResponse.new(status:response.status, result:result)
|
69
69
|
cached_response.etag = headers[:etag] if headers[:etag]
|
70
70
|
cached_response.expires = Time.parse(headers[:expires]) rescue nil if headers[:expires]
|
@@ -3,7 +3,7 @@ module Flexirest
|
|
3
3
|
def request_call(event)
|
4
4
|
self.class.time_spent += event.duration
|
5
5
|
self.class.calls_made += 1
|
6
|
-
name = '%s (%.1fms)' % [Flexirest
|
6
|
+
name = '%s (%.1fms)' % [Flexirest.name, event.duration]
|
7
7
|
Flexirest::Logger.debug " \033[1;4;32m#{name}\033[0m #{event.payload[:name]}"
|
8
8
|
end
|
9
9
|
|
@@ -47,7 +47,7 @@ module Flexirest
|
|
47
47
|
module ClassMethods
|
48
48
|
def log_process_action(payload)
|
49
49
|
messages, time_spent, calls_made = super, payload[:flexirest_time_spent], payload[:flexirest_calls_made]
|
50
|
-
messages << ("#{Flexirest
|
50
|
+
messages << ("#{Flexirest.name}: %.1fms for %d calls" % [time_spent.to_f, calls_made]) if calls_made
|
51
51
|
Flexirest::Instrumentation.reset
|
52
52
|
messages
|
53
53
|
end
|
data/lib/flexirest/request.rb
CHANGED
@@ -143,7 +143,7 @@ module Flexirest
|
|
143
143
|
if fake.respond_to?(:call)
|
144
144
|
fake = fake.call(self)
|
145
145
|
end
|
146
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
146
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Faked response found"
|
147
147
|
content_type = @method[:options][:fake_content_type] || "application/json"
|
148
148
|
return handle_response(OpenStruct.new(status:200, body:fake, response_headers:{"X-ARC-Faked-Response" => "true", "Content-Type" => content_type}))
|
149
149
|
end
|
@@ -158,10 +158,10 @@ module Flexirest
|
|
158
158
|
cached = original_object_class.read_cached_response(self)
|
159
159
|
if cached && !cached.is_a?(String)
|
160
160
|
if cached.expires && cached.expires > Time.now
|
161
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
161
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Absolutely cached copy found"
|
162
162
|
return handle_cached_response(cached)
|
163
163
|
elsif cached.etag.to_s != "" #present? isn't working for some reason
|
164
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
164
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Etag cached copy found with etag #{cached.etag}"
|
165
165
|
etag = cached.etag
|
166
166
|
end
|
167
167
|
end
|
@@ -317,7 +317,7 @@ module Flexirest
|
|
317
317
|
base_url.gsub!(%r{//(.)}, "//#{username}:#{password}@\\1") if username && !base_url[%r{//[^/]*:[^/]*@}]
|
318
318
|
connection = Flexirest::ConnectionManager.get_connection(base_url)
|
319
319
|
end
|
320
|
-
Flexirest::Logger.info " \033[1;4;32m#{Flexirest
|
320
|
+
Flexirest::Logger.info " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Requesting #{connection.base_url}#{@url}"
|
321
321
|
|
322
322
|
if verbose?
|
323
323
|
Flexirest::Logger.debug "Flexirest Verbose Log:"
|
@@ -376,7 +376,7 @@ module Flexirest
|
|
376
376
|
status = @response.status || 200
|
377
377
|
|
378
378
|
if cached && response.status == 304
|
379
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
379
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name}" +
|
380
380
|
' - Etag copy is the same as the server'
|
381
381
|
return handle_cached_response(cached)
|
382
382
|
end
|
@@ -386,9 +386,9 @@ module Flexirest
|
|
386
386
|
return @response = response.body
|
387
387
|
elsif is_json_response? || is_xml_response?
|
388
388
|
if @response.respond_to?(:proxied) && @response.proxied
|
389
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
389
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Response was proxied, unable to determine size"
|
390
390
|
else
|
391
|
-
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest
|
391
|
+
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Response received #{@response.body.size} bytes"
|
392
392
|
end
|
393
393
|
result = generate_new_object(ignore_xml_root: @method[:options][:ignore_xml_root])
|
394
394
|
else
|
data/lib/flexirest/version.rb
CHANGED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class AssociationExampleNested < Flexirest::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class AssociationExampleOther < Flexirest::Base
|
7
|
+
has_many :nested, AssociationExampleNested
|
8
|
+
has_one :nested_child, AssociationExampleNested
|
9
|
+
end
|
10
|
+
|
11
|
+
class AssociationExampleBase < Flexirest::Base
|
12
|
+
has_many :others, AssociationExampleOther
|
13
|
+
has_many :association_example_others
|
14
|
+
|
15
|
+
has_one :child, AssociationExampleOther
|
16
|
+
has_one :association_example_other
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "Has Many Associations" do
|
20
|
+
let(:subject) {AssociationExampleBase.new}
|
21
|
+
|
22
|
+
it "should return the attribute if it's not an iterable type" do
|
23
|
+
subject.others = "foo"
|
24
|
+
expect(subject.others).to eq("foo")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return the attribute if it's an empty array" do
|
28
|
+
subject.others = []
|
29
|
+
expect(subject.others).to eq([])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return a list of the association class" do
|
33
|
+
subject.others = [{test: "foo"}]
|
34
|
+
expect(subject.others.first).to be_an(AssociationExampleOther)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return correctly instantiated association classes" do
|
38
|
+
subject.others = [{test: "foo"}]
|
39
|
+
expect(subject.others.first.test).to eq("foo")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should automatically guess the association class if possible" do
|
43
|
+
subject.association_example_others = [{test: "foo"}]
|
44
|
+
expect(subject.association_example_others.first.test).to eq("foo")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should not reinstantiate objects if it's already been called" do
|
48
|
+
subject.others = [AssociationExampleOther.new(test: "foo")]
|
49
|
+
expect(AssociationExampleOther).to_not receive(:new)
|
50
|
+
subject.others
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return correctly instantiated nested associations" do
|
54
|
+
subject.others = [{nested: [{test: "foo"}]}]
|
55
|
+
expect(subject.others.first.nested.first.test).to eq("foo")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "Has One Associations" do
|
60
|
+
let(:subject) {AssociationExampleBase.new}
|
61
|
+
|
62
|
+
it "should return a list of the association class" do
|
63
|
+
subject.child = {test: "foo"}
|
64
|
+
expect(subject.child).to be_an(AssociationExampleOther)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return correctly instantiated association classes" do
|
68
|
+
subject.child = {test: "foo"}
|
69
|
+
expect(subject.child.test).to eq("foo")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should automatically guess the association class if possible" do
|
73
|
+
subject.association_example_other = {test: "foo"}
|
74
|
+
expect(subject.association_example_other.test).to eq("foo")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should not reinstantiate objects if it's already been called" do
|
78
|
+
subject.child = AssociationExampleOther.new(test: "foo")
|
79
|
+
expect(AssociationExampleOther).to_not receive(:new)
|
80
|
+
subject.child
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return correctly instantiated nested associations" do
|
84
|
+
subject.child = {nested_child: {test: "foo"}}
|
85
|
+
expect(subject.child.nested_child.test).to eq("foo")
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Flexirest do
|
4
|
+
|
5
|
+
after(:each) do
|
6
|
+
# Reload Module after each test to ensure name variable is reset to default
|
7
|
+
load 'flexirest.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should be named Flexirest" do
|
11
|
+
expect(Flexirest.name).to eq('Flexirest')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should allow setting to something else" do
|
15
|
+
Flexirest.name = 'SomethingElse'
|
16
|
+
expect(Flexirest.name).to eq('SomethingElse')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
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.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Jeffries
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -250,12 +250,14 @@ files:
|
|
250
250
|
- Gemfile
|
251
251
|
- Guardfile
|
252
252
|
- LICENSE.txt
|
253
|
+
- Migrating-from-ActiveRestClient.md
|
253
254
|
- README.md
|
254
255
|
- Rakefile
|
255
256
|
- doc/Flexirest Internals.graffle
|
256
257
|
- doc/Flexirest Internals.png
|
257
258
|
- flexirest.gemspec
|
258
259
|
- lib/flexirest.rb
|
260
|
+
- lib/flexirest/associations.rb
|
259
261
|
- lib/flexirest/attribute_parsing.rb
|
260
262
|
- lib/flexirest/base.rb
|
261
263
|
- lib/flexirest/caching.rb
|
@@ -277,12 +279,14 @@ files:
|
|
277
279
|
- lib/flexirest/result_iterator.rb
|
278
280
|
- lib/flexirest/validation.rb
|
279
281
|
- lib/flexirest/version.rb
|
282
|
+
- spec/lib/associations_spec.rb
|
280
283
|
- spec/lib/attribute_parsing_spec.rb
|
281
284
|
- spec/lib/base_spec.rb
|
282
285
|
- spec/lib/caching_spec.rb
|
283
286
|
- spec/lib/configuration_spec.rb
|
284
287
|
- spec/lib/connection_manager_spec.rb
|
285
288
|
- spec/lib/connection_spec.rb
|
289
|
+
- spec/lib/flexirest_spec.rb
|
286
290
|
- spec/lib/headers_list_spec.rb
|
287
291
|
- spec/lib/instrumentation_spec.rb
|
288
292
|
- spec/lib/lazy_association_loader_spec.rb
|
@@ -317,7 +321,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
317
321
|
version: '0'
|
318
322
|
requirements: []
|
319
323
|
rubyforge_project:
|
320
|
-
rubygems_version: 2.
|
324
|
+
rubygems_version: 2.5.1
|
321
325
|
signing_key:
|
322
326
|
specification_version: 4
|
323
327
|
summary: This gem is for accessing REST services in a flexible way. ActiveResource
|
@@ -325,12 +329,14 @@ summary: This gem is for accessing REST services in a flexible way. ActiveResou
|
|
325
329
|
Rails conventions, it doesn't have in-built caching and it's not as flexible in
|
326
330
|
general.
|
327
331
|
test_files:
|
332
|
+
- spec/lib/associations_spec.rb
|
328
333
|
- spec/lib/attribute_parsing_spec.rb
|
329
334
|
- spec/lib/base_spec.rb
|
330
335
|
- spec/lib/caching_spec.rb
|
331
336
|
- spec/lib/configuration_spec.rb
|
332
337
|
- spec/lib/connection_manager_spec.rb
|
333
338
|
- spec/lib/connection_spec.rb
|
339
|
+
- spec/lib/flexirest_spec.rb
|
334
340
|
- spec/lib/headers_list_spec.rb
|
335
341
|
- spec/lib/instrumentation_spec.rb
|
336
342
|
- spec/lib/lazy_association_loader_spec.rb
|