basiccache 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 59373a2671eea1a0d1797e282bd2a7d5e84f1fa9
4
+ data.tar.gz: e19a7bc60ee8be6d5658f6ec227bf466b489c252
5
+ SHA512:
6
+ metadata.gz: 057250fb3fbe1be8bbc55ae2764bc7c748b41f696e33ef810d1a27d7d65fb9b2f0ae72aab245a324207e9d4d5304d84b006f1e82f54ead086441f8e4c711f4b1
7
+ data.tar.gz: 26672ff44bf1ff353e07396c7968eed5c95491b38a0463c12a5917e1db0bdfff6bd89775ac1edc20bb40c8df0330bf7f7c772f6ed4023adc1a7f72ba77036a1a
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Les Aker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ BasicCache
2
+ ========
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/basiccache.png)](http://badge.fury.io/rb/basiccache)
5
+
6
+ Provides a minimal key/value caching layer
7
+
8
+ ## Usage
9
+
10
+ First, initialize a caching object:
11
+
12
+ ```
13
+ require 'basiccache'
14
+ my_cache = BasicCache.new
15
+ ```
16
+
17
+ From then on, when you want to cache the results of some processing, just call my_cache.cache(key) with the processing block:
18
+
19
+ ```
20
+ require 'basiccache'
21
+ require 'benchmark'
22
+
23
+ my_cache = BasicCache.new
24
+
25
+ 3.times do
26
+ puts Benchmark.measure {
27
+ my_cache.cache('foo') do
28
+ (1..50_000).reduce { |acc, i| acc*i }
29
+ end
30
+ }
31
+ end
32
+ ```
33
+
34
+ Results:
35
+
36
+ ```
37
+ # ruby example.rb
38
+ 1.690000 0.000000 1.690000 ( 1.698418)
39
+ 0.000000 0.000000 0.000000 ( 0.000011)
40
+ 0.000000 0.000000 0.000000 ( 0.000005)
41
+ ```
42
+
43
+ To clear the cache, call .clear!:
44
+
45
+ ```
46
+ my_cache = BasicCache.new
47
+
48
+ # do stuff
49
+
50
+ my_cache.clear!
51
+ ```
52
+
53
+ The .clear! method can be passed a key name to clear just a specific key, as well.
54
+
55
+ ## Subclasses
56
+
57
+ ### TimeCache
58
+
59
+ This cache behaves similarly, with the addition of a lifetime attribute.
60
+
61
+ When creating a new cache object, provide a lifetime or use the default of 30 seconds:
62
+
63
+ ```
64
+ default_cache = BasicCache::TimeCache.new
65
+ puts "Default Lifetime: #{default_cache.lifetime}"
66
+
67
+ custom_cache = BasicCache::TimeCache.new(3)
68
+ puts "Default Lifetime: #{custom_cache.lifetime}"
69
+
70
+ custom_cache.cache('test') { "fish" }
71
+ puts "Does the cache include 'test'? #{custom_cache.include? 'test'}"
72
+ sleep 5
73
+ puts "Does the cache include 'test' now? #{custom_cache.include? 'test'}"
74
+ ```
75
+
76
+ This returns the following:
77
+
78
+ ```
79
+ Default Lifetime: 30
80
+ Default Lifetime: 3
81
+ Does the cache include 'test'? true
82
+ Does the cache include 'test' now? false
83
+ ```
84
+
85
+ ## Installation
86
+
87
+ gem install basiccache
88
+
89
+ ## License
90
+
91
+ BasicCache is released under the MIT License. See the bundled LICENSE file for details.
92
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => [:test, :build, :install]
10
+
@@ -0,0 +1,16 @@
1
+ require File.join(Dir.pwd, 'lib/basiccache.rb')
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'basiccache'
5
+ s.version = BasicCache::VERSION
6
+ s.date = Time.now.strftime("%Y-%m-%d")
7
+ s.summary = 'Provides a minimal key/value caching layer'
8
+ s.description = "Allows an application to dynamically cache values and retrieve them later"
9
+ s.authors = ['Les Aker']
10
+ s.email = 'me@lesaker.org'
11
+ s.files = `git ls-files`.split
12
+ s.test_files = `git ls-files test/`.split
13
+ s.homepage = 'https://github.com/akerl/basiccache'
14
+ s.license = 'MIT'
15
+ end
16
+
data/lib/basiccache.rb ADDED
@@ -0,0 +1,115 @@
1
+ ##
2
+ # This module provides a simple key/value cache for storing computation results
3
+
4
+ module BasicCache
5
+ VERSION = '0.0.13'
6
+
7
+ class << self
8
+ ##
9
+ # Insert a helper .new() method for creating a new Cache object
10
+
11
+ def new(*args)
12
+ self::Cache.new(*args)
13
+ end
14
+ end
15
+
16
+ ##
17
+ # If we're using 2.0.0+, caller_locations is available and is much faster.
18
+ # If not, fall back to caller
19
+ # These methods return the name of the calling function 2 levels up
20
+ # This allows them to return the name of whatever called Cache.cache()
21
+
22
+ if Kernel.respond_to? 'caller_locations'
23
+ def self.get_caller
24
+ caller_locations(2, 1).first.label
25
+ end
26
+ else
27
+ def self.get_caller
28
+ caller[1][/`([^']*)'/, 1]
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Cache object, maintains a key/value store
34
+
35
+ class Cache
36
+ attr_reader :store
37
+
38
+ ##
39
+ # Generate an empty store
40
+
41
+ def initialize
42
+ @store = {}
43
+ end
44
+
45
+ ##
46
+ # Empty out either the given key or the full store
47
+
48
+ def clear!(key = nil)
49
+ key.nil? ? @store.clear : @store.delete(key)
50
+ end
51
+
52
+ ##
53
+ # If the key is cached, return it.
54
+ # If not, run the code, cache the result, and return it
55
+
56
+ def cache(key = nil, &code)
57
+ key ||= BasicCache.get_caller
58
+ @store[key.to_sym] ||= code.call
59
+ end
60
+
61
+ ##
62
+ # Return the size of the cache
63
+
64
+ def size
65
+ @store.length
66
+ end
67
+
68
+ ##
69
+ # Check if a value is cached
70
+ # (just a wrapper, designed to be redefined by subclasses)
71
+
72
+ def include?(key = nil)
73
+ key ||= BasicCache.get_caller
74
+ @store.include? key.to_sym
75
+ end
76
+ end
77
+
78
+ ##
79
+ # Time-based cache object
80
+
81
+ class TimeCache < Cache
82
+ attr_reader :lifetime
83
+
84
+ ##
85
+ # Generate an empty store, with a default lifetime of 60 seconds
86
+
87
+ def initialize(lifetime = 30)
88
+ @lifetime = lifetime
89
+ @cache_item = Struct.new(:stamp, :value)
90
+ super()
91
+ end
92
+
93
+ ##
94
+ # If the key is cached but expired, clear it
95
+
96
+ def cache(key = nil, &code)
97
+ key ||= BasicCache.get_caller
98
+ key = key.to_sym
99
+ unless @store.include? key and Time.now - @store[key].stamp < @lifetime
100
+ @store[key] = @cache_item.new(Time.now, code.call)
101
+ end
102
+ @store[key].value
103
+ end
104
+
105
+ ##
106
+ # Check if a value is cached and not expired
107
+
108
+ def include?(key = nil)
109
+ key ||= BasicCache.get_caller
110
+ key = key.to_sym
111
+ @store.include? key and Time.now - @store[key].stamp < @lifetime
112
+ end
113
+ end
114
+ end
115
+
@@ -0,0 +1,41 @@
1
+ require 'test/unit'
2
+ require 'benchmark'
3
+ require 'basiccache'
4
+
5
+ class BasicCacheTest < Test::Unit::TestCase
6
+ def compute(n)
7
+ (1..n).reduce { |a, e| a * e }
8
+ end
9
+
10
+ def test_creation
11
+ a = BasicCache.new
12
+ b = BasicCache::Cache.new
13
+ assert_instance_of BasicCache::Cache, a
14
+ assert_instance_of BasicCache::Cache, b
15
+ assert_equal a.store, {}
16
+ assert_equal b.store, {}
17
+ end
18
+
19
+ def test_caching
20
+ cache = BasicCache.new
21
+ cache.cache { compute(10) }
22
+ assert cache.store.include? :test_caching
23
+ assert_equal cache.store[:test_caching], 3628800
24
+ assert_equal cache.cache, 3628800
25
+ end
26
+
27
+ def test_clearing
28
+ cache = BasicCache.new
29
+ cache.cache { compute(10) }
30
+ assert_equal cache.store.length, 1
31
+ cache.clear!
32
+ assert_equal cache.store.length, 0
33
+ end
34
+
35
+ def test_speed_increase
36
+ cache = BasicCache.new
37
+ trials = 2.times.map { Benchmark.measure { cache.cache { compute(50_000) } }.real }
38
+ assert (trials[0] > trials[1]*1000)
39
+ end
40
+ end
41
+
@@ -0,0 +1,49 @@
1
+ require 'test/unit'
2
+ require 'benchmark'
3
+ require 'basiccache'
4
+
5
+ class TimeCacheTest < Test::Unit::TestCase
6
+ def compute(n)
7
+ (1..n).reduce { |a, e| a * e }
8
+ end
9
+
10
+ def test_creation
11
+ a = BasicCache::TimeCache.new
12
+ assert_instance_of BasicCache::TimeCache, a
13
+ assert_equal a.store, {}
14
+ assert_equal a.lifetime, 30
15
+ b = BasicCache::TimeCache.new(10)
16
+ assert_equal b.lifetime, 10
17
+ end
18
+
19
+ def test_caching
20
+ cache = BasicCache::TimeCache.new
21
+ cache.cache { compute(10) }
22
+ assert cache.store.include? :test_caching
23
+ assert_equal cache.store[:test_caching].value, 3628800
24
+ assert_equal cache.cache, 3628800
25
+ end
26
+
27
+ def test_clearing
28
+ cache = BasicCache::TimeCache.new
29
+ cache.cache { compute(10) }
30
+ assert_equal cache.store.length, 1
31
+ cache.clear!
32
+ assert_equal cache.store.length, 0
33
+ end
34
+
35
+ def test_speed_increase
36
+ cache = BasicCache::TimeCache.new
37
+ trials = 2.times.map { Benchmark.measure { cache.cache { compute(50_000) } }.real }
38
+ assert (trials[0] > trials[1]*1000)
39
+ end
40
+
41
+ def test_expiration
42
+ cache = BasicCache::TimeCache.new(3)
43
+ cache.cache(:test) { 100 }
44
+ assert cache.include? :test
45
+ sleep 5
46
+ assert cache.include?(:test) == false
47
+ end
48
+ end
49
+
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: basiccache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.13
5
+ platform: ruby
6
+ authors:
7
+ - Les Aker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Allows an application to dynamically cache values and retrieve them later
14
+ email: me@lesaker.org
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - Gemfile
21
+ - LICENSE
22
+ - README.md
23
+ - Rakefile
24
+ - basiccache.gemspec
25
+ - lib/basiccache.rb
26
+ - test/test_cache.rb
27
+ - test/test_timecache.rb
28
+ homepage: https://github.com/akerl/basiccache
29
+ licenses:
30
+ - MIT
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 2.0.3
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Provides a minimal key/value caching layer
52
+ test_files:
53
+ - test/test_cache.rb
54
+ - test/test_timecache.rb