cached_resource 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *DS_Store
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --backtrace
3
+ --format d
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Andrew Chan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,36 @@
1
+ # CachedResource
2
+ CachedResource helps ActiveResource by caching responses according to request parameters. It can help reduce the lag created by making repeated requests across the network.
3
+
4
+ ## Installation
5
+ gem install cached_resource
6
+
7
+ ## Configuration
8
+ CachedResource works "out of the box" with ActiveResource. By default, it caches responses to an `ActiveSupport::Cache::MemoryStore` and logs to an `ActiveSupport::BufferedLogger` attached to a `StringIO` object. *In a Rails 3 environment*, CachedResource will attach itself to the Rails logger and cache.
9
+
10
+ Turn CachedResource off. This will cause all ActiveResource responses to be retrieved normally (i.e. via the network).
11
+
12
+ CachedResource.off!
13
+
14
+ Turn CachedResource on.
15
+
16
+ CachedResource.on!
17
+
18
+ Set the cache expiry time to 60 seconds.
19
+
20
+ CachedResource.config.cache_time_to_live = 60
21
+
22
+ Set a different logger.
23
+
24
+ CachedResource.config.logger = MyLogger.new
25
+
26
+ Set a different cache store.
27
+
28
+ CachedResource.config.cache = MyCacheStore.new
29
+
30
+ ## Usage
31
+ Sit back and relax! If you need to reload a particular request you can do something like:
32
+
33
+ MyActiveResource.find(:all, :reload => true)
34
+
35
+ ## Testing
36
+ rake
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc "Run all examples"
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "cached_resource/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "cached_resource"
7
+ s.version = CachedResource::VERSION
8
+ s.authors = "Andrew Chan"
9
+ s.email = "email@suspi.net"
10
+ s.homepage = "http://github.com/Ahsizara/cached_resource"
11
+ s.summary = %q{Caching for ActiveResource}
12
+ s.description = %q{Enables request-based caching for ActiveResource}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "activeresource"
20
+ s.add_dependency "activesupport"
21
+ s.add_dependency "term-ansicolor"
22
+
23
+ s.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,72 @@
1
+ module CachedResource
2
+ # The Caching module is included in ActiveResource and
3
+ # handles caching and recaching of responses.
4
+ module Caching
5
+ extend ActiveSupport::Concern
6
+
7
+ # when included, setup a middle man for find
8
+ included do
9
+ class << self
10
+ alias_method_chain :find, :cache
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ # find a resource using the cache or resend the request
17
+ # if :reload is set to true or caching is disabled
18
+ def find_with_cache(*arguments)
19
+ arguments << {} unless arguments.last.is_a?(Hash)
20
+ should_reload = arguments.last.delete(:reload) || !CachedResource.config.cache_enabled
21
+ arguments.pop if arguments.last.empty?
22
+ key = cache_key(arguments)
23
+
24
+ begin
25
+ (should_reload ? find_via_reload(key, *arguments) : find_via_cache(key, *arguments))
26
+ rescue ActiveResource::ServerError, ActiveResource::ConnectionError, SocketError => e
27
+ raise(e)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # try to find a cached response for the given key. If
34
+ # no cache entry exists, send a new request.
35
+ def find_via_cache(key, *arguments)
36
+ result = CachedResource.cache.read(key).try(:dup)
37
+ result && log(:read, "#{key} for #{arguments.inspect}")
38
+ result || find_via_reload(key, *arguments)
39
+ end
40
+
41
+ # re/send the request to fetch the resource. Cache the response
42
+ # for the request.
43
+ def find_via_reload(key, *arguments)
44
+ result = find_without_cache(*arguments)
45
+ CachedResource.cache.write(key, result, :expires_in => CachedResource.config.cache_time_to_live)
46
+ log(:write, "#{key} for #{arguments.inspect}")
47
+ result
48
+ end
49
+
50
+ # generate the request cache key
51
+ def cache_key(*arguments)
52
+ "#{name.parameterize.gsub("-", "/")}/#{arguments.join('/')}".downcase
53
+ end
54
+
55
+ # log a message indicating a cached resource event
56
+ def log(type, msg)
57
+ c = Term::ANSIColor
58
+ type_string = "Cached Resource #{type.to_s.upcase}"
59
+
60
+ case type
61
+ when :read
62
+ type_string = c.intense_black + c.bold + type_string + c.clear
63
+ when :write
64
+ type_string = c.yellow + c.bold + type_string + c.clear
65
+ end
66
+
67
+ CachedResource.logger.info "#{type_string} #{msg}"
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ module CachedResource
2
+ # The Config class is a singleton that contains
3
+ # global configuration options for CacheResource
4
+ class Config
5
+ include Singleton
6
+
7
+ # set default cache time to live to 1 week
8
+ DEFAULT_CACHE_TIME_TO_LIVE = 604800
9
+
10
+ attr_accessor :cache_enabled, :cache_time_to_live, :logger, :cache
11
+
12
+ # initialize the config with caching enabled and
13
+ # a default cache expiry of 7 days. Also initializes
14
+ # the logging and caching mechanisms, setting them to
15
+ # the Rails logger and cache if available. If unavailable,
16
+ # sets them to active support equivalents
17
+ def initialize
18
+ @cache_enabled = true
19
+ @cache_time_to_live = DEFAULT_CACHE_TIME_TO_LIVE
20
+
21
+ @cache = defined?(Rails.cache) && Rails.cache || ActiveSupport::Cache::MemoryStore.new
22
+ @logger = defined?(Rails.logger) && Rails.logger || ActiveSupport::BufferedLogger.new(StringIO.new)
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module CachedResource
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,43 @@
1
+ # sourced from this great gist: https://gist.github.com/947734
2
+ require 'singleton'
3
+ require 'term/ansicolor'
4
+ require 'stringio'
5
+
6
+ require 'active_support/concern'
7
+ require 'cached_resource/config'
8
+ require 'cached_resource/caching'
9
+ require 'cached_resource/version'
10
+
11
+ module CachedResource
12
+
13
+ # Switch cache usage off
14
+ def self.off!
15
+ self.config.cache_enabled = false
16
+ end
17
+
18
+ # Switch cache usage on
19
+ def self.on!
20
+ self.config.cache_enabled = true
21
+ end
22
+
23
+ # retrieve the configured logger
24
+ def self.logger
25
+ config.logger
26
+ end
27
+
28
+ # retrieve the configured cache store
29
+ def self.cache
30
+ config.cache
31
+ end
32
+
33
+ # Retrieve the configuration object
34
+ def self.config
35
+ @@config ||= CachedResource::Config.instance
36
+ end
37
+
38
+ end
39
+
40
+ # Include caching in ActiveResource::Base
41
+ class ActiveResource::Base
42
+ include CachedResource::Caching
43
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ describe CachedResource do
4
+
5
+ before(:all) do
6
+ class Thing < ActiveResource::Base
7
+ self.site = "http://api.thing.com"
8
+ end
9
+
10
+ @thing = {:thing => {:id => 1, :name => "Ada"}}
11
+ @other_thing = {:thing => {:id => 1, :name => "Ari"}}
12
+ @thing_json = @thing.to_json
13
+ @other_thing_json = @other_thing.to_json
14
+ end
15
+
16
+ describe "when enabled" do
17
+
18
+ before(:all) do
19
+ # it's on by default, but lets call the method
20
+ # to make sure it works
21
+ CachedResource.on!
22
+
23
+ ActiveResource::HttpMock.reset!
24
+ ActiveResource::HttpMock.respond_to do |mock|
25
+ mock.get "/things/1.json", {}, @thing_json
26
+ end
27
+ end
28
+
29
+ it "should cache a response" do
30
+ result = Thing.find(1)
31
+ CachedResource.config.cache.read("thing/1").should == result
32
+ end
33
+
34
+ it "should read a response when the request is made again" do
35
+ Thing.find(1)
36
+ # only one request should have been made by the test
37
+ # before this one
38
+ ActiveResource::HttpMock.requests.length.should == 1
39
+ end
40
+
41
+ it "should remake a request when reloaded" do
42
+ Thing.find(1, :reload => true)
43
+ ActiveResource::HttpMock.requests.length.should == 2
44
+ end
45
+
46
+ it "should rewrite the cache when the request is reloaded" do
47
+ old_result = CachedResource.config.cache.read("thing/1")
48
+
49
+ # change the response
50
+ ActiveResource::HttpMock.reset!
51
+ ActiveResource::HttpMock.respond_to do |mock|
52
+ mock.get "/things/1.json", {}, @other_thing_json
53
+ end
54
+
55
+ Thing.find(1, :reload => true)
56
+ new_result = CachedResource.config.cache.read("thing/1")
57
+ # since active resources are equal if and only if they
58
+ # are the same object or an instance of the same class,
59
+ # not new?, and have the same id.
60
+ new_result.name.should_not == old_result.name
61
+ end
62
+ end
63
+
64
+ describe "when disabled" do
65
+
66
+ before(:all) do
67
+ CachedResource.off!
68
+
69
+ ActiveResource::HttpMock.reset!
70
+ ActiveResource::HttpMock.respond_to do |mock|
71
+ mock.get "/things/1.json", {}, @thing_json
72
+ end
73
+ end
74
+
75
+ it "should cache a response" do
76
+ result = Thing.find(1)
77
+ CachedResource.config.cache.read("thing/1").should == result
78
+ end
79
+
80
+ it "should always remake the request" do
81
+ Thing.find(1)
82
+ ActiveResource::HttpMock.requests.length.should == 2
83
+ Thing.find(1)
84
+ ActiveResource::HttpMock.requests.length.should == 3
85
+ end
86
+
87
+ it "should rewrite the cache for each request" do
88
+ old_result = CachedResource.config.cache.read("thing/1")
89
+
90
+ # change the response
91
+ ActiveResource::HttpMock.reset!
92
+ ActiveResource::HttpMock.respond_to do |mock|
93
+ mock.get "/things/1.json", {}, @other_thing_json
94
+ end
95
+
96
+ Thing.find(1)
97
+ new_result = CachedResource.config.cache.read("thing/1")
98
+ # since active resources are equal if and only if they
99
+ # are the same object or an instance of the same class,
100
+ # not new?, and have the same id.
101
+ new_result.name.should_not == old_result.name
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'active_resource'
5
+ require 'active_support'
6
+
7
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
8
+ require 'cached_resource'
9
+
10
+
11
+ RSpec.configure do |config|
12
+ # nada
13
+ end
14
+
15
+ # clear cache at beginning and end of execution
16
+ CachedResource.cache.clear
17
+ at_exit { CachedResource.cache.clear }
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cached_resource
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Andrew Chan
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-20 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ prerelease: false
32
+ name: activeresource
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ type: :runtime
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ hash: 3
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ prerelease: false
46
+ name: activesupport
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ type: :runtime
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ prerelease: false
60
+ name: term-ansicolor
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ type: :development
64
+ requirement: &id004 !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ prerelease: false
74
+ name: rspec
75
+ version_requirements: *id004
76
+ description: Enables request-based caching for ActiveResource
77
+ email: email@suspi.net
78
+ executables: []
79
+
80
+ extensions: []
81
+
82
+ extra_rdoc_files: []
83
+
84
+ files:
85
+ - .gitignore
86
+ - .rspec
87
+ - Gemfile
88
+ - MIT-LICENSE
89
+ - README
90
+ - Rakefile
91
+ - cached_resource.gemspec
92
+ - lib/cached_resource.rb
93
+ - lib/cached_resource/caching.rb
94
+ - lib/cached_resource/config.rb
95
+ - lib/cached_resource/version.rb
96
+ - spec/cached_resource/caching_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: http://github.com/Ahsizara/cached_resource
99
+ licenses: []
100
+
101
+ post_install_message:
102
+ rdoc_options: []
103
+
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ hash: 3
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
123
+ version: "0"
124
+ requirements: []
125
+
126
+ rubyforge_project:
127
+ rubygems_version: 1.8.11
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: Caching for ActiveResource
131
+ test_files:
132
+ - spec/cached_resource/caching_spec.rb
133
+ - spec/spec_helper.rb