filecache 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/COPYING +24 -0
  2. data/README +27 -0
  3. data/lib/filecache.rb +107 -0
  4. data/tests/test_filecache.rb +34 -0
  5. metadata +57 -0
data/COPYING ADDED
@@ -0,0 +1,24 @@
1
+ FileCache is distributed under the MIT license
2
+
3
+ Copyright (c) 2008 Simon Whitaker <mailto:sw@netcetera.org>
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the "Software"), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,27 @@
1
+ = FileCache
2
+
3
+ FileCache is a file-based caching library for Ruby
4
+
5
+ = Synopsis
6
+
7
+ cache = FileCache.new
8
+ cache.set(:key, "value")
9
+ puts cache.get(:key) # "value"
10
+ cache.delete(:key)
11
+ puts cache.get(:key) # nil
12
+
13
+ # create a new cache called "my-cache", rooted in /home/simon/caches
14
+ # with an expiry time of 30 seconds, and a file hierarchy three
15
+ # directories deep
16
+ cache = FileCache.new("my-cache", "/home/simon/caches", 30, 3)
17
+ cache.put("joe", "bloggs")
18
+ puts(cache.get("joe")) # "bloggs"
19
+ sleep 30
20
+ puts(cache.get("joe")) # nil
21
+
22
+
23
+ = Copyright
24
+
25
+ Copyright 2008 Simon Whitaker <mailto:sw@netcetera.org>
26
+
27
+ See COPYING for license.
@@ -0,0 +1,107 @@
1
+ require 'digest/md5'
2
+ require 'fileutils'
3
+
4
+ # A file-based caching library. It uses Marshal::dump and Marshal::load
5
+ # to serialize/deserialize cache values - so you should be OK to cache
6
+ # object values.
7
+ class FileCache
8
+
9
+ MAX_DEPTH = 32
10
+
11
+ # Create a new reference to a file cache system.
12
+ # domain:: A string that uniquely identifies this caching
13
+ # system on the given host
14
+ # root_dir:: The root directory of the cache file hierarchy
15
+ # The cache will be rooted at root_dir/domain/
16
+ # expiry:: The expiry time for cache entries, in seconds. Use
17
+ # 0 if you want cached values never to expire.
18
+ # depth:: The depth of the file tree storing the cache. Should
19
+ # be large enough that no cache directory has more than
20
+ # a couple of hundred objects in it
21
+ def initialize(domain = "default", root_dir = "/tmp", expiry = 0, depth = 2)
22
+ @domain = domain
23
+ @root_dir = root_dir
24
+ @expiry = expiry
25
+ @depth = depth > MAX_DEPTH ? MAX_DEPTH : depth
26
+ end
27
+
28
+ # Set a cache value for the given key. If the cache contains an existing value for
29
+ # the key it will be overwritten.
30
+ def set(key, value)
31
+ f = File.open(get_path(key), "w")
32
+ Marshal.dump(value, f)
33
+ f.close
34
+ end
35
+
36
+ # Return the value for the specified key from the cache. Returns nil if
37
+ # the value isn't found.
38
+ def get(key)
39
+ path = get_path(key)
40
+
41
+ # expire
42
+ if @expiry > 0 && File.exists?(path) && Time.new - File.new(path).mtime >= @expiry
43
+ FileUtils.rm(path)
44
+ end
45
+
46
+ if File.exists?(path)
47
+ f = File.open(path, "r")
48
+ result = Marshal.load(f)
49
+ f.close
50
+ return result
51
+ else
52
+ return nil
53
+ end
54
+ end
55
+
56
+ # Delete the value for the given key from the cache
57
+ def delete(key)
58
+ FileUtils.rm(get_path(key))
59
+ end
60
+
61
+ # Delete ALL data from the cache, regardless of expiry time
62
+ def clear
63
+ if File.exists?(get_root)
64
+ FileUtils.rm_r(get_root)
65
+ end
66
+ end
67
+
68
+ # Delete all expired data from the cache
69
+ def purge
70
+ @t_purge = Time.new
71
+ purge_dir(get_root) if @expiry > 0
72
+ end
73
+
74
+ #-------- private methods ---------------------------------
75
+ private
76
+ def get_path(key)
77
+ md5 = Digest::MD5.hexdigest(key.to_s).to_s
78
+
79
+ dir = File.join(get_root, md5.split(//)[0..@depth - 1])
80
+ FileUtils.mkdir_p(dir)
81
+ return File.join(dir, md5)
82
+ end
83
+
84
+ def get_root
85
+ if @root == nil
86
+ @root = File.join(@root_dir, @domain)
87
+ end
88
+ return @root
89
+ end
90
+
91
+ def purge_dir(dir)
92
+ Dir.foreach(dir) do |f|
93
+ next if f =~ /^\.\.?$/
94
+ path = File.join(dir, f)
95
+ if File.directory?(path)
96
+ purge_dir(path)
97
+ elsif @t_purge - File.new(path).mtime >= @expiry
98
+ FileUtils.rm(path)
99
+ end
100
+ end
101
+
102
+ # Delete empty directories
103
+ if Dir.entries(dir).delete_if{|e| e =~ /^\.\.?$/}.empty?
104
+ Dir.delete(dir)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.push(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+
5
+ require 'filecache'
6
+ require 'test/unit'
7
+
8
+ class TestFileCache < Test::Unit::TestCase
9
+ KEY1 = "key1"
10
+ VALUE1 = "value1"
11
+ VALUE2 = "value2"
12
+
13
+ def test_basic
14
+ f = FileCache.new("unit-test", "/tmp")
15
+
16
+ f.set(KEY1, VALUE1)
17
+ assert_equal(f.get(KEY1), VALUE1, "set/get")
18
+
19
+ f.delete(KEY1)
20
+ assert_nil(f.get(KEY1), "delete")
21
+
22
+ f.set(KEY1, VALUE1)
23
+ assert_equal(f.get(KEY1), VALUE1, "set on previously deleted key")
24
+
25
+ f.set(KEY1, VALUE2)
26
+ assert_equal(f.get(KEY1), VALUE2, "set new value on previously set key")
27
+
28
+ f.purge
29
+ assert_equal(f.get(KEY1), VALUE2, "purge has no effect on cache with expiry=0")
30
+
31
+ f.clear
32
+ assert_nil(f.get(KEY1), "clear removes previously set value")
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: filecache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Whitaker
8
+ autorequire: filecache
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-07 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: sw@netcetera.org
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - COPYING
25
+ files:
26
+ - lib/filecache.rb
27
+ - tests/test_filecache.rb
28
+ - README
29
+ - COPYING
30
+ has_rdoc: true
31
+ homepage: http://netcetera.org
32
+ post_install_message:
33
+ rdoc_options: []
34
+
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.2.0
53
+ signing_key:
54
+ specification_version: 2
55
+ summary: A file-based caching library
56
+ test_files:
57
+ - tests/test_filecache.rb