ruby-blockcache 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +44 -0
  3. data/lib/blockcache.rb +120 -0
  4. metadata +49 -0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2010, Matthew Scharley
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Neither the name of the copyright holder, BlockCache nor the
9
+ names of its contributors may be used to endorse or promote products
10
+ derived from this software without specific prior written permission.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
16
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,44 @@
1
+ # BlockCache
2
+
3
+ by Matthew Scharley
4
+ http://github.com/mscharley/ruby-blockcache
5
+
6
+ ## Overview
7
+
8
+ > In computer science, a cache is a component that improves performance
9
+ > by transparently storing data such that future requests for that
10
+ > data can be served faster.
11
+ >
12
+ > -- [Cache at Wikipedia](http://en.wikipedia.org/wiki/Cache)
13
+
14
+ Typical caches do this by allowing you to store data in them, along with
15
+ a time limit to describe how long this data is valid for. You then need
16
+ to check if the data is available, and if not, regenerate it and store
17
+ it again, ready for next time.
18
+
19
+ BlockCache eliminates all this. You define your cache, describe the
20
+ elements it contains, and then you never have to worry about making
21
+ sure you have fresh data again. Of course, if you need to ensure that
22
+ you are getting clean, uncached data, you can do that too.
23
+
24
+ ## Example Usage
25
+
26
+ require 'blockcache'
27
+
28
+ cache = BlockCache.new
29
+ cache.add('name', 10) do
30
+ puts "Hello, what is your name?"
31
+ STDIN.gets.strip
32
+ end
33
+
34
+ for i in [1,2]
35
+ for j in [1,3]
36
+ puts "Hello " + cache['name'] + "!"
37
+ end
38
+ cache.refresh
39
+ end
40
+
41
+ In the example above, you get asked for your name, then it says
42
+ hello to you three times. Note, each time is using the exact same
43
+ code. The program then tells the cache that it wants fresh data,
44
+ and repeats the process.
@@ -0,0 +1,120 @@
1
+
2
+ # This is a class used to cache data from the repository, so that it
3
+ # needn't be queried over and over. Use a timeout of a few seconds to
4
+ # prevent repeated queries in the same operation, but preserve the
5
+ # ability to retrieve up to date data.
6
+ #
7
+ # You can call #refresh to reset all the timeouts manually if you
8
+ # need to guarantee fresh data
9
+ #
10
+ # Example usage:
11
+ #
12
+ # def cache
13
+ # @cache ||= begin
14
+ # c = BlockCache.new
15
+ # c.add("test", 10) { "Hello world!" }
16
+ # # This block always returns the same thing, so never refresh it
17
+ # c.add("test2") { |name| "Hello #{name}" }
18
+ # c
19
+ # end
20
+ # end
21
+ #
22
+ # cache["test2", "Matthew"] # "Hello Matthew"
23
+
24
+ class BlockCache
25
+
26
+ #attr_reader :values, :accessed
27
+
28
+ def initialize(default=nil)
29
+ @default_value = default
30
+ @blocks = {}
31
+ @timeouts = {}
32
+ @accessed = {}
33
+ @values = {}
34
+ end
35
+
36
+ def add(name, timeout, &block)
37
+ @blocks[name] = block
38
+ @timeouts[name] = timeout
39
+ end
40
+
41
+ def [](name, *args)
42
+ return @default_value if not @blocks.keys.include?(name)
43
+
44
+ atime = get_accessed(@accessed, [name, *args])
45
+ ctime = Time.now
46
+
47
+ if ((not @timeouts[name].nil?) or (not value_exist?(@values, [name, *args]))) and ctime - atime > (@timeouts[name] || 0)
48
+ begin
49
+ set_value(@values, @blocks[name].call(*args), [name, *args])
50
+ rescue
51
+ # dump errors to the console, but otherwise, keep on trucking
52
+ puts $!.message
53
+ puts $!.backtrace
54
+ set_value(@values, @default_value, [name, *args])
55
+ end
56
+
57
+ set_accessed(@accessed, ctime, [name, *args])
58
+ end
59
+
60
+ get_value(@values, [name, *args])
61
+ end
62
+
63
+ def refresh(times=@accessed)
64
+ times.each do |k, v|
65
+ if v.respond_to? '[]'
66
+ refresh v
67
+ else
68
+ times[k] = Time.at(0)
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def value_exist?(values, path)
76
+ while path.length > 1
77
+ curr = path.shift
78
+ values = values[curr]
79
+ return false if not values.respond_to? '[]'
80
+ end
81
+
82
+ return values.keys.include?(path[0])
83
+ end
84
+
85
+ def get_value(values, path)
86
+ get_from_path(values, path, @default_value)
87
+ end
88
+
89
+ def get_accessed(times, path)
90
+ get_from_path(times, path, Time.at(0))
91
+ end
92
+
93
+ def get_from_path(hash, path, default)
94
+ while path.length > 1
95
+ curr = path.shift
96
+ hash = hash[curr]
97
+ return default if not hash.respond_to? '[]'
98
+ end
99
+
100
+ return hash[path[0]] || default
101
+ end
102
+
103
+ def set_value(values, value, path)
104
+ set_from_path(values, value, path)
105
+ end
106
+
107
+ def set_accessed(times, time, path)
108
+ set_from_path(times, time, path)
109
+ end
110
+
111
+ def set_from_path(hash, value, path)
112
+ while path.length > 1
113
+ curr = path.shift
114
+ hash[curr] ||= {}
115
+ hash = hash[curr]
116
+ end
117
+
118
+ hash[path[0]] = value
119
+ end
120
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-blockcache
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.2'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Scharley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-10 00:00:00.000000000 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+ description: ''
16
+ email: []
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/blockcache.rb
22
+ - README.md
23
+ - LICENSE
24
+ has_rdoc: true
25
+ homepage: https://github.com/mscharley/ruby-blockcache
26
+ licenses: []
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 1.6.2
46
+ signing_key:
47
+ specification_version: 3
48
+ summary: Cache implemented in Ruby that knows how to update its own contents
49
+ test_files: []