httparty-icebox 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
6
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/History ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1
2
+
3
+ * major enhancements
4
+ * Initial release.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Kristoffer Sachse
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.
@@ -0,0 +1,64 @@
1
+ # HTTParty-Icebox - Caching for HTTParty
2
+
3
+ ## Description
4
+
5
+ Cache responses in HTTParty models
6
+
7
+ ## Installation
8
+
9
+ ### RubyGems
10
+
11
+ You can install the latest Film Buff gem using RubyGems
12
+
13
+ gem install httparty-icebox
14
+
15
+ ### GitHub
16
+
17
+ Alternatively you can check out the latest code directly from Github
18
+
19
+ git clone http://github.com/sachse/httparty-icebox.git
20
+
21
+ ## Usage
22
+
23
+
24
+
25
+ ### Examples
26
+
27
+ Enable caching with default values:
28
+
29
+ require 'httparty-icebox'
30
+
31
+ include HTTParty::Icebox
32
+
33
+ cache
34
+ # Use HTTParty's .get method as usual, the response will now be cached
35
+ cached_response = HTTParty.get("https://github.com/sachse/httparty-icebox")
36
+
37
+ Cache responses for 5 minutes on the system in the directory "/tmp":
38
+
39
+ require 'httparty-icebox'
40
+
41
+ include HTTParty::Icebox
42
+
43
+ cache :store => 'file', :timeout => 300, :location => '/tmp/'
44
+ # Use HTTParty's .get method as usual, the response will now be cached
45
+ cached_response = HTTParty.get("https://github.com/sachse/httparty-icebox")
46
+
47
+ ## Authors
48
+
49
+ - [Kristoffer Sachse](https://github.com/sachse) (Current maintainer)
50
+
51
+ - [Karel Minarik](http://karmi.cz) (Original creator through [a gist](https://gist.github.com/209521/))
52
+
53
+ ## Contribute
54
+
55
+ Fork the project, implement your changes in it's own branch, and send
56
+ a pull request to me. I'll gladly consider any help or ideas.
57
+
58
+ ### Contributors
59
+
60
+ - [Martyn Loughran](https://github.com/mloughran) - Major parts of this code are based on the architecture of ApiCache.
61
+ - [David Heinemeier Hansson](https://github.com/dhh) - Other parts are inspired by the ActiveSupport::Cache in Ruby On Rails.
62
+ - [Amit Chakradeo](https://github.com/amit) - For pointing out response objects have to be stored marshalled on FS.
63
+ - Marlin Forbes - For pointing out the query parameters have to be included in the cache key.
64
+ - [ramieblatt](https://github.com/ramieblatt) - Original Memcached store.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "httparty-icebox/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "httparty-icebox"
7
+ s.version = Httparty::Icebox::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Kristoffer Sachse", "Karel Minarik"]
10
+ s.email = ["kristoffer@sachse.nu"]
11
+ s.homepage = "https://github.com/sachse/httparty-icebox"
12
+ s.summary = %q{Caching for HTTParty}
13
+ s.description = %q{Cache responses in HTTParty models}
14
+
15
+ s.rubyforge_project = "httparty-icebox"
16
+
17
+ s.add_dependency("httparty", "~> 0.7.4")
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,212 @@
1
+ require 'logger'
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+ require 'pathname'
5
+ require 'digest/md5'
6
+
7
+ module HTTParty #:nodoc:
8
+ # == Caching for HTTParty
9
+ # See documentation in HTTParty::Icebox::ClassMethods.cache
10
+ #
11
+ module Icebox
12
+
13
+ module ClassMethods
14
+
15
+ # Enable caching and set cache options
16
+ # Returns memoized cache object
17
+ #
18
+ # Following options are available, default values are in []:
19
+ #
20
+ # +store+:: Storage mechanism for cached data (memory, filesystem, your own) [memory]
21
+ # +timeout+:: Cache expiration in seconds [60]
22
+ # +logger+:: Path to logfile or logger instance [nil, silent]
23
+ #
24
+ # Any additional options are passed to the Cache constructor
25
+ #
26
+ # Usage:
27
+ #
28
+ # # Enable caching in HTTParty, in memory, for 1 minute
29
+ # cache # Use default values
30
+ #
31
+ # # Enable caching in HTTParty, on filesystem (/tmp), for 10 minutes
32
+ # cache :store => 'file', :timeout => 600, :location => '/tmp/'
33
+ #
34
+ # # Use your own cache store (see +AbstractStore+ class below)
35
+ # cache :store => 'memcached', :timeout => 600, :server => '192.168.1.1:1001'
36
+ #
37
+ def cache(options={})
38
+ options[:store] ||= 'memory'
39
+ options[:timeout] ||= 60
40
+ logger = options[:logger]
41
+ @cache ||= Cache.new( options.delete(:store), options )
42
+ end
43
+
44
+ end
45
+
46
+ # When included, extend class with +cache+ method
47
+ # and redefine +get+ method to use cache
48
+ #
49
+ def self.included(receiver) #:nodoc:
50
+ receiver.extend ClassMethods
51
+ receiver.class_eval do
52
+
53
+ # Get reponse from network
54
+ #
55
+ # TODO: Why alias :new :old is not working here? Returns NoMethodError
56
+ #
57
+ def self.get_without_caching(path, options={})
58
+ perform_request Net::HTTP::Get, path, options
59
+ end
60
+
61
+ # Get response from cache, if available
62
+ #
63
+ def self.get_with_caching(path, options={})
64
+ key = path.downcase # this makes a copy of path
65
+ key << options[:query].to_s if defined? options[:query]
66
+ if cache.exists?(key) and not cache.stale?(key)
67
+ Cache.logger.debug "CACHE -- GET #{path}#{options[:query]}"
68
+ return cache.get(key)
69
+ else
70
+ Cache.logger.debug "/!\\ NETWORK -- GET #{path}#{options[:query]}"
71
+ response = get_without_caching(path, options)
72
+ cache.set(key, response) if response.code.to_s == "200" # this works for string and integer response codes
73
+ return response
74
+ end
75
+ end
76
+
77
+ # Redefine original HTTParty +get+ method to use cache
78
+ #
79
+ def self.get(path, options={})
80
+ self.get_with_caching(path, options)
81
+ end
82
+
83
+ end
84
+ end
85
+
86
+ # === Cache container
87
+ #
88
+ # Pass a store name ('memory', etc) to new
89
+ #
90
+ class Cache
91
+ attr_accessor :store
92
+
93
+ def initialize(store, options={})
94
+ self.class.logger = options[:logger]
95
+ @store = self.class.lookup_store(store).new(options)
96
+ end
97
+
98
+ def get(key); @store.get encode(key) unless stale?(key); end
99
+ def set(key, value);puts "Cache.set, key: #{key}, value: #{value}"; @store.set encode(key), value; end
100
+ def exists?(key); @store.exists? encode(key); end
101
+ def stale?(key); @store.stale? encode(key); end
102
+
103
+ def self.logger; @logger || default_logger; end
104
+ def self.default_logger; logger = ::Logger.new(STDERR); end
105
+
106
+ # Pass a filename (String), IO object, Logger instance or +nil+ to silence the logger
107
+ def self.logger=(device); @logger = device.kind_of?(::Logger) ? device : ::Logger.new(device); end
108
+
109
+ private
110
+
111
+ # Return store class based on passed name
112
+ def self.lookup_store(name)
113
+ store_name = "#{name.capitalize}Store"
114
+ return Store::const_get(store_name)
115
+ rescue NameError => e
116
+ raise Store::StoreNotFound, "The cache store '#{store_name}' was not found. Did you load any such class?"
117
+ end
118
+
119
+ def encode(key); Digest::MD5.hexdigest(key); end
120
+ end
121
+
122
+
123
+ # === Cache stores
124
+ #
125
+ module Store
126
+
127
+ class StoreNotFound < StandardError; end #:nodoc:
128
+
129
+ # ==== Abstract Store
130
+ # Inherit your store from this class
131
+ # *IMPORTANT*: Do not forget to call +super+ in your +initialize+ method!
132
+ #
133
+ class AbstractStore
134
+ def initialize(options={})
135
+ raise ArgumentError, "You need to set the :timeout parameter" unless options[:timeout]
136
+ @timeout = options[:timeout]
137
+ message = "Cache: Using #{self.class.to_s.split('::').last}"
138
+ message << " in location: #{options[:location]}" if options[:location]
139
+ message << " with timeout #{options[:timeout]} sec"
140
+ Cache.logger.info message unless options[:logger].nil?
141
+ return self
142
+ end
143
+ %w{set get exists? stale?}.each do |method_name|
144
+ define_method(method_name) { raise NoMethodError, "Please implement method #{method_name} in your store class" }
145
+ end
146
+ end
147
+
148
+ # ==== Store objects in memory
149
+ # See HTTParty::Icebox::ClassMethods.cache
150
+ #
151
+ class MemoryStore < AbstractStore
152
+ def initialize(options={})
153
+ super; @store = {}; self
154
+ end
155
+ def set(key, value)
156
+ Cache.logger.info("Cache: set (#{key})")
157
+ @store[key] = [Time.now, value]; true
158
+ end
159
+ def get(key)
160
+ data = @store[key][1]
161
+ Cache.logger.info("Cache: #{data.nil? ? "miss" : "hit"} (#{key})")
162
+ data
163
+ end
164
+ def exists?(key)
165
+ !@store[key].nil?
166
+ end
167
+ def stale?(key)
168
+ return true unless exists?(key)
169
+ Time.now - created(key) > @timeout
170
+ end
171
+ private
172
+ def created(key)
173
+ @store[key][0]
174
+ end
175
+ end
176
+
177
+ # ==== Store objects on the filesystem
178
+ # See HTTParty::Icebox::ClassMethods.cache
179
+ #
180
+ class FileStore < AbstractStore
181
+ def initialize(options={})
182
+ super
183
+ options[:location] ||= Dir::tmpdir
184
+ @path = Pathname.new( options[:location] )
185
+ FileUtils.mkdir_p( @path )
186
+ self
187
+ end
188
+ def set(key, value)
189
+ Cache.logger.info("Cache: set (#{key})")
190
+ File.open( @path.join(key), 'w' ) { |file| file << Marshal.dump(value) }
191
+ true
192
+ end
193
+ def get(key)
194
+ data = Marshal.load(File.read( @path.join(key)))
195
+ Cache.logger.info("Cache: #{data.nil? ? "miss" : "hit"} (#{key})")
196
+ data
197
+ end
198
+ def exists?(key)
199
+ File.exists?( @path.join(key) )
200
+ end
201
+ def stale?(key)
202
+ return true unless exists?(key)
203
+ Time.now - created(key) > @timeout
204
+ end
205
+ private
206
+ def created(key)
207
+ File.mtime( @path.join(key) )
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,5 @@
1
+ module Httparty
2
+ module Icebox
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: httparty-icebox
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Kristoffer Sachse
9
+ - Karel Minarik
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-03-15 00:00:00 +01:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: httparty
19
+ prerelease: false
20
+ requirement: &id001 !ruby/object:Gem::Requirement
21
+ none: false
22
+ requirements:
23
+ - - ~>
24
+ - !ruby/object:Gem::Version
25
+ version: 0.7.4
26
+ type: :runtime
27
+ version_requirements: *id001
28
+ description: Cache responses in HTTParty models
29
+ email:
30
+ - kristoffer@sachse.nu
31
+ executables: []
32
+
33
+ extensions: []
34
+
35
+ extra_rdoc_files: []
36
+
37
+ files:
38
+ - .gitignore
39
+ - Gemfile
40
+ - History
41
+ - LICENSE
42
+ - README.md
43
+ - Rakefile
44
+ - httparty-icebox.gemspec
45
+ - lib/httparty-icebox.rb
46
+ - lib/httparty-icebox/version.rb
47
+ has_rdoc: true
48
+ homepage: https://github.com/sachse/httparty-icebox
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project: httparty-icebox
71
+ rubygems_version: 1.6.2
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Caching for HTTParty
75
+ test_files: []
76
+