retriever 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ .DS_Store
7
+ dump.rdb
8
+ coverage
9
+ doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in retriever.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011 Nelvin Driz <ndriz@exist.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,40 @@
1
+ = Retriever
2
+
3
+ A block result caching library.
4
+
5
+ == Installation
6
+
7
+ Either include to your <tt>Gemfile</tt> or install it.
8
+
9
+ # Bash
10
+ $ gem install retriever
11
+
12
+ # Gemfile
13
+ gem 'retriever'
14
+
15
+ == Rails Usage
16
+
17
+ Create file <tt>config/initializer/retriever.rb</tt> with your configuration.
18
+
19
+ === Example <tt>retriever.rb</tt>
20
+
21
+ Retriever.config.storage(:memory)
22
+ Retreiver.catch! do
23
+ target :bone do |parameters|
24
+ ...
25
+ end
26
+ end
27
+
28
+ === Example Usage (Controller)
29
+
30
+ def index
31
+ @bone = Retriever.fetch(:bone)
32
+ end
33
+
34
+ == {Documentation}[http://rubydoc.info/gems/retriever/frames]
35
+
36
+ == License
37
+
38
+ Copyright (c) 2011 Nelvin Driz.
39
+
40
+ Retriever is free software released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ gem 'rdoc'
5
+ require 'rdoc/task'
6
+
7
+ RDoc::Task.new do |rdoc|
8
+ rdoc.rdoc_dir = 'doc'
9
+ rdoc.title = "Retriever #{Retriever::VERSION}"
10
+ rdoc.rdoc_files.include('lib/**/*.rb')
11
+ rdoc.rdoc_files.include('README.rdoc')
12
+ rdoc.options << '--charset' << 'utf-8'
13
+ rdoc.options << '--line-numbers'
14
+ rdoc.main = 'README.rdoc'
15
+ end
16
+
17
+ RSpec::Core::RakeTask.new(:spec) do |t|
18
+ t.pattern = "./spec/**/*_spec.rb"
19
+ t.rspec_opts = ['--color']
20
+ end
@@ -0,0 +1,74 @@
1
+ module Retriever
2
+ # Configuration Namespace
3
+ module Config
4
+ class << self
5
+ # Boolean value to indicate whether or not key used for cache is encrypted or not.
6
+ attr_reader :encrypt
7
+
8
+ # Set encryption to boolean specified
9
+ #
10
+ # ==== Examples
11
+ #
12
+ # Retriever.config.encrypt = true
13
+ # Retriever.config.encrypt = false
14
+ #
15
+ def encrypt=(boolean)
16
+ require 'digest/sha1' if boolean
17
+ @encrypt = boolean
18
+ end
19
+
20
+ # Set storage handler to be used by retriever.
21
+ # This is a requirement to be set so that you
22
+ # can use retriever.
23
+ #
24
+ # ==== Storage Handlers (Built-in)
25
+ #
26
+ # * <tt>:ephemeral</tt> - Uses a ruby hash to store cache.
27
+ # * <tt>:redis</tt> - Use redis. (Requires <tt>redis</tt> gem.)
28
+ #
29
+ # ==== Custom Storage Handlers
30
+ # You can supply your own storage handler. In the class you supply,
31
+ # you need to specify the following methods:
32
+ #
33
+ # * <tt>set(key, value)</tt> - Used to set value in the cache store.
34
+ # * <tt>get(key)</tt> - Used to retrieve value from cache store.
35
+ # * <tt>delete(key)</tt> - Used to delete a record from cache store.
36
+ #
37
+ # ==== Examples
38
+ #
39
+ # Retriever.config.storage(:ephemeral) # Set storage to memory.
40
+ # Retriever.config.storage(:redis) # Set storage to redis.
41
+ #
42
+ # class CustomStorageHandler
43
+ # def set(key, value)
44
+ # ...
45
+ # end
46
+ #
47
+ # def get(key)
48
+ # ...
49
+ # end
50
+ #
51
+ # def delete(key)
52
+ # ...
53
+ # end
54
+ # end
55
+ #
56
+ # Retriever.config.storage(CustomStorageHandler) # Set storage to a custom storage.
57
+ #
58
+ def storage(type)
59
+ if type.is_a? Class
60
+ ::Retriever.storage = type.new if type.is_a?(Class)
61
+ else
62
+ case type
63
+ when :ephemeral
64
+ require File.join(File.dirname(__FILE__), 'storage', 'ephemeral')
65
+ ::Retriever.storage = Retriever::Storage::Ephemeral.new
66
+ when :redis
67
+ require File.join(File.dirname(__FILE__), 'storage', 'redis')
68
+ ::Retriever.storage = Retriever::Storage::Redis.new
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,63 @@
1
+ module Retriever
2
+ # Instruction is used by retriever as an object that would
3
+ # store set attributes and options while specifying your
4
+ # targets in <tt>Retriever.catch!</tt>
5
+ #
6
+ class Instruction
7
+ # Key used by instruction for storage manipulation.
8
+ attr_accessor :key
9
+
10
+ # Block executed to retrieve value to be cached.
11
+ attr_accessor :block
12
+
13
+ # Instantiate Instruction
14
+ #
15
+ # ==== Parameters
16
+ #
17
+ # * <tt>:key</tt> - Key used to store and retrieve value from cache.
18
+ # * <tt>:options</tt> - Options defined in <tt>Retriever.catch!</tt>
19
+ # * <tt>:block</tt> - Block is the <tt>Proc</tt> object to be executed.
20
+ # Resulting value would be the cached.
21
+ #
22
+ def initialize(key, options, block)
23
+ @key = key
24
+ @block = block
25
+ @validity = options[:validity] || 365.days
26
+ end
27
+
28
+ # Checks if value in storage is expired before trying to retrieve
29
+ # a new value. Value in storage is returned if value is still valid.
30
+ #
31
+ # ==== Parameters
32
+ #
33
+ # * <tt>:storage</tt> - Instance of the storage handler.
34
+ # * <tt>:block_parameters</tt> - Arguments sent to the block if value
35
+ # in storage is expired.
36
+ #
37
+ def execute(storage, block_parameters)
38
+ if expired? then execute!(storage, block_parameters) else storage.get(key) end
39
+ end
40
+
41
+ # Cache the result of the block. Just like <tt>execute</tt> but does not
42
+ # check cached value.
43
+ #
44
+ # ==== Parameters
45
+ #
46
+ # * <tt>:storage</tt> - Instance of the storage handler.
47
+ # * <tt>:block_parameters</tt> - Arguments sent to the block if value
48
+ # in storage is expired.
49
+ #
50
+ def execute!(storage, block_parameters)
51
+ @last_execution = Time.now
52
+ storage.set(key, block.call(*block_parameters))
53
+ end
54
+
55
+ private
56
+ # Check if cached value is expired
57
+ #
58
+ def expired?
59
+ return true unless @last_execution
60
+ Time.now - @last_execution > @validity
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,32 @@
1
+ # Storage handler namespace
2
+ module Retriever::Storage
3
+ # Storage handler for a Hash Backend
4
+ class Ephemeral
5
+ # Instance of Hash
6
+ attr_reader :storage
7
+
8
+ # Instantiate hash object as storage of cache.
9
+ #
10
+ def initialize
11
+ @storage = Hash.new
12
+ end
13
+
14
+ # Set record in hash.
15
+ #
16
+ def set(key, value)
17
+ storage[key] = value
18
+ end
19
+
20
+ # Get record from hash.
21
+ #
22
+ def get(key)
23
+ storage[key]
24
+ end
25
+
26
+ # Delete record in hash.
27
+ #
28
+ def delete(key)
29
+ storage.delete(key)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,51 @@
1
+ require 'redis'
2
+ require 'json'
3
+
4
+ module Retriever::Storage
5
+ # Storage handler for a Redis Backend
6
+ class Redis
7
+ # Instance of Redis
8
+ attr_reader :storage
9
+
10
+ # Instantiate Redis Connection (Default Settings Used)
11
+ #
12
+ def initialize
13
+ @storage = ::Redis.new
14
+ end
15
+
16
+ # Set record in storage.
17
+ # Serializes value to JSON if applicable.
18
+ #
19
+ def set(key, value)
20
+ value = serialize(value)
21
+ storage.set(key, value)
22
+ JSON.parse(value) rescue value
23
+ end
24
+
25
+ # Get record from storage.
26
+ # Deserialize value from JSON if applicable.
27
+ #
28
+ def get(key)
29
+ value = storage.get(key)
30
+ JSON.parse(value) rescue value
31
+ end
32
+
33
+ # Delete record from storage.
34
+ #
35
+ def delete(key)
36
+ storage.del key
37
+ end
38
+
39
+ private
40
+ # Serialize value by converting it to JSON if possible.
41
+ #
42
+ def serialize(value)
43
+ case value.class.to_s
44
+ when 'String' then value
45
+ else
46
+ value.to_json rescue value.to_s
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,4 @@
1
+ module Retriever
2
+ # Version of Retriever
3
+ VERSION = "0.1.0"
4
+ end
data/lib/retriever.rb ADDED
@@ -0,0 +1,149 @@
1
+ require File.join('retriever', 'version')
2
+ require File.join('retriever', 'config')
3
+ require File.join('retriever', 'instruction')
4
+
5
+ # Main Retriever Entry Point
6
+ module Retriever
7
+ class << self
8
+ # Instance of storage handler.
9
+ attr_accessor :storage
10
+
11
+ # Array of instructions.
12
+ attr_accessor :instructions
13
+
14
+ # Setup targets for retriever to cache.
15
+ #
16
+ # ==== Example
17
+ #
18
+ # Retriever.catch! do
19
+ # target :bone do
20
+ # 'wishbone'
21
+ # end
22
+ # end
23
+ #
24
+ def catch!(&block)
25
+ @instance_timestamp = Time.now
26
+ @instructions = Hash.new
27
+ self.instance_eval &block
28
+ end
29
+
30
+ # Setup a new <tt>target</tt> for retriever to catch.
31
+ #
32
+ # ==== Parameters
33
+ #
34
+ # * <tt>:name</tt> - Identifier used to call the block whenever you call
35
+ # <tt>fetch</tt> or <tt>fetch!</tt>.
36
+ # * <tt>:options</tt> - Options that modify basic instruction of simply
37
+ # caching the result of the block.
38
+ # * <tt>:block</tt> - The block to be executed with it's result being cached.
39
+ #
40
+ # ==== Options
41
+ #
42
+ # * <tt>:validity</tt> - Sets length of validity of a certain cache.
43
+ # After the cache expires, retriever simply executes the block again.
44
+ #
45
+ # target :bone, :validity => 10.minutes
46
+ #
47
+ # ==== Example
48
+ #
49
+ # Retriever.catch! do
50
+ # @counter = 0
51
+ # target :bone, :validity => 10.minutes do
52
+ # @counter += 1
53
+ # end
54
+ # end
55
+ #
56
+ # Retriever.fetch(:bone) # => 1
57
+ # # After 10 minutes
58
+ # Retreiver.fetch(:bone) # => 2
59
+ #
60
+ def target(name, options = {}, &block)
61
+ key = keyify(name)
62
+ instructions[key] = Instruction.new(key, options, block)
63
+ end
64
+
65
+ # Fetch data based upon the execution result of the corresponding
66
+ # instruction identified by the <tt>target_name</tt>. If data cached
67
+ # is still valid, that data would be returned.
68
+ #
69
+ # ==== Parameters
70
+ #
71
+ # * <tt>:target_name</tt> - The name used to identify the instruction.
72
+ # * <tt>:*block_parameters</tt> - Parameters passed on to the block
73
+ # that is part of the instruction.
74
+ #
75
+ # ==== Examples
76
+ #
77
+ # Retriever.fetch(:bone)
78
+ #
79
+ def fetch(target_name, *block_parameters)
80
+ key = keyify(target_name)
81
+ instruction = instructions[key]
82
+ instruction.execute(storage, block_parameters)
83
+ end
84
+
85
+ # Fetch data based upon the execution result of the corresponding
86
+ # instruction identified by the <tt>target_name</tt>.
87
+ #
88
+ # ==== Parameters
89
+ #
90
+ # * <tt>:target_name</tt> - The name used to identify the instruction.
91
+ # * <tt>:*block_parameters</tt> - Parameters passed on to the block
92
+ # that is part of the instruction.
93
+ #
94
+ # ==== Examples
95
+ #
96
+ # Retriever.fetch(:bone)
97
+ #
98
+ def fetch!(target_name, *block_parameters)
99
+ key = keyify(target_name)
100
+ instruction = instructions[key]
101
+ instruction.execute!(storage, block_parameters)
102
+ end
103
+
104
+ # Check if keys used for the cache store is encrypted or not encrypted.
105
+ # Basis of key is namespaced to retriever as well as timestamped.
106
+ # (Timestamp comes from the instance start.)
107
+ #
108
+ def encrypted?
109
+ config.encrypt || false
110
+ end
111
+
112
+ # Returns config namespace.
113
+ #
114
+ def config
115
+ Config
116
+ end
117
+
118
+ # Delete all cache. Automatically run on instance process termination.
119
+ #
120
+ def clean!
121
+ return unless instructions
122
+ instructions.keys.each do |key|
123
+ storage.delete(key)
124
+ end
125
+ end
126
+
127
+ private
128
+ # Namespaces <tt>target_name</tt> to retriever as well as timestamped
129
+ # with the instance start timestamp. This key is also encrypted using
130
+ # SHA1 if set to be encrypted.
131
+ #
132
+ # ==== Examples
133
+ #
134
+ # To set encryption:
135
+ # Retriever.config.encrypt = true # Set encryption to true
136
+ # Retriever.config.encrypt = false # Set encryption to false
137
+ #
138
+ def keyify(target_name)
139
+ key = "Retriever::#{target_name}::#{@instance_timestamp}"
140
+ key = Digest::SHA1.hexdigest(key) if encrypted?
141
+ return key
142
+ end
143
+
144
+ end
145
+ end
146
+
147
+ at_exit do
148
+ Retriever.clean!
149
+ end
data/retriever.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "retriever/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'retriever'
7
+ s.version = Retriever::VERSION
8
+ s.authors = ['Nelvin Driz']
9
+ s.email = ['ndriz@exist.com']
10
+ s.homepage = "http://github.com/Keoven/Retriever"
11
+ s.summary = %q{Retriever is a block result caching library.}
12
+ s.description = %q{
13
+ Retriever allows caching of the result of a block. It currently supports ruby memory storage and redis.
14
+ }
15
+
16
+ s.rubyforge_project = 'retriever'
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ # Development
24
+ s.add_development_dependency 'rspec'
25
+ s.add_development_dependency 'redis'
26
+ s.add_development_dependency 'yajl-ruby'
27
+ s.add_development_dependency 'rails'
28
+ s.add_development_dependency 'timecop'
29
+ s.add_development_dependency 'ruby-debug19'
30
+ s.add_development_dependency 'simplecov'
31
+
32
+ # Runtime
33
+ s.add_runtime_dependency 'activesupport'
34
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ class Custom
4
+ attr_reader :storage
5
+
6
+ def initialize
7
+ @storage = Hash.new
8
+ end
9
+
10
+ def set(key, value)
11
+ storage[key] = value
12
+ end
13
+
14
+ def get(key)
15
+ storage[key]
16
+ end
17
+
18
+ def delete(key)
19
+ storage.delete(key)
20
+ end
21
+ end
22
+
23
+ describe Retriever do
24
+ before do
25
+ Retriever.config.storage(Custom)
26
+ end
27
+
28
+ it 'should fetch ball' do
29
+ Retriever.catch! do
30
+ target :ball do
31
+ 'ball'
32
+ end
33
+ end
34
+ Retriever.fetch(:ball).should be_eql('ball')
35
+ end
36
+
37
+ it 'should memoize ball' do
38
+ Retriever.catch! do
39
+ target :ball do
40
+ 'ball'
41
+ end
42
+ end
43
+ Retriever.storage.should_receive(:set).once.and_return('ball')
44
+ Retriever.fetch(:ball).should be_eql('ball')
45
+ Retriever.storage.stub!(:get).and_return('ball')
46
+ Retriever.fetch(:ball).should be_eql('ball')
47
+ end
48
+
49
+ it 'should only be valid in 10 minutes' do
50
+ now = Time.now
51
+ Timecop.freeze(now)
52
+ Retriever.catch! do
53
+ @counter = 0
54
+ target :ball, :validity => 10.minutes do
55
+ @counter += 1
56
+ end
57
+ end
58
+ Retriever.fetch(:ball).should be_eql(1)
59
+ Timecop.freeze(now + 5.minutes)
60
+ Retriever.fetch(:ball).should be_eql(1)
61
+ Timecop.freeze(now + 10.minutes)
62
+ Retriever.fetch(:ball).should be_eql(1)
63
+ Timecop.freeze(now + 10.minutes + 1.second)
64
+ Retriever.fetch(:ball).should be_eql(2)
65
+ Timecop.freeze(now + 15.minutes)
66
+ Retriever.fetch(:ball).should be_eql(2)
67
+ Timecop.freeze(now)
68
+ Retriever.fetch(:ball).should be_eql(2)
69
+ Timecop.freeze(now + 30.minutes)
70
+ Retriever.fetch(:ball).should be_eql(3)
71
+ end
72
+
73
+ it 'should be able to pass parameters' do
74
+ Retriever.catch! do
75
+ target :ball do |arg1, arg2|
76
+ arg1 + arg2
77
+ end
78
+ end
79
+
80
+ Retriever.fetch(:ball, 1, 2).should be_eql(3)
81
+ end
82
+
83
+ it 'should be able to fetch forcefully' do
84
+ now = Time.now
85
+ Timecop.freeze(now)
86
+ Retriever.catch! do
87
+ @counter = 0
88
+ target :ball, :validity => 10.minutes do
89
+ @counter += 1
90
+ end
91
+ end
92
+ Retriever.fetch(:ball).should be_eql(1)
93
+ Retriever.fetch!(:ball).should be_eql(2)
94
+ Retriever.fetch(:ball).should be_eql(2)
95
+ end
96
+
97
+ it 'should be encrypted' do
98
+ Retriever.config.encrypt = true
99
+ Retriever.should be_encrypted
100
+ Retriever.catch! do
101
+ target :ball do
102
+ 'ball'
103
+ end
104
+ end
105
+ Retriever.fetch(:ball).should be_eql('ball')
106
+ end
107
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe Retriever do
4
+ before do
5
+ Retriever.config.storage(:ephemeral)
6
+ end
7
+
8
+ it 'should fetch ball' do
9
+ Retriever.catch! do
10
+ target :ball do
11
+ 'ball'
12
+ end
13
+ end
14
+ Retriever.fetch(:ball).should be_eql('ball')
15
+ end
16
+
17
+ it 'should memoize ball' do
18
+ Retriever.catch! do
19
+ target :ball do
20
+ 'ball'
21
+ end
22
+ end
23
+ Retriever.storage.should_receive(:set).once.and_return('ball')
24
+ Retriever.fetch(:ball).should be_eql('ball')
25
+ Retriever.storage.stub!(:get).and_return('ball')
26
+ Retriever.fetch(:ball).should be_eql('ball')
27
+ end
28
+
29
+ it 'should only be valid in 10 minutes' do
30
+ now = Time.now
31
+ Timecop.freeze(now)
32
+ Retriever.catch! do
33
+ @counter = 0
34
+ target :ball, :validity => 10.minutes do
35
+ @counter += 1
36
+ end
37
+ end
38
+ Retriever.fetch(:ball).should be_eql(1)
39
+ Timecop.freeze(now + 5.minutes)
40
+ Retriever.fetch(:ball).should be_eql(1)
41
+ Timecop.freeze(now + 10.minutes)
42
+ Retriever.fetch(:ball).should be_eql(1)
43
+ Timecop.freeze(now + 10.minutes + 1.second)
44
+ Retriever.fetch(:ball).should be_eql(2)
45
+ Timecop.freeze(now + 15.minutes)
46
+ Retriever.fetch(:ball).should be_eql(2)
47
+ Timecop.freeze(now)
48
+ Retriever.fetch(:ball).should be_eql(2)
49
+ Timecop.freeze(now + 30.minutes)
50
+ Retriever.fetch(:ball).should be_eql(3)
51
+ end
52
+
53
+ it 'should be able to pass parameters' do
54
+ Retriever.catch! do
55
+ target :ball do |arg1, arg2|
56
+ arg1 + arg2
57
+ end
58
+ end
59
+
60
+ Retriever.fetch(:ball, 1, 2).should be_eql(3)
61
+ end
62
+
63
+ it 'should be able to fetch forcefully' do
64
+ now = Time.now
65
+ Timecop.freeze(now)
66
+ Retriever.catch! do
67
+ @counter = 0
68
+ target :ball, :validity => 10.minutes do
69
+ @counter += 1
70
+ end
71
+ end
72
+ Retriever.fetch(:ball).should be_eql(1)
73
+ Retriever.fetch!(:ball).should be_eql(2)
74
+ Retriever.fetch(:ball).should be_eql(2)
75
+ end
76
+
77
+ it 'should be encrypted' do
78
+ Retriever.config.encrypt = true
79
+ Retriever.should be_encrypted
80
+ Retriever.catch! do
81
+ target :ball do
82
+ 'ball'
83
+ end
84
+ end
85
+ Retriever.fetch(:ball).should be_eql('ball')
86
+ end
87
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe Retriever do
4
+ before do
5
+ Retriever.config.storage(:redis)
6
+ end
7
+
8
+ it 'should fetch ball' do
9
+ Retriever.catch! do
10
+ target :ball do
11
+ 'ball'
12
+ end
13
+ end
14
+ Retriever.fetch(:ball).should be_eql('ball')
15
+ end
16
+
17
+ it 'should memoize ball' do
18
+ Retriever.catch! do
19
+ target :ball do
20
+ 'ball'
21
+ end
22
+ end
23
+ Retriever.storage.should_receive(:set).once.and_return('ball')
24
+ Retriever.fetch(:ball).should be_eql('ball')
25
+ Retriever.storage.stub!(:get).and_return('ball')
26
+ Retriever.fetch(:ball).should be_eql('ball')
27
+ end
28
+
29
+ it 'should only be valid in 10 minutes' do
30
+ now = Time.now
31
+ Timecop.freeze(now)
32
+ Retriever.catch! do
33
+ @counter = 0
34
+ target :ball, :validity => 10.minutes do
35
+ @counter += 1
36
+ end
37
+ end
38
+ Retriever.fetch(:ball).should be_eql('1')
39
+ Timecop.freeze(now + 5.minutes)
40
+ Retriever.fetch(:ball).should be_eql('1')
41
+ Timecop.freeze(now + 10.minutes)
42
+ Retriever.fetch(:ball).should be_eql('1')
43
+ Timecop.freeze(now + 10.minutes + 1.second)
44
+ Retriever.fetch(:ball).should be_eql('2')
45
+ Timecop.freeze(now + 15.minutes)
46
+ Retriever.fetch(:ball).should be_eql('2')
47
+ Timecop.freeze(now)
48
+ Retriever.fetch(:ball).should be_eql('2')
49
+ Timecop.freeze(now + 30.minutes)
50
+ Retriever.fetch(:ball).should be_eql('3')
51
+ end
52
+
53
+ it 'should be able to pass parameters' do
54
+ Retriever.catch! do
55
+ target :ball do |arg1, arg2|
56
+ arg1 + arg2
57
+ end
58
+ end
59
+
60
+ Retriever.fetch(:ball, 1, 2).should be_eql('3')
61
+ end
62
+
63
+ it 'should be able to fetch forcefully' do
64
+ now = Time.now
65
+ Timecop.freeze(now)
66
+ Retriever.catch! do
67
+ @counter = 0
68
+ target :ball, :validity => 10.minutes do
69
+ @counter += 1
70
+ end
71
+ end
72
+ Retriever.fetch(:ball).should be_eql('1')
73
+ Retriever.fetch!(:ball).should be_eql('2')
74
+ Retriever.fetch(:ball).should be_eql('2')
75
+ end
76
+
77
+ it 'should be encrypted' do
78
+ Retriever.config.encrypt = true
79
+ Retriever.should be_encrypted
80
+ Retriever.catch! do
81
+ target :ball do
82
+ 'ball'
83
+ end
84
+ end
85
+ Retriever.fetch(:ball).should be_eql('ball')
86
+ end
87
+ end
@@ -0,0 +1,19 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ end
5
+
6
+ require File.join(
7
+ File.dirname(__FILE__),
8
+ '..', 'lib', 'retriever')
9
+ require 'timecop'
10
+ require 'active_support'
11
+ require 'active_support/time'
12
+
13
+ RSpec.configure do |config|
14
+ [:all, :each].each do |x|
15
+ config.after(x) do
16
+ Retriever.clean!
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: retriever
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nelvin Driz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-25 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70342454584380 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70342454584380
25
+ - !ruby/object:Gem::Dependency
26
+ name: redis
27
+ requirement: &70342454583340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70342454583340
36
+ - !ruby/object:Gem::Dependency
37
+ name: yajl-ruby
38
+ requirement: &70342454582340 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70342454582340
47
+ - !ruby/object:Gem::Dependency
48
+ name: rails
49
+ requirement: &70342454580180 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70342454580180
58
+ - !ruby/object:Gem::Dependency
59
+ name: timecop
60
+ requirement: &70342454579060 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70342454579060
69
+ - !ruby/object:Gem::Dependency
70
+ name: ruby-debug19
71
+ requirement: &70342454578320 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70342454578320
80
+ - !ruby/object:Gem::Dependency
81
+ name: simplecov
82
+ requirement: &70342454577260 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70342454577260
91
+ - !ruby/object:Gem::Dependency
92
+ name: activesupport
93
+ requirement: &70342454576500 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *70342454576500
102
+ description: ! "\n Retriever allows caching of the result of a block. It currently
103
+ supports ruby memory storage and redis.\n "
104
+ email:
105
+ - ndriz@exist.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - .gitignore
111
+ - Gemfile
112
+ - LICENSE.txt
113
+ - README.rdoc
114
+ - Rakefile
115
+ - lib/retriever.rb
116
+ - lib/retriever/config.rb
117
+ - lib/retriever/instruction.rb
118
+ - lib/retriever/storage/ephemeral.rb
119
+ - lib/retriever/storage/redis.rb
120
+ - lib/retriever/version.rb
121
+ - retriever.gemspec
122
+ - spec/lib/custom_storage_spec.rb
123
+ - spec/lib/default_spec.rb
124
+ - spec/lib/redis_spec.rb
125
+ - spec/spec_helper.rb
126
+ homepage: http://github.com/Keoven/Retriever
127
+ licenses: []
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project: retriever
146
+ rubygems_version: 1.8.10
147
+ signing_key:
148
+ specification_version: 3
149
+ summary: Retriever is a block result caching library.
150
+ test_files:
151
+ - spec/lib/custom_storage_spec.rb
152
+ - spec/lib/default_spec.rb
153
+ - spec/lib/redis_spec.rb
154
+ - spec/spec_helper.rb