timedcache 0.1.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,13 @@
1
+ === 0.2 / 2008-02-02
2
+
3
+ * Updated specs to be compatible with the latest rSpec release.
4
+
5
+ * Made thread safe by synchronizing all access to the @store instance
6
+ variable used by a TimedCache instance.
7
+
8
+ * Altered the API so that strings and symbols are not treated as equivalent keys.
9
+ This is in order to prevent unintentional memory leaks.
10
+
11
+ === 0.1 / 2006-12-07
12
+
13
+ * Initial release.
data/Manifest.txt ADDED
@@ -0,0 +1,8 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/timed_cache.rb
6
+ lib/timedcache.rb
7
+ misc/thread_test.rb
8
+ spec/timed_cache_spec.rb
data/README.txt ADDED
@@ -0,0 +1,57 @@
1
+ = timedcache
2
+
3
+ * http://timedcache.rubyforge.org
4
+
5
+ == DESCRIPTION:
6
+
7
+ TimedCache implements a cache in which you can place objects
8
+ and specify a timeout value.
9
+
10
+ If you attempt to retrieve the object within the specified timeout
11
+ period, the object will be returned. If the timeout period has elapsed,
12
+ the TimedCache will return nil.
13
+
14
+ == FEATURES/PROBLEMS:
15
+
16
+ * Memory or file-based data stores available.
17
+ * Thread safety.
18
+
19
+ == SYNOPSIS:
20
+
21
+ cache = TimedCache.new
22
+ cache.put :my_object_key, "Expensive data", 10 #=> "Expensive data"
23
+
24
+ cache.get :my_object_key #=> "Expensive data"
25
+ cache[:my_object_key] #=> "Expensive data"
26
+
27
+ ... 10 seconds later:
28
+ cache.get :my_object_key #=> nil
29
+
30
+ == INSTALL:
31
+
32
+ sudo gem timedcache
33
+
34
+ == LICENSE:
35
+
36
+ (The MIT License)
37
+
38
+ Copyright (c) 2008 Nicholas Dainty
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining
41
+ a copy of this software and associated documentation files (the
42
+ 'Software'), to deal in the Software without restriction, including
43
+ without limitation the rights to use, copy, modify, merge, publish,
44
+ distribute, sublicense, and/or sell copies of the Software, and to
45
+ permit persons to whom the Software is furnished to do so, subject to
46
+ the following conditions:
47
+
48
+ The above copyright notice and this permission notice shall be
49
+ included in all copies or substantial portions of the Software.
50
+
51
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
52
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
53
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
54
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
55
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
56
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
57
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/timedcache.rb'
6
+
7
+ Hoe.new('timedcache', TimedCache::VERSION) do |p|
8
+ p.rubyforge_name = 'timedcache'
9
+ p.author = 'Nicholas Dainty'
10
+ p.email = 'nick@npad.co.uk'
11
+ p.summary = 'A very simple time-based object cache.'
12
+ p.description = p.paragraphs_of('README.txt', 3..4).join("\n\n")
13
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
14
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
15
+ p.remote_rdoc_dir = '' # Place RDocs on project home page.
16
+ end
data/lib/timedcache.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "pstore"
2
+ require "monitor"
2
3
 
3
4
  # == TimedCache
4
5
  #
@@ -39,9 +40,13 @@ require "pstore"
39
40
  #
40
41
  # TimedCache.new(:type => :file, :filename => "my_cache.db")
41
42
  #
43
+ # The file-based cache makes it possible to easily share a cache between several ruby
44
+ # processes. However when using the cache in this way, you will probably want to update the
45
+ # cache by passing a block to the TimedCache#get method (see below for details).
46
+ #
42
47
  # Note that objects that cannot be marshalled (e.g. a Proc) can't be stored using the file-based cache.
43
48
  class TimedCache
44
- Version = "0.1.1"
49
+ VERSION = "0.2"
45
50
 
46
51
  attr_reader :default_timeout
47
52
 
@@ -56,6 +61,7 @@ class TimedCache
56
61
  opts[:type] ||= :memory
57
62
  @default_timeout = opts[:default_timeout] || 60
58
63
  @store = new_store(opts)
64
+ @store.extend(MonitorMixin)
59
65
  end
60
66
 
61
67
  # Add an object to the cache. e.g.:
@@ -64,13 +70,31 @@ class TimedCache
64
70
  # The third parameter is an optional timeout value. If not specified, the
65
71
  # <tt>:default_timeout</tt> for this TimedCache will be used instead.
66
72
  def put(key, value, timeout = @default_timeout)
67
- @store.put(key, value, timeout)
73
+ @store.synchronize do
74
+ @store.put(key, value, timeout) unless value.nil?
75
+ end
68
76
  end
69
77
 
70
78
  # Retrieve the object which the given +key+. If the object has expired or
71
79
  # is not present, +nil+ is returned.
72
- def get(key)
73
- @store.get(key)
80
+ #
81
+ # Optionally, a block can be given. The result of evaluating the block will
82
+ # be substituted as the cache value, if the cache has expired. This is particularly
83
+ # useful when using a file-based cache from multiple ruby processes, as it
84
+ # will prevent your application from making multiple simultaneous attempts to
85
+ # re-populate the cache.
86
+ #
87
+ # e.g.:
88
+ #
89
+ # cache.get("slow_database_query") do
90
+ # MyDatabase.query("SELECT * FROM bigtable...")
91
+ # end
92
+ #
93
+ # The block syntax can also be used with the in-memory cache.
94
+ def get(key, &block)
95
+ @store.synchronize do
96
+ @store.get(key, &block)
97
+ end
74
98
  end
75
99
 
76
100
  # Add to the cache using a hash-like syntax. e.g.:
@@ -91,18 +115,52 @@ class TimedCache
91
115
  protected
92
116
 
93
117
  def new_store(options) #:nodoc:
94
- self.class.const_get(options[:type].to_s.capitalize + "Store").new(options)
118
+ self.class.const_get(options[:type].to_s.capitalize + "Store").new(self, options)
95
119
  end
96
120
 
97
121
  class Store #:nodoc:
98
- def initialize(options)
99
- @options = options
122
+ def initialize(timed_cache, options)
123
+ @timed_cache = timed_cache
124
+ @options = options
125
+ end
126
+
127
+ protected
128
+
129
+ def generic_get(key, timeout, callback, fetch_key = lambda {|k| @cache[key]})
130
+ if object_store = fetch_key.call(key)
131
+ if object_store.expired?
132
+ if callback
133
+ run_callback_and_add_to_cache(key, object_store, callback, timeout)
134
+ else
135
+ # Free up memory:
136
+ @cache[key] = nil
137
+ end
138
+ else
139
+ object_store.object
140
+ end
141
+ elsif callback
142
+ run_callback_and_add_to_cache(key, object_store, callback, timeout)
143
+ end
144
+ end
145
+
146
+ def run_callback_and_add_to_cache(key, object_store, callback, timeout)
147
+ object_store.no_expiry! if object_store
148
+
149
+ begin
150
+ result = callback.call
151
+ rescue
152
+ object_store.reset_expiry! if object_store
153
+ raise
154
+ end
155
+
156
+ @timed_cache.put(key, result, timeout)
157
+ result
100
158
  end
101
159
  end
102
160
 
103
161
  class MemoryStore < Store #:nodoc:
104
- def initialize(options)
105
- super
162
+ def initialize(*args)
163
+ super(*args)
106
164
  @cache = Hash.new
107
165
  end
108
166
 
@@ -113,15 +171,8 @@ class TimedCache
113
171
  value
114
172
  end
115
173
 
116
- def get(key)
117
- if object_store = @cache[key]
118
- if object_store.expired?
119
- # Free up memory:
120
- @cache[key] = nil
121
- else
122
- object_store.object
123
- end
124
- end
174
+ def get(key, timeout = @timed_cache.default_timeout, &block)
175
+ generic_get(key, timeout, block)
125
176
  end
126
177
  end
127
178
 
@@ -135,41 +186,46 @@ class TimedCache
135
186
  @cache = PStore.new(filename)
136
187
  end
137
188
 
138
- def put(key, value, timeout = nil)
139
- @cache.transaction do
140
- @cache[key] = ObjectContainer.new(value, timeout)
141
- end
189
+ def put(key, value, timeout)
190
+ @cache.transaction { @cache[key] = ObjectContainer.new(value, timeout) }
142
191
 
143
192
  # Return just the given value, so that references to the
144
193
  # ObjectStore instance can't be held outside this TimedCache:
145
194
  value
146
195
  end
147
196
 
148
- def get(key)
149
- @cache.transaction do
150
- if object_store = @cache[key]
151
- if object_store.expired?
152
- # Free up memory:
153
- @cache[key] = nil
154
- else
155
- object_store.object
156
- end
157
- end
197
+ def get(key, timeout = @timed_cache.default_timeout, &block)
198
+ if block
199
+ generic_get(key, timeout, block, lambda {|k| @cache.transaction { @cache[key] } })
200
+ else
201
+ @cache.transaction { generic_get(key, timeout, block) }
158
202
  end
159
203
  end
160
204
  end
161
205
 
162
206
  class ObjectContainer #:nodoc:
163
- attr_reader :object
207
+ attr_accessor :object
164
208
 
165
209
  def initialize(object, timeout)
166
210
  @created_at = Time.now.utc
167
211
  @timeout = timeout
168
212
  @object = object
213
+ @frozen = false
169
214
  end
170
215
 
171
216
  def expired?
172
- (Time.now.utc - @timeout) > @created_at
217
+ if @frozen: false
218
+ else
219
+ (Time.now.utc - @timeout) > @created_at
220
+ end
221
+ end
222
+
223
+ def no_expiry!
224
+ @frozen = true
225
+ end
226
+
227
+ def reset_expiry!
228
+ @frozen = false
173
229
  end
174
230
  end
175
231
  end
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(__FILE__), "../lib/timedcache")
2
+
3
+ # This script will almost certainly raise an exception if
4
+ # thread safety is not implemented.
5
+
6
+ db = File.join(File.dirname(__FILE__), "thread_test.db")
7
+
8
+ cache = TimedCache.new(:type => :file, :filename => File.join(db))
9
+
10
+ threads = []
11
+
12
+ 10.times do
13
+ threads << Thread.new do
14
+ 100.times {
15
+ cache.put("thread-safe?", "let's find out")
16
+ cache.get("thread-safe?")
17
+ }
18
+ end
19
+ end
20
+
21
+
22
+ threads.each { |t| t.join }
23
+
24
+ File.delete(db)
@@ -0,0 +1,102 @@
1
+ require File.join(File.dirname(__FILE__), "../lib/timedcache")
2
+
3
+ $filename = File.join(File.dirname(__FILE__), "specs.db")
4
+
5
+ describe "Adding and retrieving objects from the cache" do
6
+ setup do
7
+ @memory_cache = TimedCache.new
8
+ @file_cache = TimedCache.new(:type => :file, :filename => $filename)
9
+ @caches = [@memory_cache, @file_cache]
10
+ end
11
+
12
+ teardown do
13
+ File.delete($filename)
14
+ end
15
+
16
+ it "Can add an object to the cache, specifying a timeout value" do
17
+ @caches.each do |cache|
18
+ cache.put(:myobject, "This needs caching", 10).should == "This needs caching"
19
+ end
20
+ end
21
+
22
+ it "Cache should hold seperate values for each key" do
23
+ @caches.each do |cache|
24
+ cache.put(:myobject, "This needs caching", 10).should == "This needs caching"
25
+ cache.put(:my_other_object, "...and this too", 10).should == "...and this too"
26
+ cache.get(:myobject).should == "This needs caching"
27
+ cache.get(:my_other_object).should == "...and this too"
28
+ end
29
+ end
30
+
31
+ it "String and symbol keys are not treated as equivalent" do
32
+ @caches.each do |cache|
33
+ cache[:symbolkey] = "Referenced by symbol"
34
+ cache["stringkey"] = "Referenced by string"
35
+
36
+ cache[:symbolkey].should == "Referenced by symbol"
37
+ cache["symbolkey"].should == nil
38
+
39
+ cache["stringkey"].should == "Referenced by string"
40
+ cache[:stringkey].should == nil
41
+ end
42
+ end
43
+
44
+ it "After the specified timeout value has elapsed, nil should be returned" do
45
+ @caches.each do |cache|
46
+ cache.put(:myobject, "This needs caching", 0).should == "This needs caching"
47
+ cache.get(:myobject).should == nil
48
+ end
49
+ end
50
+
51
+ it "If no object matching the given key is found, nil should be returned" do
52
+ @caches.each do |cache|
53
+ cache.get(:my_nonexistant_object).should == nil
54
+ end
55
+ end
56
+
57
+ it "Should be able to use an array as a cache key" do
58
+ @caches.each do |cache|
59
+ cache.put([123,234], "Array").should == "Array"
60
+ cache.get([123,234]).should == "Array"
61
+ end
62
+ end
63
+
64
+ it "Passing a block to the TimedCache#get method should substitute the " +
65
+ "result of the block as the value for the given key" do
66
+ @caches.each do |cache|
67
+ cache.put("block_test", 1984, 0)
68
+ cache.get("block_test") { 2001 }.should == 2001
69
+ cache.get("block_test").should == 2001
70
+ end
71
+ end
72
+
73
+ it "Passing a block to TimedCache#get should add the result of the callback " +
74
+ "when there is no existing value for the key given" do
75
+ @caches.each do |cache|
76
+ cache.get("new_key_with_block").should == nil
77
+ cache.get("new_key_with_block") { "Nicholas" }.should == "Nicholas"
78
+ end
79
+ end
80
+ end
81
+
82
+ describe "Specifying a default timeout" do
83
+ it "Should be able to it a default timeout when creating a TimedCache" do
84
+ cache = TimedCache.new(:default_timeout => 20)
85
+ cache.should be_kind_of(TimedCache)
86
+ cache.default_timeout.should == 20
87
+ end
88
+
89
+ it "If no default timeout is set, 60 seconds should be used" do
90
+ cache = TimedCache.new
91
+ cache.should be_kind_of(TimedCache)
92
+ cache.default_timeout.should == 60
93
+ end
94
+
95
+ it "Timeout specified when putting a new object into the cache should override default timeout" do
96
+ cache = TimedCache.new(:default_timeout => 20)
97
+ cache.default_timeout.should == 20
98
+ cache.put("alternative_timeout", "2 minutes", 120)
99
+ cache.instance_variable_get(:@store).instance_variable_get(
100
+ :@cache)["alternative_timeout"].instance_variable_get(:@timeout).should == 120
101
+ end
102
+ end
metadata CHANGED
@@ -1,60 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
3
- specification_version: 1
4
2
  name: timedcache
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.1.1
7
- date: 2007-03-26 00:00:00 +01:00
8
- summary: A very simple time-based object cache.
9
- require_paths:
10
- - lib
11
- email: nick@npad.co.uk
12
- homepage: http://timedcache.rubyforge.org
13
- rubyforge_project: timedcache
14
- description: TimedCache implements a cache in which you can place objects and specify a timeout value. If you attempt to retrieve the object within the specified timeout period, the object will be returned. If the timeout period has elapsed, the TimedCache will return nil.
15
- autorequire: timedcache
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: "0.2"
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Nicholas Dainty
31
- files:
32
- - doc/classes
33
- - doc/created.rid
34
- - doc/files
35
- - doc/fr_class_index.html
36
- - doc/fr_file_index.html
37
- - doc/fr_method_index.html
38
- - doc/index.html
39
- - doc/rdoc-style.css
40
- - lib/timed_cache.rb
41
- - lib/timedcache.rb
42
- - specs/timed_cache_spec.rb
43
- - MIT_LICENSE
44
- test_files: []
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
45
11
 
46
- rdoc_options:
47
- - --main
48
- - TimedCache
49
- - --line-numbers
50
- - --inline-source
51
- extra_rdoc_files:
52
- - MIT_LICENSE
12
+ date: 2008-02-03 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.5.0
23
+ version:
24
+ description: TimedCache implements a cache in which you can place objects and specify a timeout value. If you attempt to retrieve the object within the specified timeout period, the object will be returned. If the timeout period has elapsed, the TimedCache will return nil.
25
+ email: nick@npad.co.uk
53
26
  executables: []
54
27
 
55
28
  extensions: []
56
29
 
30
+ extra_rdoc_files:
31
+ - History.txt
32
+ - Manifest.txt
33
+ - README.txt
34
+ files:
35
+ - History.txt
36
+ - Manifest.txt
37
+ - README.txt
38
+ - Rakefile
39
+ - lib/timed_cache.rb
40
+ - lib/timedcache.rb
41
+ - misc/thread_test.rb
42
+ - spec/timed_cache_spec.rb
43
+ has_rdoc: true
44
+ homepage:
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --main
48
+ - README.txt
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
57
63
  requirements: []
58
64
 
59
- dependencies: []
65
+ rubyforge_project: timedcache
66
+ rubygems_version: 1.0.1
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: A very simple time-based object cache.
70
+ test_files: []
60
71
 
data/MIT_LICENSE DELETED
@@ -1,7 +0,0 @@
1
- Copyright (c) 2006 Nicholas Dainty
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
-
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
-
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/doc/created.rid DELETED
@@ -1 +0,0 @@
1
- Mon Mar 26 22:35:48 +0100 2007
@@ -1,27 +0,0 @@
1
-
2
- <?xml version="1.0" encoding="iso-8859-1"?>
3
- <!DOCTYPE html
4
- PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
-
7
- <!--
8
-
9
- Classes
10
-
11
- -->
12
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
- <head>
14
- <title>Classes</title>
15
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
- <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
- <base target="docwin" />
18
- </head>
19
- <body>
20
- <div id="index">
21
- <h1 class="section-bar">Classes</h1>
22
- <div id="index-entries">
23
- <a href="classes/TimedCache.html">TimedCache</a><br />
24
- </div>
25
- </div>
26
- </body>
27
- </html>
@@ -1,29 +0,0 @@
1
-
2
- <?xml version="1.0" encoding="iso-8859-1"?>
3
- <!DOCTYPE html
4
- PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
-
7
- <!--
8
-
9
- Files
10
-
11
- -->
12
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
- <head>
14
- <title>Files</title>
15
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
- <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
- <base target="docwin" />
18
- </head>
19
- <body>
20
- <div id="index">
21
- <h1 class="section-bar">Files</h1>
22
- <div id="index-entries">
23
- <a href="files/MIT_LICENSE.html">MIT_LICENSE</a><br />
24
- <a href="files/lib/timed_cache_rb.html">lib/timed_cache.rb</a><br />
25
- <a href="files/lib/timedcache_rb.html">lib/timedcache.rb</a><br />
26
- </div>
27
- </div>
28
- </body>
29
- </html>
@@ -1,31 +0,0 @@
1
-
2
- <?xml version="1.0" encoding="iso-8859-1"?>
3
- <!DOCTYPE html
4
- PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
-
7
- <!--
8
-
9
- Methods
10
-
11
- -->
12
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
- <head>
14
- <title>Methods</title>
15
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
- <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
- <base target="docwin" />
18
- </head>
19
- <body>
20
- <div id="index">
21
- <h1 class="section-bar">Methods</h1>
22
- <div id="index-entries">
23
- <a href="classes/TimedCache.html#M000005">[] (TimedCache)</a><br />
24
- <a href="classes/TimedCache.html#M000004">[]= (TimedCache)</a><br />
25
- <a href="classes/TimedCache.html#M000003">get (TimedCache)</a><br />
26
- <a href="classes/TimedCache.html#M000001">new (TimedCache)</a><br />
27
- <a href="classes/TimedCache.html#M000002">put (TimedCache)</a><br />
28
- </div>
29
- </div>
30
- </body>
31
- </html>
data/doc/index.html DELETED
@@ -1,24 +0,0 @@
1
- <?xml version="1.0" encoding="iso-8859-1"?>
2
- <!DOCTYPE html
3
- PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
4
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5
-
6
- <!--
7
-
8
- TimedCache Documentation
9
-
10
- -->
11
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
12
- <head>
13
- <title>TimedCache Documentation</title>
14
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
15
- </head>
16
- <frameset rows="20%, 80%">
17
- <frameset cols="25%,35%,45%">
18
- <frame src="fr_file_index.html" title="Files" name="Files" />
19
- <frame src="fr_class_index.html" name="Classes" />
20
- <frame src="fr_method_index.html" name="Methods" />
21
- </frameset>
22
- <frame src="classes/TimedCache.html" name="docwin" />
23
- </frameset>
24
- </html>
data/doc/rdoc-style.css DELETED
@@ -1,208 +0,0 @@
1
-
2
- body {
3
- font-family: Verdana,Arial,Helvetica,sans-serif;
4
- font-size: 90%;
5
- margin: 0;
6
- margin-left: 40px;
7
- padding: 0;
8
- background: white;
9
- }
10
-
11
- h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
- h1 { font-size: 150%; }
13
- h2,h3,h4 { margin-top: 1em; }
14
-
15
- a { background: #eef; color: #039; text-decoration: none; }
16
- a:hover { background: #039; color: #eef; }
17
-
18
- /* Override the base stylesheet's Anchor inside a table cell */
19
- td > a {
20
- background: transparent;
21
- color: #039;
22
- text-decoration: none;
23
- }
24
-
25
- /* and inside a section title */
26
- .section-title > a {
27
- background: transparent;
28
- color: #eee;
29
- text-decoration: none;
30
- }
31
-
32
- /* === Structural elements =================================== */
33
-
34
- div#index {
35
- margin: 0;
36
- margin-left: -40px;
37
- padding: 0;
38
- font-size: 90%;
39
- }
40
-
41
-
42
- div#index a {
43
- margin-left: 0.7em;
44
- }
45
-
46
- div#index .section-bar {
47
- margin-left: 0px;
48
- padding-left: 0.7em;
49
- background: #ccc;
50
- font-size: small;
51
- }
52
-
53
-
54
- div#classHeader, div#fileHeader {
55
- width: auto;
56
- color: white;
57
- padding: 0.5em 1.5em 0.5em 1.5em;
58
- margin: 0;
59
- margin-left: -40px;
60
- border-bottom: 3px solid #006;
61
- }
62
-
63
- div#classHeader a, div#fileHeader a {
64
- background: inherit;
65
- color: white;
66
- }
67
-
68
- div#classHeader td, div#fileHeader td {
69
- background: inherit;
70
- color: white;
71
- }
72
-
73
-
74
- div#fileHeader {
75
- background: #057;
76
- }
77
-
78
- div#classHeader {
79
- background: #048;
80
- }
81
-
82
-
83
- .class-name-in-header {
84
- font-size: 180%;
85
- font-weight: bold;
86
- }
87
-
88
-
89
- div#bodyContent {
90
- padding: 0 1.5em 0 1.5em;
91
- }
92
-
93
- div#description {
94
- padding: 0.5em 1.5em;
95
- background: #efefef;
96
- border: 1px dotted #999;
97
- }
98
-
99
- div#description h1,h2,h3,h4,h5,h6 {
100
- color: #125;;
101
- background: transparent;
102
- }
103
-
104
- div#validator-badges {
105
- text-align: center;
106
- }
107
- div#validator-badges img { border: 0; }
108
-
109
- div#copyright {
110
- color: #333;
111
- background: #efefef;
112
- font: 0.75em sans-serif;
113
- margin-top: 5em;
114
- margin-bottom: 0;
115
- padding: 0.5em 2em;
116
- }
117
-
118
-
119
- /* === Classes =================================== */
120
-
121
- table.header-table {
122
- color: white;
123
- font-size: small;
124
- }
125
-
126
- .type-note {
127
- font-size: small;
128
- color: #DEDEDE;
129
- }
130
-
131
- .xxsection-bar {
132
- background: #eee;
133
- color: #333;
134
- padding: 3px;
135
- }
136
-
137
- .section-bar {
138
- color: #333;
139
- border-bottom: 1px solid #999;
140
- margin-left: -20px;
141
- }
142
-
143
-
144
- .section-title {
145
- background: #79a;
146
- color: #eee;
147
- padding: 3px;
148
- margin-top: 2em;
149
- margin-left: -30px;
150
- border: 1px solid #999;
151
- }
152
-
153
- .top-aligned-row { vertical-align: top }
154
- .bottom-aligned-row { vertical-align: bottom }
155
-
156
- /* --- Context section classes ----------------------- */
157
-
158
- .context-row { }
159
- .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
- .context-item-value { font-size: small; color: #448; }
161
- .context-item-desc { color: #333; padding-left: 2em; }
162
-
163
- /* --- Method classes -------------------------- */
164
- .method-detail {
165
- background: #efefef;
166
- padding: 0;
167
- margin-top: 0.5em;
168
- margin-bottom: 1em;
169
- border: 1px dotted #ccc;
170
- }
171
- .method-heading {
172
- color: black;
173
- background: #ccc;
174
- border-bottom: 1px solid #666;
175
- padding: 0.2em 0.5em 0 0.5em;
176
- }
177
- .method-signature { color: black; background: inherit; }
178
- .method-name { font-weight: bold; }
179
- .method-args { font-style: italic; }
180
- .method-description { padding: 0 0.5em 0 0.5em; }
181
-
182
- /* --- Source code sections -------------------- */
183
-
184
- a.source-toggle { font-size: 90%; }
185
- div.method-source-code {
186
- background: #262626;
187
- color: #ffdead;
188
- margin: 1em;
189
- padding: 0.5em;
190
- border: 1px dashed #999;
191
- overflow: hidden;
192
- }
193
-
194
- div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
-
196
- /* --- Ruby keyword styles --------------------- */
197
-
198
- .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
-
200
- .ruby-constant { color: #7fffd4; background: transparent; }
201
- .ruby-keyword { color: #00ffff; background: transparent; }
202
- .ruby-ivar { color: #eedd82; background: transparent; }
203
- .ruby-operator { color: #00ffee; background: transparent; }
204
- .ruby-identifier { color: #ffdead; background: transparent; }
205
- .ruby-node { color: #ffa07a; background: transparent; }
206
- .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
- .ruby-regexp { color: #ffa07a; background: transparent; }
208
- .ruby-value { color: #7fffd4; background: transparent; }
@@ -1,80 +0,0 @@
1
- require File.join(File.dirname(__FILE__), "../lib/timedcache")
2
-
3
- $filename = File.join(File.dirname(__FILE__), "specs.db")
4
-
5
- context "Adding and retrieving objects from the cache" do
6
- setup do
7
- @memory_cache = TimedCache.new
8
- @file_cache = TimedCache.new(:type => :file, :filename => $filename)
9
- @caches = [@memory_cache, @file_cache]
10
- end
11
-
12
- teardown do
13
- File.delete($filename)
14
- end
15
-
16
- specify "Can add an object to the cache, specifying a timeout value" do
17
- @caches.each do |cache|
18
- cache.put(:myobject, "This needs caching", 10).should_equal "This needs caching"
19
- end
20
- end
21
-
22
- specify "Cache should hold seperate values for each key" do
23
- @caches.each do |cache|
24
- cache.put(:myobject, "This needs caching", 10).should_equal "This needs caching"
25
- cache.put(:my_other_object, "...and this too", 10).should_equal "...and this too"
26
- cache.get(:myobject).should_equal "This needs caching"
27
- cache.get(:my_other_object).should_equal "...and this too"
28
- end
29
- end
30
-
31
- specify "String and symbol keys are not treated as equivalent" do
32
- @caches.each do |cache|
33
- cache[:symbolkey] = "Referenced by symbol"
34
- cache["stringkey"] = "Referenced by string"
35
-
36
- cache[:symbolkey].should_equal "Referenced by symbol"
37
- cache["symbolkey"].should_equal nil
38
-
39
- cache["stringkey"].should_equal "Referenced by string"
40
- cache[:stringkey].should_equal nil
41
- end
42
- end
43
-
44
- specify "After the specified timeout value has elapsed, nil should be returned" do
45
- @caches.each do |cache|
46
- cache.put(:myobject, "This needs caching", 0).should_equal "This needs caching"
47
- cache.get(:myobject).should_equal nil
48
- end
49
- end
50
-
51
- specify "If no object matching the given key is found, nil should be returned" do
52
- @caches.each do |cache|
53
- cache.get(:my_nonexistant_object).should_equal nil
54
- end
55
- end
56
-
57
- specify "Should be able to use an array as a cache key" do
58
- @caches.each do |cache|
59
- cache.put([123,234], "Array").should_equal "Array"
60
- cache.get([123,234]).should_equal "Array"
61
- end
62
- end
63
- end
64
-
65
- context "Specifying a default timeout" do
66
- specify "Should be able to specify a default timeout when creating a TimedCache" do
67
- cache = TimedCache.new(:default_timeout => 20)
68
- cache.should_be_kind_of TimedCache
69
- cache.default_timeout.should_equal 20
70
- end
71
-
72
- specify "If no default timeout is set, 60 seconds should be used" do
73
- cache = TimedCache.new
74
- cache.should_be_kind_of TimedCache
75
- cache.default_timeout.should_equal 60
76
- end
77
-
78
- specify "Timeout specified when putting a new object into the cache should override default timeout" do
79
- end
80
- end