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 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