reuse_query_results 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: c1b2157313e9aeacb8ad1bfdaebd928d5f8b40a6
4
+ data.tar.gz: 870d10bf386099250a44715c6c8392537720faa7
5
+ SHA512:
6
+ metadata.gz: 0615bc0a42cfd1fd36c3c5c457afc8d81aa234a2cb2ce010973b98f318c7c0da651217c22060224d5567249442a65802d527de991803ca515756d1ee37e33617
7
+ data.tar.gz: 8be939634b718a13344da664e0da03748de6ff95b575e360cb2edcecda8bec91c4dcf3738a18f608aed8e8793d904b246d5b3acb24f70517bf33a49064dfbd67
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ log
20
+ spec/*.sqlite3
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in reuse_query_results.gemspec
4
+ gemspec
5
+
6
+
7
+ group :development, :test do
8
+ gem 'rspec', '~> 2.14.1'
9
+ gem 'rspec-rails', '~> 2.14.2'
10
+ gem 'rescue_tracer', '~> 0.0.2'
11
+ gem 'byebug'
12
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 COOKPAD Inc.
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 all
13
+ 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 THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,42 @@
1
+ # ReuseQueryResults
2
+ Improve development environment speed.
3
+ Reuse query results and clear cache when insert update and delete record.
4
+ No more db requests.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'reuse_query_results', git: 'https://github.com/cookpad/reuse_query_results'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install reuse_query_results
21
+
22
+ ## Usage
23
+ run command on development environment .
24
+ ```
25
+ REUSE_QUERY_RESULTS=1 rails server
26
+ ```
27
+
28
+ Can share update status between separated applications.
29
+ ```ruby
30
+ # initializers/reuse_query_results.rb
31
+ memcache = ActiveSupport::Cache.lookup_store(:dalli_store, address)
32
+ ReuseQueryResults.storage = ReuseQueryResults::Storage.new(sync_client: memcache)
33
+
34
+ ```
35
+
36
+ ## Contributing
37
+
38
+ 1. Fork it ( https://github.com/[my-github-username]/reuse_query_results/fork )
39
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
40
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
41
+ 4. Push to the branch (`git push origin my-new-feature`)
42
+ 5. Create a new Pull Request
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ task :noop do; end
8
+ task :default => :spec
9
+
10
+ RSpec::Core::RakeTask.new(:spec => :noop)
11
+
@@ -0,0 +1,41 @@
1
+ require "reuse_query_results/version"
2
+ require "reuse_query_results/storage"
3
+
4
+ module ReuseQueryResults
5
+ class << self
6
+ def storage
7
+ @storage ||= Storage.new
8
+ end
9
+
10
+ def storage=(storage)
11
+ @storage = storage
12
+ end
13
+
14
+
15
+ def cache(connection, sql, &block)
16
+ database = connection.instance_variable_get(:'@config')[:database]
17
+ case sql.strip
18
+ when (/\AINSERT INTO (?:\.*[`"]?([^.\s`"]+)[`"]?)*/i)
19
+ return storage.clear_and_execute(database, $1, &block)
20
+ when (/\ADELETE FROM (?:\.*[`"]?([^.\s`"]+)[`"]?)*/i)
21
+ return storage.clear_and_execute(database, $1, &block)
22
+ when (/\AUPDATE (?:\.*[`"]?([^.\s`"]+)[`"]?)*/i)
23
+ return storage.clear_and_execute(database, $1, &block)
24
+ when (/\ASELECT\s+.*FROM\s+"?([^\.\s'"]+)"?/im)
25
+ return storage.fetch_or_execute(database, tables(sql), sql, &block)
26
+ end
27
+ block.call
28
+ end
29
+
30
+ def tables(sql)
31
+ sql.scan(/(?:FROM|JOIN)\s+[`"]?([^\.\s'`"]+)(?:[`"]?)/).flatten.sort
32
+ end
33
+ end
34
+ end
35
+
36
+ begin
37
+ require 'rails'
38
+ require_relative 'reuse_query_results/railtie'
39
+ rescue LoadError
40
+ require_relative "reuse_query_results/active_record_monkey_patch"
41
+ end
@@ -0,0 +1,31 @@
1
+ module ReuseQueryResults
2
+ module Cache
3
+ def execute(sql, *)
4
+ ReuseQueryResults.cache(self, sql) do
5
+ super
6
+ end
7
+ end
8
+
9
+ def exec_query(sql, *)
10
+ ReuseQueryResults.cache(self, sql) do
11
+ super
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ begin
18
+ require 'active_record/connection_adapters/sqlite3_adapter'
19
+ ::ActiveRecord::ConnectionAdapters::SQLite3Adapter.send :prepend, ReuseQueryResults::Cache
20
+ rescue LoadError
21
+ end
22
+ begin
23
+ require 'active_record/connection_adapters/postgresql_adapter'
24
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send :prepend, ReuseQueryResults::Cache
25
+ rescue LoadError
26
+ end
27
+ begin
28
+ require 'active_record/connection_adapters/abstract_mysql_adapter'
29
+ ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.send :prepend, ReuseQueryResults::Cache
30
+ rescue LoadError
31
+ end
@@ -0,0 +1,10 @@
1
+ module ReuseQueryResults
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'resque_query_results', after: 'active_record.initialize_database' do
4
+ ActiveSupport.on_load :active_record do
5
+ Rails.logger.info("load reuse_query_results")
6
+ require_relative "active_record_monkey_patch" if ENV["REUSE_QUERY_RESULTS"] && Rails.env.development?
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,68 @@
1
+ module ReuseQueryResults
2
+ class Storage
3
+ attr_reader :databases
4
+ def initialize(sync_client: nil)
5
+ @sync_client = sync_client
6
+ clear_all
7
+ end
8
+
9
+ def add(database, tables, sql, result)
10
+ @databases[database][tables][sql] = { data: result, timestamp: Time.now.to_i }
11
+ end
12
+
13
+ def clear_all
14
+ @databases = Hash.new do |h, k|
15
+ h[k] = Hash.new { |h2, k2| h2[k2] = {} }
16
+ end
17
+ return unless sync_mode?
18
+ @sync_client.clear
19
+ end
20
+
21
+ def clear(database, table)
22
+ @databases[database].keys.select { |tables|
23
+ tables.include?(table)
24
+ }.each { |tables|
25
+ @databases[database][tables] = {}
26
+ }
27
+ return unless sync_mode?
28
+ update_modified_timestamp(database, table)
29
+ end
30
+
31
+ def fetch_or_execute(database, tables, sql, &block)
32
+ cached_result = fetch(database, tables, sql)
33
+ if cached_result
34
+ Rails.logger.debug("REUSE CACHE: #{sql}")
35
+ return cached_result
36
+ end
37
+ block.call.tap { |result| add(database, tables, sql, result) }
38
+ end
39
+
40
+ def clear_and_execute(database, table, &block)
41
+ clear(database, table)
42
+ block.call
43
+ end
44
+
45
+ def fetch(database, tables, sql)
46
+ result = @databases[database][tables][sql]
47
+ return nil unless result
48
+ return result[:data] unless sync_mode?
49
+ return updated?(database, tables, result[:timestamp]) ? nil : result[:data]
50
+ end
51
+
52
+ def sync_mode?
53
+ !!@sync_client
54
+ end
55
+
56
+ def update_modified_timestamp(database, table)
57
+ @sync_client.write("#{database}+#{table}", Time.now.to_i)
58
+ end
59
+
60
+ def updated?(database, tables, cached_timestamp)
61
+ tables.any? do |table|
62
+ next unless updated_timestamp = @sync_client.read("#{database}+#{table}")
63
+ next if updated_timestamp < cached_timestamp
64
+ next true
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module ReuseQueryResults
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'reuse_query_results/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "reuse_query_results"
8
+ spec.version = ReuseQueryResults::VERSION
9
+ spec.authors = ["morita shingo"]
10
+ spec.email = ["eudoxa.jp@gmail.com"]
11
+ spec.summary = "Reuse sql query results on development"
12
+ spec.description = "Reuse sql query results on development"
13
+ spec.homepage = ""
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 'rails'
24
+ spec.add_development_dependency 'sqlite3'
25
+ end
@@ -0,0 +1,151 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ module ReuseQueryResults
5
+ describe Storage do
6
+ before do
7
+ ReuseQueryResults.storage = ReuseQueryResults::Storage.new
8
+ end
9
+
10
+ def test_database_name
11
+ Bar.connection.instance_variable_get(:'@config')[:database]
12
+ end
13
+
14
+ def alter_database_name
15
+ AlterBar.connection.instance_variable_get(:'@config')[:database]
16
+ end
17
+
18
+ describe 'multi databases' do
19
+ it 'fetch from cache from each databases' do
20
+ allow(ReuseQueryResults.storage).to receive(:add).and_call_original
21
+ expect(ReuseQueryResults.storage).to receive(:add).with(test_database_name, %w(bars), anything, anything).once.and_call_original
22
+ expect(ReuseQueryResults.storage).to receive(:add).with(alter_database_name, %w(bars), anything, anything).once.and_call_original
23
+ 2.times { Bar.first.to_s }
24
+ 2.times { AlterBar.first.to_s }
25
+ end
26
+
27
+ it "does not clear by other database's same name table" do
28
+ Bar.first
29
+ AlterBar.create!
30
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(bars)].keys.size).to eq 1
31
+ end
32
+ end
33
+
34
+ it 'cache result' do
35
+ Foo.first
36
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(foos)].keys.size).to eq 1
37
+ end
38
+
39
+ it 'add result first time' do
40
+ allow(ReuseQueryResults.storage).to receive(:add).and_call_original
41
+ expect(ReuseQueryResults.storage).to receive(:add).with(test_database_name, %w(foos), anything, anything).once.and_call_original
42
+ Foo.first
43
+ end
44
+
45
+ it 'fetch from cache second time' do
46
+ allow(ReuseQueryResults.storage).to receive(:add).and_call_original
47
+ expect(ReuseQueryResults.storage).to receive(:add).with(test_database_name, %w(foos), anything, anything).once.and_call_original
48
+ 2.times { Foo.first.to_s }
49
+ end
50
+
51
+ it 'clear cache when insert' do
52
+ Foo.first
53
+ Foo.create!
54
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(foos)].keys.size).to eq 0
55
+ end
56
+
57
+ it 'clear cache when delete' do
58
+ Foo.create!
59
+ Foo.first
60
+ Foo.first.destroy
61
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(foos)].keys.size).to eq 0
62
+ end
63
+
64
+ it 'clear cache when update' do
65
+ Foo.create!(name: 'new')
66
+ Foo.first
67
+ Foo.first.update_attributes!(name: 'updated')
68
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(foos)].keys.size).to eq 0
69
+ end
70
+
71
+ context 'with join' do
72
+ it 'cache result' do
73
+ Foo.joins(:bar).first
74
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(bars foos)].keys.size).to eq 1
75
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(foos)].keys.size).to eq 0
76
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(bars)].keys.size).to eq 0
77
+ end
78
+
79
+ it 'clear cache when insert' do
80
+ Foo.joins(:bar).first
81
+ Foo.create!
82
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(bars foos)].keys.size).to eq 0
83
+ end
84
+ end
85
+
86
+ context 'with join' do
87
+ it 'cache result' do
88
+ Bar.create!(foo_id: Foo.create!.id)
89
+ Foo.joins(:bar).first
90
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(bars foos)].keys.size).to eq 1
91
+ end
92
+
93
+ it 'clear cache when insert' do
94
+ Foo.joins(:bar).first
95
+ Foo.create!
96
+ expect(ReuseQueryResults.storage.databases[test_database_name][%w(bars foos)].keys.size).to eq 0
97
+ end
98
+ end
99
+
100
+ describe 'sync mode' do
101
+ let(:sync_client_mock) do
102
+ double(:sync_client).tap do |client|
103
+ client.stub(:clear)
104
+ end
105
+ end
106
+
107
+ before do
108
+ ReuseQueryResults.storage = ReuseQueryResults::Storage.new(sync_client: sync_client_mock)
109
+ allow(sync_client_mock).to receive(:write)
110
+ allow(sync_client_mock).to receive(:read)
111
+ allow(ReuseQueryResults.storage).to receive(:add).and_call_original
112
+ end
113
+
114
+ it 'sync mode' do
115
+ expect(ReuseQueryResults.storage).to be_sync_mode
116
+ end
117
+
118
+ it 'update timestamp' do
119
+ expect(sync_client_mock).to receive(:write).with("#{test_database_name}+foos", kind_of(Numeric))
120
+ Foo.create!
121
+ end
122
+
123
+ it 'does not reuse query when table updated' do
124
+ expect(ReuseQueryResults.storage).to receive(:add).with(test_database_name, %w(foos), anything, anything).twice.and_call_original
125
+ sync_client_mock.stub(:read).with("#{test_database_name}+foos") { (Time.now + 1.day).to_i }
126
+ 2.times { Foo.first }
127
+ end
128
+
129
+ it 'reuse query when table no updated' do
130
+ expect(ReuseQueryResults.storage).to receive(:add).with(test_database_name, %w(foos), anything, anything).once.and_call_original
131
+ sync_client_mock.stub(:read).with("#{test_database_name}+foos") { (Time.now - 1.day).to_i }
132
+ 2.times { Foo.first }
133
+ end
134
+
135
+ describe 'joinned table' do
136
+ it 'does not reuse query when table updated' do
137
+ expect(ReuseQueryResults.storage).to receive(:add).with(test_database_name, %w(bars foos), anything, anything).twice.and_call_original
138
+ sync_client_mock.stub(:read).with("#{test_database_name}+bars") { (Time.now + 1.day).to_i }
139
+ 2.times { Foo.joins(:bar).first }
140
+ end
141
+
142
+ it 'reuse query when table no updated' do
143
+ expect(ReuseQueryResults.storage).to receive(:add).with(test_database_name, %w(bars foos), anything, anything).once.and_call_original
144
+ sync_client_mock.stub(:read).with("#{test_database_name}+bars") { (Time.now - 1.day).to_i }
145
+ 2.times { Foo.joins(:bar).first }
146
+ end
147
+ end
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,11 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: test.sqlite3
4
+ pool: 5
5
+ timeout: 5000
6
+
7
+ alter_test:
8
+ adapter: sqlite3
9
+ database: test_alter.sqlite3
10
+ pool: 5
11
+ timeout: 5000
@@ -0,0 +1,38 @@
1
+ require 'active_record/connection_handling'
2
+ require 'active_record/railtie'
3
+ require 'active_record/migration'
4
+
5
+ module ReuseQueryResultsTestApp
6
+ Application = Class.new(Rails::Application) do
7
+ config.root = __dir__
8
+ config.eager_load = false
9
+ config.active_support.deprecation = :log
10
+ end.initialize!
11
+ end
12
+
13
+
14
+ # models
15
+ class Foo < ActiveRecord::Base
16
+ has_one :bar
17
+ end
18
+
19
+ class Bar < ActiveRecord::Base
20
+ belongs_to :foo
21
+ end
22
+
23
+ class AlterBar < ActiveRecord::Base
24
+ self.table_name = 'bars'
25
+ establish_connection :alter_test
26
+ end
27
+ # migrations
28
+ class CreateAllTables < ActiveRecord::Migration
29
+ def self.up
30
+ create_table(:foos) {|t| t.string :name }
31
+ create_table(:bars) {|t| t.string :name; t.integer :foo_id }
32
+
33
+ test2_connection = ActiveRecord::Base.establish_connection(:alter_test).connection
34
+ test2_connection.create_table(:bars) {|t| t.string :name }
35
+
36
+ ActiveRecord::Base.establish_connection :test
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+
3
+ $LOAD_PATH.unshift(File.join(__dir__, '..', 'lib'))
4
+ $LOAD_PATH.unshift(__dir__)
5
+
6
+
7
+ require 'rails'
8
+ require 'reuse_query_results'
9
+ require 'reuse_query_results/active_record_monkey_patch'
10
+ require 'fake_app'
11
+
12
+ RSpec.configure do |config|
13
+ config.before :all do
14
+ CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'foos'
15
+ end
16
+
17
+ config.after :each do
18
+ ReuseQueryResults.storage.clear_all
19
+ [Foo, Bar, AlterBar].each {|m| m.delete_all }
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reuse_query_results
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - morita shingo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Reuse sql query results on development
70
+ email:
71
+ - eudoxa.jp@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - lib/reuse_query_results.rb
82
+ - lib/reuse_query_results/active_record_monkey_patch.rb
83
+ - lib/reuse_query_results/railtie.rb
84
+ - lib/reuse_query_results/storage.rb
85
+ - lib/reuse_query_results/version.rb
86
+ - reuse_query_results.gemspec
87
+ - spec/caching_query_spec.rb
88
+ - spec/config/database.yml
89
+ - spec/fake_app.rb
90
+ - spec/spec_helper.rb
91
+ homepage: ''
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.0.14
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Reuse sql query results on development
115
+ test_files:
116
+ - spec/caching_query_spec.rb
117
+ - spec/config/database.yml
118
+ - spec/fake_app.rb
119
+ - spec/spec_helper.rb