httparty-icebox 0.0.1

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.
@@ -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
+