nice_cache 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZjFlNDA4NmZhMmFmMDc0ZDZjNGQyNjJkMDVjY2M3ZjhkMjQ4NWFmOA==
5
+ data.tar.gz: !binary |-
6
+ NGNkZDZhZmE5NmVhMGY4NTVkODQzMGIwYmVlN2E2ZjViNjY4NWY2Ng==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NTY0ZTg0ZDAwN2YyNDcwY2Y1NWNhZjZkMTBjMzNiZmNmNmUyZWYyMDg3ODA4
10
+ Y2ExZWY1N2FlMGY3ZjE2ZjNhOGM0YTI2ZDhlMzkwYjdiYjVkMzdiMjFhZTYw
11
+ MWExMDBjMmJhYzQ4ZjBiYWNjYzJlZDNmOTU3NmEyNzgxMzZkM2U=
12
+ data.tar.gz: !binary |-
13
+ OWE0ZGQ4MTJjYWE2Y2ZhN2QzYjVjYzE5MTE1MDk5OTY5OWVjNGUxODgzOGI2
14
+ ZWI5NDY1Zjk4ZmRlMDgyMjI4OTk5OTA1NzkwZmQ1YWE1ZWVlMDBiNmJhMmRj
15
+ ZmFiNmZiNzY3NWFmMTc0NzQ2YjQ1YjlhYzA5MjgzZjQ4MzJhM2Y=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,26 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nice_cache.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
7
+
8
+ group :development do
9
+ gem 'guard'
10
+ gem 'guard-bundler'
11
+ gem 'guard-rspec'
12
+ end
13
+
14
+ group :test do
15
+ gem 'json', platforms: [:jruby, :rbx, :ruby_19]
16
+ gem 'libnotify'
17
+ gem 'mime-types', platforms: :jruby
18
+ gem 'rspec'
19
+ gem 'mock_redis'
20
+ gem 'simplecov', require: false
21
+ end
22
+
23
+ group :development, :test do
24
+ gem 'pry-debugger', platforms: :ruby_19
25
+ gem 'pry-byebug', platforms: :ruby_20
26
+ end
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Taian Su
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # NiceCache
2
+
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ gem 'nice_cache'
9
+
10
+ And then execute:
11
+
12
+ $ bundle
13
+
14
+ Or install it yourself as:
15
+
16
+ $ gem install nice_cache
17
+
18
+ ## Usage
19
+
20
+
21
+
22
+ ## Contributing
23
+
24
+ 1. Fork it ( http://github.com/<my-github-username>/nice_cache/fork )
25
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
26
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
27
+ 4. Push to the branch (`git push origin my-new-feature`)
28
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,95 @@
1
+ require_relative 'tag'
2
+
3
+ module NiceCache
4
+ class Fragment
5
+ attr_reader :name, :data
6
+
7
+ def self.find(name)
8
+ new.find(name)
9
+ end
10
+
11
+ def self.key(name)
12
+ "Fragment:#{name}"
13
+ end
14
+
15
+ def self.tags_for(name)
16
+ "TagsFor:#{name}"
17
+ end
18
+
19
+ def initialize(data = nil, tag_names = nil)
20
+ create(data, tag_names) if data && tag_names
21
+ end
22
+
23
+ def create(data, tag_names)
24
+ @name = stringify(tag_names)
25
+ @data = data
26
+ attach_tags(tag_names)
27
+ save_to_redis
28
+ end
29
+
30
+ def find(name)
31
+ @name = name
32
+ @data = data_from_redis
33
+ self
34
+ end
35
+
36
+ def tags
37
+ Tag.find(redis_tag_names)
38
+ end
39
+
40
+ def attach_with(tag)
41
+ redis.sadd(attached_tags, tag.name)
42
+ end
43
+
44
+ def destroy
45
+ tags.each do |tag|
46
+ tag.remove_from(self)
47
+ end
48
+
49
+ redis.srem(NiceCache.all_fragments_key, @name)
50
+ redis.del attached_tags
51
+ redis.del fragment_key
52
+ end
53
+
54
+ def ==(other)
55
+ [name, data] == [other.name, other.data]
56
+ rescue
57
+ false
58
+ end
59
+
60
+ private
61
+
62
+ def attach_tags(tag_names)
63
+ Tag.find(tag_names).map{ |tag| tag.attach_on(self) }
64
+ end
65
+
66
+ def stringify(tag_names)
67
+ tag_names.map{ |tag| tag.to_s.capitalize }.join("-")
68
+ end
69
+
70
+ def attached_tags
71
+ self.class.tags_for(@name)
72
+ end
73
+
74
+ def fragment_key
75
+ self.class.key(@name)
76
+ end
77
+
78
+ def redis_tag_names
79
+ redis.smembers(attached_tags)
80
+ end
81
+
82
+ def save_to_redis
83
+ redis.sadd(NiceCache.all_fragments_key, @name)
84
+ redis.set(fragment_key, @data)
85
+ end
86
+
87
+ def data_from_redis
88
+ redis.get(fragment_key)
89
+ end
90
+
91
+ def redis
92
+ NiceCache.redis
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,63 @@
1
+ require_relative 'fragment'
2
+
3
+ module NiceCache
4
+ class Tag
5
+ attr_reader :name
6
+
7
+ def self.find(*tag_names)
8
+ Array(tag_names).flatten.map{ |tag_symbol| new(tag_symbol) }
9
+ end
10
+
11
+ def self.key(name)
12
+ "Tag:#{name}"
13
+ end
14
+
15
+ def initialize(name)
16
+ @name = name.to_s
17
+ end
18
+
19
+ def attach_on(fragment)
20
+ redis.sadd(tag_key, fragment.name)
21
+ fragment.attach_with(self)
22
+ self
23
+ end
24
+
25
+ def fragments
26
+ fragment_keys.map{ |fragment_key| Fragment.find(fragment_key) }
27
+ end
28
+
29
+ def tag_key
30
+ self.class.key(@name)
31
+ end
32
+
33
+ def remove_from(fragment)
34
+ redis.srem(tag_key, fragment.name)
35
+ end
36
+
37
+ def sweep
38
+ fragments.map(&:destroy)
39
+ destroy
40
+ end
41
+
42
+ def ==(other)
43
+ name == other.name
44
+ rescue
45
+ false
46
+ end
47
+
48
+ private
49
+
50
+ def redis
51
+ NiceCache.redis
52
+ end
53
+
54
+ def destroy
55
+ redis.del tag_key
56
+ end
57
+
58
+ def fragment_keys
59
+ redis.smembers(tag_key)
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module NiceCache
2
+ VERSION = "0.1.0"
3
+ end
data/lib/nice_cache.rb ADDED
@@ -0,0 +1,55 @@
1
+ require 'redis-namespace'
2
+ require_relative "nice_cache/fragment"
3
+ require_relative "nice_cache/tag"
4
+
5
+ module NiceCache
6
+
7
+ def self.config(&block)
8
+ block.call(self)
9
+ end
10
+
11
+ def self.redis
12
+ @redis ||= namespaced_redis
13
+ end
14
+
15
+ def self.redis=(custom_redis)
16
+ @redis = namespaced_redis(custom_redis)
17
+ end
18
+
19
+ def self.cache(data, tags)
20
+ tag_names = tags.is_a?(Hash) ? tags[:tags] : Array(tags)
21
+ Fragment.new(data, tag_names)
22
+ self
23
+ end
24
+
25
+ def self.sweep_tags(*tag_names)
26
+ Tag.find(tag_names).map do |tag|
27
+ tag.sweep
28
+ end
29
+ end
30
+
31
+ def self.sweep_fragments(*fragment_names)
32
+ fragment_names.map do |fragment_name|
33
+ Fragment.find(fragment_name).destroy
34
+ end
35
+ end
36
+
37
+ def self.all_fragments_key
38
+ "AllFragments"
39
+ end
40
+
41
+ def self.cleanup
42
+ fragments.map(&:destroy)
43
+ end
44
+
45
+ def self.fragments
46
+ # O(N), N is number of fragment keys in NiceCache
47
+ redis.smembers(all_fragments_key).map { |name| Fragment.find(name) }
48
+ end
49
+
50
+ private
51
+ def self.namespaced_redis(redis = nil)
52
+ redis ||= Redis.current
53
+ Redis::Namespace.new(:NiceCache, redis: redis)
54
+ end
55
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nice_cache/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nice_cache"
8
+ spec.version = NiceCache::VERSION
9
+ spec.authors = ["Taian Su"]
10
+ spec.email = ["me@taian.su"]
11
+ spec.summary = %q{Tag based caching with Redis.}
12
+ spec.description = %q{}
13
+ spec.homepage = "https://github.com/optimis/nice_cache"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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_dependency 'redis', '~> 3.0'
22
+ spec.add_dependency 'redis-namespace', '~> 1.4'
23
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'mock_redis'
3
+
4
+ describe NiceCache::Fragment do
5
+
6
+ subject(:fragment) { NiceCache::Fragment.new("Some Data", [:Year2014, :Month01, :Date01]) }
7
+
8
+ after :all do
9
+ puts "=== Clean up redis ==="
10
+ puts Benchmark.measure {
11
+ NiceCache.cleanup
12
+ }
13
+ end
14
+
15
+ before :all do
16
+ NiceCache.config do |options|
17
+ options.redis = REDIS # => from spec/spec_helper.rb
18
+ end
19
+ end
20
+
21
+ describe "#new" do
22
+ it "has correct name" do
23
+ expect(fragment.name).to eq "Year2014-Month01-Date01"
24
+ end
25
+
26
+ it "has correct data" do
27
+ expect(fragment.data).to eq "Some Data"
28
+ end
29
+ end
30
+
31
+ describe "#find" do
32
+ let(:fetch_fragment) { NiceCache::Fragment.find("Year2014-Month01-Date01") }
33
+
34
+ it "find correct data with fragment name" do
35
+ expect(fetch_fragment.data).to eq "Some Data"
36
+ end
37
+ end
38
+
39
+ it "get correct #tags" do
40
+ expect(fragment.tags.length).to eq 3
41
+ end
42
+
43
+ it "can compare with any classes" do
44
+ expect(fragment == []).to be_false
45
+ end
46
+ end
47
+
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'mock_redis'
3
+
4
+ describe NiceCache::Tag do
5
+
6
+ subject(:tag) { NiceCache::Tag.new(:"Year2014") }
7
+
8
+ after :all do
9
+ puts "=== Clean up redis ==="
10
+ puts Benchmark.measure {
11
+ NiceCache.cleanup
12
+ }
13
+ end
14
+
15
+ before :all do
16
+ NiceCache.config do |options|
17
+ options.redis = REDIS # => from spec/spec_helper.rb
18
+ end
19
+ end
20
+
21
+ it "have correct name" do
22
+ expect(tag.name).to eq "Year2014"
23
+ end
24
+
25
+ describe "#attach_on and #fragments" do
26
+ it "get correct #fragments after #attach_on" do
27
+ fragment = NiceCache::Fragment.new("Some Data", [:"Year2014", :"Month01", :"Date01"])
28
+ tag.attach_on(fragment)
29
+ expect(tag.fragments).to eq [fragment]
30
+ end
31
+ end
32
+
33
+ it "can compare with any classes" do
34
+ expect(tag == []).to be_false
35
+ end
36
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'benchmark'
3
+
4
+ describe NiceCache do
5
+
6
+ it "change redis from #config" do
7
+ NiceCache.config do |options|
8
+ options.redis = REDIS # => from spec/spec_helper.rb
9
+ end
10
+
11
+ expect(NiceCache.redis.redis.class).to eq REDIS.class
12
+ end
13
+
14
+ after :all do
15
+ puts "=== Clean up redis ==="
16
+ puts Benchmark.measure {
17
+ NiceCache.cleanup
18
+ }
19
+ end
20
+
21
+ before :each do
22
+ NiceCache.cache("Some Data", tags: [:Year2014, :Month01, :Date01])
23
+ end
24
+
25
+ it "cleanup all the fragments and tags" do
26
+ NiceCache::Fragment.find("Year2014-Month01-Date01")
27
+ expect(NiceCache.redis.keys("*")).to_not be_empty
28
+ NiceCache.cleanup
29
+ expect(NiceCache.redis.keys("*")).to be_empty
30
+ end
31
+
32
+ let(:found_fragment) { NiceCache::Fragment.find("Year2014-Month01-Date01") }
33
+
34
+ it "cache fragment to #fragments" do
35
+ expect(NiceCache.fragments).to eq [found_fragment]
36
+ end
37
+
38
+ it "remove fragment" do
39
+ NiceCache.sweep_fragments("Year2014-Month01-Date01")
40
+ expect(NiceCache.fragments).to eq []
41
+ end
42
+
43
+ context "multiple fragments" do
44
+ before :each do
45
+ NiceCache.cache("Other Data", tags: [:Year2014, :Month02, :Date01])
46
+ end
47
+
48
+ it "get correct #fragments length" do
49
+ expect(NiceCache.fragments.length).to eq 2
50
+ end
51
+
52
+ it "sweep only one matched fragment" do
53
+ p Benchmark.measure {
54
+ NiceCache.sweep_tags(:Month02)
55
+ expect(NiceCache.fragments.length).to eq 1
56
+ }
57
+ end
58
+
59
+ it "sweep both of matching fragments" do
60
+ p Benchmark.measure {
61
+ NiceCache.sweep_tags(:Year2014)
62
+ expect(NiceCache.fragments.length).to eq 0
63
+ }
64
+ end
65
+
66
+ end
67
+ end
68
+
@@ -0,0 +1,15 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ GEM_ROOT = File.expand_path('../../', __FILE__)
5
+ $LOAD_PATH.unshift File.join(GEM_ROOT, 'lib')
6
+
7
+ require 'nice_cache'
8
+ Dir[File.join(GEM_ROOT, 'spec', 'support', '**/*.rb')].each { |f| require f }
9
+
10
+ require 'mock_redis'
11
+ require 'redis-namespace'
12
+ REDIS = MockRedis.new
13
+ # REDIS = Redis.new
14
+
15
+ require 'pry'
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nice_cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Taian Su
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: redis-namespace
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.4'
41
+ description: ''
42
+ email:
43
+ - me@taian.su
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - License.txt
51
+ - README.md
52
+ - Rakefile
53
+ - lib/nice_cache.rb
54
+ - lib/nice_cache/fragment.rb
55
+ - lib/nice_cache/tag.rb
56
+ - lib/nice_cache/version.rb
57
+ - nice_cache.gemspec
58
+ - spec/nice_cache/fragment_spec.rb
59
+ - spec/nice_cache/tag_spec.rb
60
+ - spec/nice_cache_spec.rb
61
+ - spec/spec_helper.rb
62
+ homepage: https://github.com/optimis/nice_cache
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.2.2
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Tag based caching with Redis.
86
+ test_files:
87
+ - spec/nice_cache/fragment_spec.rb
88
+ - spec/nice_cache/tag_spec.rb
89
+ - spec/nice_cache_spec.rb
90
+ - spec/spec_helper.rb