greencache 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fd924fd562c22233595cde3eca25cdd69da88f22
4
+ data.tar.gz: b9e4e115ba90713299eafcb38fa6a300b37a9370
5
+ SHA512:
6
+ metadata.gz: ceb54a296bac09558022ec22c29ccb91ead6de930055d7726c778835e3cb9bc79834d2fa141f0ef92437558a058b9e0cec14f876308460b460a4c73429cf09f3
7
+ data.tar.gz: 1fe8b49123c5a006b232278d3547d6387bf9def0a708d8d6ed9523504ea53b4e2aecd1a2936654a2f30d086836ab720d1f195332ef5b6328b23ed81963f747a6
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in greencache.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Neil Middleton
2
+
3
+ MIT License
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.
@@ -0,0 +1,87 @@
1
+ # Greencache
2
+
3
+ A gem for caching data in Redis.
4
+
5
+ This gem caches data from slow services in Redis
6
+
7
+ This gem is also able to encrypt the cached results with Fernet if required.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'greencache'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install greencache
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+
29
+ GreenCache.configure do |c|
30
+ c.redis = $redis
31
+ c.secret = <some_long_hash>
32
+ c.encrypt = true
33
+ end
34
+
35
+ value = Greencache.cache "unique_cache_key" do
36
+ call_to_slow_service
37
+ end
38
+ ```
39
+
40
+ ### Configuration
41
+
42
+ Several configuration options are available to use that defined the behaviour of
43
+ greencache.
44
+
45
+ <table>
46
+ <tr>
47
+ <td>:redis</td>
48
+ <td>Connection to redis</td>
49
+ </tr>
50
+ <tr>
51
+ <td>:secret</td>
52
+ <td>If encrypting, what secret should be used. See [Fernet](https://github.com/fernet/fernet-rb) README for more
53
+ information</td>
54
+ </tr>
55
+ <tr>
56
+ <td>:encrypt</td>
57
+ <td>Should cached data be encrypted (boolean)</td>
58
+ </tr>
59
+ <tr>
60
+ <td>:skip_cache</td>
61
+ <td>Should the cache be skipped. Useful in test environments (boolean)</td>
62
+ </tr>
63
+ <tr>
64
+ <td>:logged</td>
65
+ <td>Standard logger object to use for logging</td>
66
+ </tr>
67
+ <tr>
68
+ <td>:log_prefix</td>
69
+ <td>String to prefix to l2met compatible log lines</td>
70
+ </tr>
71
+ <tr>
72
+ <td>:cache_time</td>
73
+ <td>Time (in seconds) to cache data for before expiring</td>
74
+ </tr>
75
+ </table>
76
+
77
+ ## Testing
78
+
79
+ Specs to come ;)
80
+
81
+ ## Contributing
82
+
83
+ 1. Fork it ( https://github.com/neilmiddleton/greencache/fork )
84
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
85
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
86
+ 4. Push to the branch (`git push origin my-new-feature`)
87
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'greencache/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "greencache"
8
+ spec.version = Greencache::VERSION
9
+ spec.authors = ["Neil Middleton", "John Beynon"]
10
+ spec.email = ["neil@neilmiddleton.com"]
11
+ spec.summary = %q{A gem for caching values in redis and encrypting them}
12
+ spec.description = %q{A wrapper for Redis, for caching and encryption with Fernet}
13
+ spec.homepage = "http://www.neilmiddleton.com"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.0"
24
+ spec.add_development_dependency "fakeredis", "~> 0.5"
25
+ spec.add_development_dependency "pliny", "~> 0.0"
26
+
27
+ spec.add_dependency "fernet", "~> 2.1"
28
+ spec.add_dependency "redis", "~> 3.1"
29
+ spec.add_dependency "multi_json", "~> 1.10"
30
+ end
@@ -0,0 +1,119 @@
1
+ require "greencache/version"
2
+ require "fernet"
3
+ require "greencache/configuration"
4
+
5
+ Fernet::Configuration.run do |config|
6
+ config.enforce_ttl = false
7
+ end
8
+
9
+ module Greencache
10
+ class << self
11
+ attr_writer :configuration
12
+
13
+ def configure
14
+ yield(configuration)
15
+ end
16
+
17
+ def cache(redis_key, &block)
18
+ return block.call if skip_cache? || !redis_up?
19
+ value = read_from_cache(redis_key)
20
+ return value if value
21
+ value = block.call
22
+ write_into_cache(redis_key, value)
23
+ value
24
+ end
25
+
26
+ def read_from_cache(redis_key, &block)
27
+ value = get_value(redis_key)
28
+ value.nil? ? log("cache.miss", redis_key) : log("cache.hit", redis_key)
29
+ return value
30
+ end
31
+
32
+ def write_into_cache(redis_key, value)
33
+ with_redis do
34
+ log("cache.write", redis_key)
35
+ set_value(redis_key, value)
36
+ end
37
+ value
38
+ end
39
+
40
+ def get_value(key)
41
+ decrypt redis.get(key)
42
+ end
43
+
44
+ def set_value(key, value)
45
+ redis.setex key, configuration.cache_time, encrypt(value)
46
+ end
47
+
48
+ def encrypt(value)
49
+ return prep_value(value) unless encrypt?
50
+ fernet.generate(secret, prep_value(value))
51
+ end
52
+
53
+ def decrypt(value)
54
+ return nil if value.nil?
55
+ return value unless encrypt?
56
+ verifier = fernet.verifier(secret, value)
57
+ return MultiJson.load(verifier.message) if verifier.valid?
58
+ return nil
59
+ end
60
+
61
+ def configuration
62
+ @configuration ||= Configuration.new
63
+ end
64
+
65
+ def redis
66
+ configuration.redis
67
+ end
68
+
69
+ def redis_up?
70
+ begin
71
+ redis.ping
72
+ rescue Redis::CannotConnectError, Timeout::Error
73
+ puts "Redis is DOWN! :shitsonfire:"
74
+ return false
75
+ end
76
+ return true
77
+ end
78
+
79
+ def with_redis(&block)
80
+ block.call if redis_up?
81
+ end
82
+
83
+ def cache_time
84
+ configuration.cache_time
85
+ end
86
+
87
+ def skip_cache?
88
+ configuration.skip_cache
89
+ end
90
+
91
+ def test?
92
+ ENV["RACK_ENV"] == 'test'
93
+ end
94
+
95
+ def prep_value(value)
96
+ MultiJson.encode(value)
97
+ end
98
+
99
+ def encrypt?
100
+ configuration.encrypt
101
+ end
102
+
103
+ def secret
104
+ configuration.secret
105
+ end
106
+
107
+ def log(str, key)
108
+ configuration.logger.log(log_prefix(str) => 1, :key => key) unless configuration.silent
109
+ end
110
+
111
+ def log_prefix(str)
112
+ [configuration.log_prefix, str].join(".")
113
+ end
114
+
115
+ def fernet
116
+ ::Fernet
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,22 @@
1
+ module Greencache
2
+ class Configuration
3
+ attr_accessor :redis
4
+ attr_accessor :secret
5
+ attr_accessor :cache_time
6
+ attr_accessor :encrypt
7
+ attr_accessor :skip_cache
8
+ attr_accessor :silent
9
+ attr_accessor :logger
10
+ attr_accessor :log_prefix
11
+
12
+ def initialize
13
+ @cache_time = 600
14
+ @encrypt = false
15
+ @secret = nil
16
+ @skip_cache = false
17
+ @silent = false
18
+ @logger = nil
19
+ @log_prefix = "greencache"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Greencache
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+ require 'fernet'
3
+
4
+ Greencache.configure do |c|
5
+ c.redis = Redis.new
6
+ c.logger = Pliny
7
+ c.silent = true
8
+ end
9
+
10
+ class Dummy
11
+ def self.uuid
12
+ SecureRandom.uuid
13
+ end
14
+
15
+ def self.run
16
+ Greencache.cache "foo" do
17
+ get_value
18
+ end
19
+ end
20
+
21
+ def self.get_value
22
+ "bar"
23
+ end
24
+ end
25
+
26
+ describe Greencache do
27
+ let(:rc) { Greencache }
28
+ let(:config) { Greencache.configuration }
29
+
30
+ before do
31
+ allow(rc.fernet).to receive(:generate){ "abd" }
32
+ end
33
+
34
+ context 'when skipping caching' do
35
+ before do
36
+ config.skip_cache = true
37
+ end
38
+
39
+ it 'does not use the cache' do
40
+ expect(rc).to_not receive(:read_from_cache)
41
+ Dummy.run
42
+ end
43
+ end
44
+
45
+ context 'when caching' do
46
+ before do
47
+ config.skip_cache = false
48
+ end
49
+
50
+ it 'uses the cached' do
51
+ expect(rc).to receive(:read_from_cache){ {} }
52
+ Dummy.run
53
+ end
54
+
55
+ it 'shows redis as down if it times out' do
56
+ allow(rc.redis).to receive(:ping){ raise Timeout::Error }
57
+ expect(rc.redis_up?).to eq(false)
58
+ end
59
+
60
+ it 'skips cache when redis is down' do
61
+ allow(rc).to receive(:redis_up?){ false }
62
+ expect(rc).to_not receive(:read_from_cache)
63
+ expect(Dummy).to receive(:get_value){ "bar" }
64
+ Dummy.run
65
+ end
66
+
67
+ end
68
+
69
+ describe 'configuration' do
70
+ it 'respects cache_time' do
71
+ config.cache_time = 100
72
+ expect(rc.cache_time).to eq(100)
73
+ end
74
+
75
+ it 'respects skip_cache' do
76
+ config.skip_cache = true
77
+ expect(rc.skip_cache?).to eq(true)
78
+ end
79
+
80
+ it 'knows the secret' do
81
+ config.secret = "bar"
82
+ expect(rc.secret).to eq("bar")
83
+ end
84
+ end
85
+
86
+ it 'can write into the cache' do
87
+ p = Proc.new { "" }
88
+ expect(rc).to receive(:set_value).with("foo", "")
89
+ rc.write_into_cache("foo", p.call)
90
+ end
91
+
92
+ it 'can get a value' do
93
+ expect(rc.redis).to receive(:get).with("foo"){ "bar" }
94
+ expect(rc).to receive(:decrypt).with("bar")
95
+ rc.get_value("foo")
96
+ end
97
+
98
+ it 'can set a value' do
99
+ config.cache_time = 100
100
+ config.encrypt = false
101
+ expect(rc.redis).to receive(:setex).with("foo", 100, '"bar"')
102
+ rc.set_value("foo", "bar")
103
+ end
104
+
105
+ it 'encrypts' do
106
+ config.encrypt = true
107
+ config.secret = "foo"
108
+ expect(rc.fernet).to receive(:generate).with("foo", '"bar"'){ "abc" }
109
+ rc.encrypt("bar")
110
+ end
111
+ end
@@ -0,0 +1,17 @@
1
+ require 'bundler/setup'
2
+ Bundler.require
3
+
4
+ require 'greencache'
5
+ require 'redis'
6
+ require 'fakeredis'
7
+ require 'pliny'
8
+
9
+ RSpec.configure do |config|
10
+ config.expect_with :rspec do |expectations|
11
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
12
+ end
13
+
14
+ config.mock_with :rspec do |mocks|
15
+ mocks.verify_partial_doubles = true
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: greencache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Neil Middleton
8
+ - John Beynon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-03-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.7'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.7'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: fakeredis
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0.5'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.5'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pliny
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '0.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: fernet
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '2.1'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '2.1'
98
+ - !ruby/object:Gem::Dependency
99
+ name: redis
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '3.1'
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '3.1'
112
+ - !ruby/object:Gem::Dependency
113
+ name: multi_json
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '1.10'
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '1.10'
126
+ description: A wrapper for Redis, for caching and encryption with Fernet
127
+ email:
128
+ - neil@neilmiddleton.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - Gemfile
136
+ - LICENSE.txt
137
+ - README.md
138
+ - Rakefile
139
+ - greencache.gemspec
140
+ - lib/greencache.rb
141
+ - lib/greencache/configuration.rb
142
+ - lib/greencache/version.rb
143
+ - spec/greencache_spec.rb
144
+ - spec/spec_helper.rb
145
+ homepage: http://www.neilmiddleton.com
146
+ licenses:
147
+ - MIT
148
+ metadata: {}
149
+ post_install_message:
150
+ rdoc_options: []
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ requirements: []
164
+ rubyforge_project:
165
+ rubygems_version: 2.4.5
166
+ signing_key:
167
+ specification_version: 4
168
+ summary: A gem for caching values in redis and encrypting them
169
+ test_files:
170
+ - spec/greencache_spec.rb
171
+ - spec/spec_helper.rb
172
+ has_rdoc: