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