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 CHANGED
@@ -1 +1 @@
1
- 0.3.12
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.12"
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-11"
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.24"
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
@@ -13,4 +13,4 @@ module ApiResource
13
13
  end
14
14
  end
15
15
  end
16
- end
16
+ end
@@ -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
- @internal_object ||= self.klass.send(:load_scope_with_options, self.current_scope, self.to_hash)
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
- @internal_object ||= self.klass.send(:find, :all, :params => self.to_hash)
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
@@ -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
- case scope
268
- when :all then find_every(options)
269
- when :first then find_every(options).first
270
- when :last then find_every(options).last
271
- when :one then find_one(options)
272
- else find_single(scope, options)
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
 
@@ -42,4 +42,4 @@ module ApiResource
42
42
  end
43
43
 
44
44
  end
45
- end
45
+ end
@@ -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
@@ -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
@@ -54,5 +54,9 @@ Mocks.define do
54
54
  endpoint("/childern/new") do
55
55
  get({})
56
56
  end
57
+
58
+ endpoint("/test_throughs/new") do
59
+ get({})
60
+ end
57
61
 
58
62
  end
@@ -39,6 +39,10 @@ class ErrorFullMessageResource < ApiResource::Base
39
39
 
40
40
  end
41
41
 
42
+ class TestThrough < ApiResource::Base
43
+
44
+ end
45
+
42
46
  module TestMod
43
47
 
44
48
  module InnerMod
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.12
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-11 00:00:00.000000000 Z
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: 2099614695071453573
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.24
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