active_cash 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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dfe51a8a1ee9db01686a85f20fe6645be5a7197f
4
+ data.tar.gz: 9b496a458a78e3bb25e6e19dd9a317306cce4fd2
5
+ SHA512:
6
+ metadata.gz: f920abb9e8575cda8f24ac9b1cda4a158e724d9f095409c5c720f60ed297ff409047bdbd55ccf663678c74ef910d5558eee1ce750005f4be07de0b1f4fd199ad
7
+ data.tar.gz: bc10988ccc150437efa698fc1f79b717acbed4bf10946e1072452cdbbb1ca170d2aadcf1aae21d06982cb8784fd5f4321948f56ee2c998cb9b23ea84a1f6b890
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_cash.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Filippos Vasilakis
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.
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # ActiveCash
2
+ Drop in cache strategies for ActiveRecord.
3
+
4
+ I named the gem ActiveCash in case an official gem arrives with the name
5
+ ActiveCache.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'active_cash'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install active_cash
22
+
23
+ ## Usage
24
+ We will add more strategies soon..
25
+
26
+ #### Existence strategy
27
+ ``` ruby
28
+ class Like < ActiveRecord::Base
29
+ include ActiveCash
30
+
31
+ # type # matched conditions # cache name (default is strategy name)
32
+ caches :existence, find_by: [:user_id, :video_id]
33
+ caches :existence, find_by: [:user_id, :video_id, :hidden], name: :hidden
34
+ end
35
+
36
+ # Check if Like exists for specific :user_id, :video_id.
37
+ @like = Like.cached_existence_by(user_id: 1, video_id: 2)
38
+
39
+
40
+ # Check if a hidden Like exists for specific :user_id, :video_id.
41
+ # not sure what hidden could be but let's say that likes table has a boolean hidden column :)
42
+ @like = Like.cached_hidden_by(user_id: 1, video_id: 2, hidden: true)
43
+ ```
44
+
45
+ I am open for better naming conventions :)
46
+
47
+ Cache will be created and updated on every object creation, update and deletion
48
+ using an `after_commit` callback. If you want to have a read-driven cache (which could
49
+ enhance your hit ratio depending on your read/writes ratio) you can provide an
50
+ empty `update_on` array (by default it includes `[:create, :update, :destroy]`):
51
+
52
+ ``` ruby
53
+ class Like < ActiveRecord::Base
54
+ include ActiveCash
55
+
56
+ # type # matched conditions # updating strategies
57
+ caches :existence, find_by: [:video_id], update_on: []
58
+ end
59
+
60
+ # Check if Like exists for specific :user_id, :video_id.
61
+ @like = Like.cached_existence_by(user_id: 1, video_id: 2)
62
+
63
+
64
+ # Check if a hidden Like exists for specific :user_id, :video_id.
65
+ # not sure what hidden could be but let's say that likes table has a boolean hidden column :)
66
+ @like = Like.cached_hidden_by(user_id: 1, video_id: 2, hidden: true)
67
+ ```
68
+
69
+ Now cache will be created and updated ONLY IF there is a reference to Redis.
70
+
71
+ ## Todo
72
+ Only existence strategy is supported at the moment but the code is designed to
73
+ support other kind of caching strategies as well, like caching the whole object
74
+ or some parts of it. Also:
75
+
76
+ * We should provide named callbacks
77
+ * It's super easy to extend for Mongoid
78
+
79
+ ## Relevant projects
80
+ There is [identity_cache](https://github.com/Shopify/identity_cache) built by Shopify.
81
+ It uses memcached unfortunately that's why I needed something else.
82
+ For existence strategy ActiveCash is definitely better when it comes to space optimizations.
83
+ But I would use that if I wanted a full bloated solution.
84
+
85
+ Unfortunately I couldn't find any other gem for database caching :(
86
+
87
+ ## Development
88
+
89
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
90
+
91
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
92
+
93
+ ## Contributing
94
+
95
+ 1. Fork it ( https://github.com/vasilakisfil/active_cash/fork )
96
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
97
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
98
+ 4. Push to the branch (`git push origin my-new-feature`)
99
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'active_cash/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "active_cash"
8
+ spec.version = ActiveCash::VERSION
9
+ spec.authors = ["Filippos Vasilakis"]
10
+ spec.email = ["vasilakisfil@gmail.com"]
11
+
12
+ spec.summary = %q{Write a short summary, because Rubygems requires one.}
13
+ spec.description = %q{Write a longer description or delete this line.}
14
+ spec.homepage = "https://github.com/vasilakisfil/active_cash"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "redis-objects", "~> 1.2"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.8"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.4"
26
+ spec.add_development_dependency "activerecord", "~> 4.0"
27
+ spec.add_development_dependency "sqlite3", "~> 1.3"
28
+ spec.add_development_dependency "factory_girl", "~> 4.5"
29
+ spec.add_development_dependency "database_cleaner", "~> 1.5"
30
+ spec.add_development_dependency "fakeredis", "~> 0.5"
31
+ spec.add_development_dependency "test_after_commit", "~> 0.4"
32
+ spec.add_development_dependency "pry", "~> 0.10"
33
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "active_cash"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,23 @@
1
+ module ActiveCash::Adapter #fix boolean and make it generic
2
+ extend self
3
+
4
+ def get_value(key_name)
5
+ boolean(Redis::Value.new(key_name).value)
6
+ end
7
+
8
+ def set_value(key_name, value)
9
+ Redis::Value.new(key_name).value = value
10
+
11
+ boolean(value)
12
+ end
13
+
14
+ def delete_value(key_name)
15
+ Redis::Value.new(key_name).delete
16
+ end
17
+
18
+ def boolean(value)
19
+ return nil if value.nil?
20
+
21
+ [true, 1, '1', 't', 'T', 'true', 'TRUE'].include? value
22
+ end
23
+ end
@@ -0,0 +1,81 @@
1
+ module ActiveCash::Cache
2
+ extend self
3
+
4
+ def exists?(find_by:, method_name:, return: nil, klass:)
5
+ key_name = get_key_name(klass, method_name, find_by)
6
+ cached_value = adapter.get_value(key_name)
7
+ return cached_value unless cached_value.nil?
8
+
9
+ adapter.set_value(key_name, klass.to_s.constantize.exists?(find_by))
10
+ end
11
+
12
+ def instance_exists?(find_by:, method_name:, instance:, return: nil)
13
+ key_name = get_key_name(instance.class, method_name, find_by)
14
+ cached_value = adapter.get_value(key_name)
15
+ return cached_value unless cached_value.nil?
16
+
17
+ instance_update(find_by: find_by, method_name: method_name, instance: instance)
18
+ end
19
+
20
+ def instance_update(find_by:, method_name:, return_value: nil, instance:)
21
+ key_name = get_key_name(instance.class, method_name, find_by)
22
+
23
+ find_by.keys.each_with_index do |key, i|
24
+ if instance.send(key) != find_by.values[i]
25
+ return adapter.set_value(key_name, false)
26
+ end
27
+ end
28
+
29
+ adapter.set_value(key_name, true)
30
+ end
31
+
32
+ def instance_updated?(find_by:, instance:)
33
+ find_by.keys.each_with_index do |key, i|
34
+ if instance.send(key) != instance.send("#{key}_was")
35
+ return true
36
+ end
37
+ end
38
+ end
39
+
40
+ def old_instance_update(find_by:, method_name:, return_value: nil, instance:)
41
+ #old values
42
+ instance_update_if_exists(
43
+ find_by: Hash[find_by.map {|k, v| ["#{k}_was", v] }],
44
+ method_name: method_name,
45
+ return: return_value,
46
+ instance: instance
47
+ )
48
+ end
49
+
50
+ def instance_update_if_exists(find_by:, method_name:, return: nil, instance:)
51
+ key_name = get_key_name(instance.class, method_name, find_by)
52
+
53
+ cached_value = adapter.get_value(key_name)
54
+ return true if cached_value.nil?
55
+
56
+ instance_update(find_by: find_by, method_name: method_name, instance: instance)
57
+ end
58
+
59
+ def delete(find_by:, method_name:, return: nil, klass:)
60
+ key_name = get_key_name(klass, method_name, find_by)
61
+ adapter.delete_value(key_name)
62
+ end
63
+
64
+ def set_false(find_by:, method_name:, return: nil, klass:)
65
+ key_name = get_key_name(klass, method_name, find_by)
66
+ adapter.set_value(key_name, false)
67
+ end
68
+
69
+ def set_true(find_by:, method_name:, return: nil, klass:)
70
+ key_name = get_key_name(klass, method_name, find_by)
71
+ adapter.set_value(key_name, true)
72
+ end
73
+
74
+ def get_key_name(klass, method_name, hash_params)
75
+ "#{klass}:#{method_name}:#{hash_params.values.join('-')}"
76
+ end
77
+
78
+ def adapter
79
+ ActiveCash::Adapter
80
+ end
81
+ end
@@ -0,0 +1,8 @@
1
+ class ActiveCashError < StandardError
2
+ end
3
+
4
+ class RedefinedCacheError < ActiveCashError
5
+ end
6
+
7
+ class UnknownCacheTypeError < ActiveCashError
8
+ end
@@ -0,0 +1,127 @@
1
+ module ActiveCash::Utils
2
+ extend self
3
+
4
+ def set_callbacks(model, opts)
5
+ if (opts[:update_on] & [:create]).blank?
6
+ model.send(:after_commit, on: [:create]) do
7
+ ActiveCash::Cache.instance_update_if_exists(
8
+ ActiveCash::Utils.extract_instance_args(opts, self)
9
+ )
10
+ end
11
+ else
12
+ model.send(:after_commit, on: [:create]) do
13
+ ActiveCash::Cache.instance_update(
14
+ ActiveCash::Utils.extract_instance_args(opts, self)
15
+ )
16
+ end
17
+ end
18
+
19
+ if (opts[:update_on] & [:update]).blank?
20
+ model.send(:after_commit, on: [:update]) do
21
+ if instance_updated?(opts[:find_by], self)
22
+ ActiveCash::Cache.delete(extract_old_instance_args(opts, self))
23
+ ActiveCash::Cache.instance_update_if_exists(
24
+ ActiveCash::Utils.extract_instance_args(opts, self)
25
+ )
26
+ end
27
+ end
28
+ else
29
+ model.send(:after_commit, on: [:update]) do
30
+ if instance_updated?(opts[:find_by], self)
31
+ ActiveCash::Cache.delete(extract_old_instance_args(opts, self))
32
+ ActiveCash::Cache.instance_update(
33
+ ActiveCash::Utils.extract_instance_args(opts, self)
34
+ )
35
+ end
36
+ end
37
+ end
38
+
39
+ if (opts[:update_on] & [:destroy]).blank?
40
+ model.send(:after_commit, on: [:destroy]) do
41
+ ActiveCash::Cache.delete(
42
+ ActiveCash::Utils.extract_args(opts, self)
43
+ )
44
+ end
45
+ else
46
+ model.send(:after_commit, on: [:destroy]) do
47
+ ActiveCash::Cache.set_false(
48
+ ActiveCash::Utils.extract_args(opts, self)
49
+ )
50
+ end
51
+ end
52
+ end
53
+
54
+ def create_methods(model, opts) #raise error when arg not given
55
+ model.send(:define_singleton_method, "cached_#{opts[:name]}_by") do |args = {}|
56
+ return ActiveCash::Cache.exists?(
57
+ find_by: opts[:find_by].inject({}) {|h, arg| h[arg] = args[arg]; h},
58
+ method_name: opts[:name],
59
+ klass: opts[:klass]
60
+ )
61
+ end
62
+ end
63
+
64
+ def raise_unknown_cache_type(type)
65
+ raise(
66
+ UnknownCacheTypeError,
67
+ "Unknown cache type #{type}. Valid options are: :existence"
68
+ )
69
+ end
70
+
71
+ def raise_redefined_cache_error(name)
72
+ raise(
73
+ RedefinedCacheError,
74
+ "#{name} cache already exists"
75
+ )
76
+ end
77
+
78
+ #fix this
79
+ def extract_args(opts, instance)
80
+ {
81
+ find_by: opts[:find_by].inject({}){|h, arg|
82
+ h[arg] = instance.send(arg); h
83
+ },
84
+ method_name: opts[:name],
85
+ klass: instance.class.to_s
86
+ }
87
+ end
88
+
89
+ #and this
90
+ def extract_instance_args(opts, instance)
91
+ {
92
+ find_by: opts[:find_by].inject({}){|h, arg|
93
+ h[arg] = instance.send(arg); h
94
+ },
95
+ method_name: opts[:name],
96
+ instance: instance
97
+ }
98
+ end
99
+
100
+ #and this
101
+ def extract_instance_args(opts, instance)
102
+ {
103
+ find_by: opts[:find_by].inject({}){|h, arg|
104
+ h[arg] = instance.send("#{arg}_was"); h
105
+ },
106
+ method_name: opts[:name],
107
+ instance: instance
108
+ }
109
+ end
110
+
111
+ def build_cache_opts(type, opts, cache_opts, klass)
112
+ #add procs/lambdas for better finds
113
+ raise_unknown_cache_type(type) unless type.to_sym == :existence
114
+ cache_opts ||= {}
115
+ name = opts[:name] || type.to_sym
116
+ raise_redefined_cache_error(name) unless cache_opts[name].nil?
117
+ cache_opts[name] = {}
118
+ cache_opts[name][:name] = name
119
+ cache_opts[name][:type] = type.to_sym
120
+ cache_opts[name][:find_by] = opts[:find_by]
121
+ cache_opts[name][:return] = opts[:return]
122
+ cache_opts[name][:update_on] = opts[:update_on] || [:create, :update, :destroy]
123
+ cache_opts[name][:klass] = klass
124
+
125
+ return cache_opts
126
+ end
127
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveCash
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_cash/version'
2
+
3
+ require 'redis-objects'
4
+
5
+ require_relative 'active_cash/errors'
6
+ require_relative 'active_cash/adapter'
7
+ require_relative 'active_cash/cache'
8
+ require_relative 'active_cash/utils'
9
+
10
+ module ActiveCash
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ module ClassMethods
15
+ def caches(type, opts = {})
16
+ name = opts[:name] || type.to_sym
17
+ @cache_opts = Utils.build_cache_opts(type, opts, @cache_opts, self.to_s)
18
+ Utils.set_callbacks(self, @cache_opts[name])
19
+ Utils.create_methods(self, @cache_opts[name])
20
+ end
21
+
22
+ def cache_opts
23
+ @cache_opts
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,215 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_cash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Filippos Vasilakis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis-objects
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activerecord
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: factory_girl
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.5'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.5'
111
+ - !ruby/object:Gem::Dependency
112
+ name: database_cleaner
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.5'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.5'
125
+ - !ruby/object:Gem::Dependency
126
+ name: fakeredis
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.5'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.5'
139
+ - !ruby/object:Gem::Dependency
140
+ name: test_after_commit
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.4'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.4'
153
+ - !ruby/object:Gem::Dependency
154
+ name: pry
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.10'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.10'
167
+ description: Write a longer description or delete this line.
168
+ email:
169
+ - vasilakisfil@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".gitignore"
175
+ - ".rspec"
176
+ - ".travis.yml"
177
+ - CODE_OF_CONDUCT.md
178
+ - Gemfile
179
+ - LICENSE.txt
180
+ - README.md
181
+ - Rakefile
182
+ - active_cash.gemspec
183
+ - bin/console
184
+ - bin/setup
185
+ - lib/active_cash.rb
186
+ - lib/active_cash/adapter.rb
187
+ - lib/active_cash/cache.rb
188
+ - lib/active_cash/errors.rb
189
+ - lib/active_cash/utils.rb
190
+ - lib/active_cash/version.rb
191
+ homepage: https://github.com/vasilakisfil/active_cash
192
+ licenses:
193
+ - MIT
194
+ metadata: {}
195
+ post_install_message:
196
+ rdoc_options: []
197
+ require_paths:
198
+ - lib
199
+ required_ruby_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ required_rubygems_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ requirements: []
210
+ rubyforge_project:
211
+ rubygems_version: 2.4.5
212
+ signing_key:
213
+ specification_version: 4
214
+ summary: Write a short summary, because Rubygems requires one.
215
+ test_files: []