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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd0763762a7ac0ddc9a4b65deb81f2351434bb27
4
- data.tar.gz: 4c67c29342a607fdddefa1f3685f3694a6ce0f30
3
+ metadata.gz: bd8c9e532875def5d80496e08867b0f12579dc1d
4
+ data.tar.gz: f4e81c7652797f5fc3dac4c02870691b2b356583
5
5
  SHA512:
6
- metadata.gz: 7e68fc41d9dae157ce978fc60990b9394c393c1781858190abc01e0f63570584846cc52f6f9434bc6efab3a3c7c528365f91c575b2dcf3ca6ea109a2b3478640
7
- data.tar.gz: b5d25f4aeb33ad3265f690efcabd0cca78687097cd82b133afbcc3095fb61e73be17cf6ec256a72720c95de68b488b84c007a74cac61e10993a0705b0c01326b
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
- NAME = "Flexirest"
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
@@ -7,6 +7,7 @@ module Flexirest
7
7
  include Caching
8
8
  include Recording
9
9
  include AttributeParsing
10
+ include Associations
10
11
 
11
12
  attr_accessor :_status
12
13
  attr_accessor :_etag
@@ -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::NAME}\033[0m #{key} - Trying to read from cache"
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::NAME}\033[0m #{key} - Writing to cache"
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::NAME, event.duration]
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::NAME}: %.1fms for %d calls" % [time_spent.to_f, calls_made]) if calls_made
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
@@ -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::NAME}\033[0m #{@instrumentation_name} - Faked response found"
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::NAME}\033[0m #{@instrumentation_name} - Absolutely cached copy found"
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::NAME}\033[0m #{@instrumentation_name} - Etag cached copy found with etag #{cached.etag}"
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::NAME}\033[0m #{@instrumentation_name} - Requesting #{connection.base_url}#{@url}"
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::NAME}\033[0m #{@instrumentation_name}" +
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::NAME}\033[0m #{@instrumentation_name} - Response was proxied, unable to determine size"
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::NAME}\033[0m #{@instrumentation_name} - Response received #{@response.body.size} bytes"
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
@@ -1,3 +1,3 @@
1
1
  module Flexirest
2
- VERSION = "1.2.19"
2
+ VERSION = "1.3.1"
3
3
  end
@@ -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.2.19
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 00:00:00.000000000 Z
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.4.5
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