api_resource 0.3.12 → 0.3.13
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.
- data/VERSION +1 -1
- data/api_resource.gemspec +4 -3
- data/lib/api_resource/associations/has_many_remote_object_proxy.rb +1 -1
- data/lib/api_resource/associations/has_many_through_remote_object_proxy.rb +13 -0
- data/lib/api_resource/associations/relation_scope.rb +3 -1
- data/lib/api_resource/associations/resource_scope.rb +4 -2
- data/lib/api_resource/associations/scope.rb +6 -1
- data/lib/api_resource/associations.rb +2 -1
- data/lib/api_resource/base.rb +14 -7
- data/lib/api_resource/scopes.rb +1 -1
- data/spec/lib/associations_spec.rb +36 -4
- data/spec/lib/base_spec.rb +8 -0
- data/spec/support/mocks/association_mocks.rb +4 -0
- data/spec/support/test_resource.rb +4 -0
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.13
|
data/api_resource.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "api_resource"
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.13"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ethan Langevin"]
|
12
|
-
s.date = "2012-09-
|
12
|
+
s.date = "2012-09-20"
|
13
13
|
s.description = "A replacement for ActiveResource for RESTful APIs that handles associated object and multiple data sources"
|
14
14
|
s.email = "ejl6266@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -35,6 +35,7 @@ Gem::Specification.new do |s|
|
|
35
35
|
"lib/api_resource/associations/belongs_to_remote_object_proxy.rb",
|
36
36
|
"lib/api_resource/associations/dynamic_resource_scope.rb",
|
37
37
|
"lib/api_resource/associations/has_many_remote_object_proxy.rb",
|
38
|
+
"lib/api_resource/associations/has_many_through_remote_object_proxy.rb",
|
38
39
|
"lib/api_resource/associations/has_one_remote_object_proxy.rb",
|
39
40
|
"lib/api_resource/associations/multi_argument_resource_scope.rb",
|
40
41
|
"lib/api_resource/associations/multi_object_proxy.rb",
|
@@ -83,7 +84,7 @@ Gem::Specification.new do |s|
|
|
83
84
|
s.homepage = "http://github.com/ejlangev/resource"
|
84
85
|
s.licenses = ["MIT"]
|
85
86
|
s.require_paths = ["lib"]
|
86
|
-
s.rubygems_version = "1.8.
|
87
|
+
s.rubygems_version = "1.8.22"
|
87
88
|
s.summary = "A replacement for ActiveResource for RESTful APIs that handles associated object and multiple data sources"
|
88
89
|
|
89
90
|
if s.respond_to? :specification_version then
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ApiResource
|
2
|
+
module Associations
|
3
|
+
module HasManyThroughRemoteObjectProxy
|
4
|
+
def has_many_through_remote(association, options)
|
5
|
+
self.instance_eval do
|
6
|
+
send(:define_method, association) do
|
7
|
+
send(options[:through]).collect{ |t| t.send(association.to_s.singularize) }.flatten
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -8,7 +8,9 @@ module ApiResource
|
|
8
8
|
|
9
9
|
# Use this method to access the internal data, this guarantees that loading only occurs once per object
|
10
10
|
def internal_object
|
11
|
-
|
11
|
+
ApiResource.with_ttl(ttl) do
|
12
|
+
@internal_object ||= self.klass.send(:load_scope_with_options, self.current_scope, self.to_hash)
|
13
|
+
end
|
12
14
|
end
|
13
15
|
#
|
14
16
|
# class factory
|
@@ -9,7 +9,9 @@ module ApiResource
|
|
9
9
|
include Enumerable
|
10
10
|
|
11
11
|
def internal_object
|
12
|
-
|
12
|
+
ApiResource.with_ttl(ttl) do
|
13
|
+
@internal_object ||= self.klass.send(:find, :all, :params => self.to_hash)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
17
|
alias_method :all, :internal_object
|
@@ -31,4 +33,4 @@ module ApiResource
|
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
34
|
-
end
|
36
|
+
end
|
@@ -12,6 +12,7 @@ module ApiResource
|
|
12
12
|
# Holds onto the association proxy this RelationScope is bound to
|
13
13
|
@klass = klass
|
14
14
|
@parent = opts.delete(:parent)
|
15
|
+
@ttl = opts.delete(:expires_in)
|
15
16
|
# splits on _and_ and sorts to get a consistent scope key order
|
16
17
|
@current_scope = (self.parent_scope + Array.wrap(current_scope.to_s)).sort
|
17
18
|
# define methods for the scopes of the object
|
@@ -32,7 +33,11 @@ module ApiResource
|
|
32
33
|
# This expression substitutes the options from opts into the default attributes of the scope, it will only copy keys that exist in the original
|
33
34
|
self.scopes[self.current_scope] = opts.inject(self.scopes[current_scope]){|accum,(k,v)| accum.key?(k.to_s) ? accum.merge(k.to_s => v) : accum}
|
34
35
|
end
|
35
|
-
|
36
|
+
|
37
|
+
def ttl
|
38
|
+
@ttl || 0
|
39
|
+
end
|
40
|
+
|
36
41
|
# Use this method to access the internal data, this guarantees that loading only occurs once per object
|
37
42
|
def internal_object
|
38
43
|
raise "Not Implemented: This method must be implemented in a subclass"
|
@@ -10,6 +10,7 @@ require 'api_resource/associations/single_object_proxy'
|
|
10
10
|
require 'api_resource/associations/belongs_to_remote_object_proxy'
|
11
11
|
require 'api_resource/associations/has_one_remote_object_proxy'
|
12
12
|
require 'api_resource/associations/has_many_remote_object_proxy'
|
13
|
+
require 'api_resource/associations/has_many_through_remote_object_proxy'
|
13
14
|
require 'api_resource/associations/related_object_hash'
|
14
15
|
|
15
16
|
module ApiResource
|
@@ -50,7 +51,7 @@ module ApiResource
|
|
50
51
|
self.activate_associations(
|
51
52
|
:has_many_remote => :has_many_remote,
|
52
53
|
:belongs_to_remote => :belongs_to_remote,
|
53
|
-
:has_one_remote => :has_one_remote
|
54
|
+
:has_one_remote => :has_one_remote,
|
54
55
|
)
|
55
56
|
end
|
56
57
|
end
|
data/lib/api_resource/base.rb
CHANGED
@@ -260,16 +260,23 @@ module ApiResource
|
|
260
260
|
self.new(attributes).tap{ |resource| resource.save }
|
261
261
|
end
|
262
262
|
|
263
|
+
# This decides which finder method to call.
|
264
|
+
# It accepts arguments of the form "scope", "options={}"
|
265
|
+
# where options can be standard rails options or :expires_in.
|
266
|
+
# If :expires_in is set, it caches it for expires_in seconds.
|
263
267
|
def find(*arguments)
|
264
268
|
scope = arguments.slice!(0)
|
265
269
|
options = arguments.slice!(0) || {}
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
270
|
+
|
271
|
+
expiry = options.delete(:expires_in) || ApiResource::Base.ttl || 0
|
272
|
+
ApiResource.with_ttl(expiry.to_f) do
|
273
|
+
case scope
|
274
|
+
when :all then find_every(options)
|
275
|
+
when :first then find_every(options).first
|
276
|
+
when :last then find_every(options).last
|
277
|
+
when :one then find_one(options)
|
278
|
+
else find_single(scope, options)
|
279
|
+
end
|
273
280
|
end
|
274
281
|
end
|
275
282
|
|
data/lib/api_resource/scopes.rb
CHANGED
@@ -393,6 +393,20 @@ describe "Associations" do
|
|
393
393
|
ap.times_loaded.should eql(1)
|
394
394
|
end
|
395
395
|
|
396
|
+
it "should load scopes with caching" do
|
397
|
+
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
398
|
+
ap.times_loaded.should eql(0)
|
399
|
+
ap.active(:active => true, :expires_in => 10).internal_object
|
400
|
+
ap.times_loaded.should eql(1)
|
401
|
+
ap.active(:active => true, :expires_in => 10).ttl.should eql(10)
|
402
|
+
end
|
403
|
+
|
404
|
+
it "should cache scopes when caching enabled" do
|
405
|
+
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
406
|
+
ApiResource.expects(:with_ttl).with(10)
|
407
|
+
ap.active(:active => true, :expires_in => 10).internal_object
|
408
|
+
end
|
409
|
+
|
396
410
|
it "should only load each distinct set of scopes once" do
|
397
411
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
398
412
|
ap.times_loaded.should eql(0)
|
@@ -658,13 +672,11 @@ describe "Associations" do
|
|
658
672
|
end
|
659
673
|
end
|
660
674
|
context "Belongs To" do
|
661
|
-
|
662
675
|
before(:all) do
|
663
676
|
TestAR.class_eval do
|
664
677
|
belongs_to_remote :test_resource
|
665
678
|
end
|
666
679
|
end
|
667
|
-
|
668
680
|
it "should attempt to load a single remote object for a belongs_to relationship" do
|
669
681
|
tar = TestAR.new
|
670
682
|
tar.stubs(:test_resource_id).returns(1)
|
@@ -672,7 +684,6 @@ describe "Associations" do
|
|
672
684
|
# load the test resource
|
673
685
|
tar.test_resource.name.should eql "testing"
|
674
686
|
end
|
675
|
-
|
676
687
|
end
|
677
688
|
context "Has One" do
|
678
689
|
before(:all) do
|
@@ -701,7 +712,28 @@ describe "Associations" do
|
|
701
712
|
# load the test resource
|
702
713
|
tar.has_many_objects.first.name.should eql "testing"
|
703
714
|
end
|
704
|
-
|
715
|
+
end
|
716
|
+
context "Has Many Through" do
|
717
|
+
before(:all) do
|
718
|
+
TestAR.class_eval do
|
719
|
+
self.extend ApiResource::Associations::HasManyThroughRemoteObjectProxy
|
720
|
+
has_many :test_throughs
|
721
|
+
has_many_through_remote(:belongs_to_objects, :through => :test_throughs)
|
722
|
+
end
|
723
|
+
end
|
724
|
+
it "should attempt to load a collection of remote objects for a has_many_through relationship" do
|
725
|
+
tar = TestAR.new
|
726
|
+
through_test_resource_1 = TestThrough.new
|
727
|
+
through_test_resource_2 = TestThrough.new
|
728
|
+
belongs_to_object_1 = BelongsToObject.new
|
729
|
+
belongs_to_object_2 = BelongsToObject.new
|
730
|
+
tar.expects(:test_throughs).returns([through_test_resource_1, through_test_resource_2])
|
731
|
+
through_test_resource_1.expects(:belongs_to_object).returns([belongs_to_object_1])
|
732
|
+
through_test_resource_2.expects(:belongs_to_object).returns([belongs_to_object_2])
|
733
|
+
|
734
|
+
tar.belongs_to_objects.should eql [belongs_to_object_1, belongs_to_object_2]
|
735
|
+
end
|
736
|
+
|
705
737
|
end
|
706
738
|
end
|
707
739
|
end
|
data/spec/lib/base_spec.rb
CHANGED
@@ -621,6 +621,14 @@ describe "Base" do
|
|
621
621
|
ApiResource.stubs(:cache => cache)
|
622
622
|
TestResource.find(123)
|
623
623
|
end
|
624
|
+
|
625
|
+
it "should find with expires_in and cache" do
|
626
|
+
ApiResource.cache.expects(:fetch).with(anything, :expires_in => 10.0).returns({:id => 2, :name => "d"})
|
627
|
+
res = TestResource.find("adfa", :expires_in => 10)
|
628
|
+
|
629
|
+
ApiResource::Base.ttl.should eql(1)
|
630
|
+
res.id.to_i.should eql(2)
|
631
|
+
end
|
624
632
|
end
|
625
633
|
|
626
634
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api_resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.13
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -438,6 +438,7 @@ files:
|
|
438
438
|
- lib/api_resource/associations/belongs_to_remote_object_proxy.rb
|
439
439
|
- lib/api_resource/associations/dynamic_resource_scope.rb
|
440
440
|
- lib/api_resource/associations/has_many_remote_object_proxy.rb
|
441
|
+
- lib/api_resource/associations/has_many_through_remote_object_proxy.rb
|
441
442
|
- lib/api_resource/associations/has_one_remote_object_proxy.rb
|
442
443
|
- lib/api_resource/associations/multi_argument_resource_scope.rb
|
443
444
|
- lib/api_resource/associations/multi_object_proxy.rb
|
@@ -497,7 +498,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
497
498
|
version: '0'
|
498
499
|
segments:
|
499
500
|
- 0
|
500
|
-
hash:
|
501
|
+
hash: 3537958463116260436
|
501
502
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
502
503
|
none: false
|
503
504
|
requirements:
|
@@ -506,7 +507,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
506
507
|
version: '0'
|
507
508
|
requirements: []
|
508
509
|
rubyforge_project:
|
509
|
-
rubygems_version: 1.8.
|
510
|
+
rubygems_version: 1.8.22
|
510
511
|
signing_key:
|
511
512
|
specification_version: 3
|
512
513
|
summary: A replacement for ActiveResource for RESTful APIs that handles associated
|