tobi-cached 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2009-06-07
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ cached.gemspec
7
+ init.rb
8
+ lib/cached.rb
9
+ lib/cached/config.rb
10
+ lib/cached/config_compiler.rb
11
+ lib/cached/model.rb
12
+ lib/cached/record.rb
13
+ test/people_database.rb
14
+ test/test_cached.rb
15
+ test/test_cached_delegation.rb
16
+ test/test_config_compiler.rb
17
+ test/test_helper.rb
18
+ test/test_record.rb
data/PostInstall.txt ADDED
File without changes
data/README.rdoc ADDED
@@ -0,0 +1,63 @@
1
+ = cached
2
+
3
+ * http://github.com/tobi/cached
4
+
5
+ == DESCRIPTION:
6
+
7
+ Small trial project that attempts to accelerate common active record like operations without too much black magic.
8
+
9
+
10
+ == SYNOPSIS:
11
+
12
+ class Product < AR:Base
13
+
14
+ cache_by_key :id do
15
+ index :name
16
+ index [:brand, :name]
17
+
18
+ delegate_to :find
19
+ end
20
+ end
21
+
22
+ Product.create :name => 'ipod', :brand => 'apple'
23
+
24
+ Product.lookup(1) # cache_hit, 1 memcached query
25
+ Product.lookup(2) # cache_miss, 1 memcached query, 1 db query: .find(2) (see delegates_to)
26
+ Product.lookup_by_name('ipod') # cache_hit, 2 memcached queries
27
+ Product.lookup_by_brand_and_name('apple','ipod') # cache_hit, 2 memcached queries
28
+
29
+ Product.lookup_by_something('else') # raise NoMethodError
30
+
31
+
32
+ == REQUIREMENTS:
33
+
34
+ * Active Record included with rails 2.3+
35
+
36
+ == INSTALL:
37
+
38
+ * Gem install or plugin install
39
+
40
+ == LICENSE:
41
+
42
+ (The MIT License)
43
+
44
+ Copyright (c) 2009 Tobias Lütke
45
+
46
+ Permission is hereby granted, free of charge, to any person obtaining
47
+ a copy of this software and associated documentation files (the
48
+ 'Software'), to deal in the Software without restriction, including
49
+ without limitation the rights to use, copy, modify, merge, publish,
50
+ distribute, sublicense, and/or sell copies of the Software, and to
51
+ permit persons to whom the Software is furnished to do so, subject to
52
+ the following conditions:
53
+
54
+ The above copyright notice and this permission notice shall be
55
+ included in all copies or substantial portions of the Software.
56
+
57
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
58
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
59
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
60
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
61
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
62
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
63
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ BEGIN {$VERBOSE = nil;$DEBUG = nil}
2
+
3
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
4
+ %w[rake rake/clean fileutils newgem rubigen].each { |f| require f }
5
+ require File.dirname(__FILE__) + '/lib/cached'
6
+
7
+ # Generate all the Rake tasks
8
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
9
+ $hoe = Hoe.new('cached', Cached::VERSION) do |p|
10
+ p.developer('Tobias Lütke', 'tobi@leetsoft.com')
11
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
12
+ p.extra_deps = [
13
+ ['activesupport','>= 2.3.2'],
14
+ ]
15
+
16
+ p.extra_dev_deps = [
17
+ ['newgem', ">= #{::Newgem::VERSION}"]
18
+ ]
19
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
20
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
21
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
22
+ p.rsync_args = '-av --delete --ignore-errors'
23
+ end
24
+
25
+ require 'newgem/tasks' # load /tasks/*.rake
26
+ Dir['tasks/**/*.rake'].each { |t| load t }
27
+
28
+ # TODO - want other tests/tasks run by default? Add them to the list
29
+ # task :default => [:spec, :features]
data/cached.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{cached}
5
+ s.version = "0.5.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Tobias L\303\274tke"]
9
+ s.date = %q{2009-06-10}
10
+ s.description = %q{Small trial project that attempts to accelerate common active record like operations without too much black magic.}
11
+ s.email = ["tobi@leetsoft.com"]
12
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc"]
13
+ s.files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "cached.gemspec", "init.rb", "lib/cached.rb", "lib/cached/config.rb", "lib/cached/config_compiler.rb", "lib/cached/model.rb", "lib/cached/record.rb", "test/people_database.rb", "test/test_cached.rb", "test/test_cached_delegation.rb", "test/test_config_compiler.rb", "test/test_helper.rb", "test/test_record.rb"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/tobi/cached}
16
+ s.rdoc_options = ["--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{cached}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Small trial project that attempts to accelerate common active record like operations without too much black magic.}
21
+ s.test_files = ["test/test_cached.rb", "test/test_cached_delegation.rb", "test/test_config_compiler.rb", "test/test_helper.rb", "test/test_record.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
29
+ s.add_development_dependency(%q<newgem>, [">= 1.4.1"])
30
+ s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
31
+ else
32
+ s.add_dependency(%q<activesupport>, [">= 2.3.2"])
33
+ s.add_dependency(%q<newgem>, [">= 1.4.1"])
34
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<activesupport>, [">= 2.3.2"])
38
+ s.add_dependency(%q<newgem>, [">= 1.4.1"])
39
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
40
+ end
41
+ end
data/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'cached'
2
+
3
+ ActiveRecord::Base.send(:include, Cached::Model)
4
+ ActiveRecord::Base.send(:include, Cached::Record)
data/lib/cached.rb ADDED
@@ -0,0 +1,17 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'active_support'
6
+
7
+ module Cached
8
+ VERSION = '0.5.0'
9
+
10
+ mattr_accessor :store
11
+ self.store = ActiveSupport::Cache.lookup_store(:memory_store)
12
+ end
13
+
14
+
15
+ require 'cached/config'
16
+ require 'cached/config_compiler'
17
+ require 'cached/model'
@@ -0,0 +1,18 @@
1
+ module Cached
2
+ class Config
3
+ attr_accessor :indexes, :class_name, :primary_key, :delegates
4
+
5
+ def initialize(class_name, primary_key)
6
+ @delegates, @indexes, @class_name, @primary_key = [], [], class_name.to_s, primary_key.to_s
7
+ end
8
+
9
+ def index(*args)
10
+ @indexes.push args.flatten
11
+ end
12
+
13
+ def delegate_to(*methods)
14
+ @delegates += methods.flatten
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,103 @@
1
+ module Cached
2
+
3
+ class ConfigCompiler
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ def to_ruby
10
+ [compiled_meta_methods, compiled_save_methods, compiled_fetch_methods].join
11
+ end
12
+
13
+ def compiled_meta_methods
14
+
15
+ # Instance methods
16
+ "def object_cache_primary_key; \"#{@config.primary_key}\"; end;" +
17
+ "def object_cache_key; \"\#{object_cache_prefix}:\#{#{@config.primary_key}}\"; end;" +
18
+ "def object_cache_prefix; \"#{@config.class_name}\"; end;" +
19
+ "def object_cache_hash(*args); args.join.hash; end;" +
20
+
21
+ # Class methods
22
+ "def self.object_cache_prefix; \"#{@config.class_name}\"; end;" +
23
+ "def self.object_cache_hash(*args); args.join.hash; end;"
24
+ end
25
+
26
+ def compiled_save_methods
27
+ compiled_save_object_method + compiled_save_index_method
28
+ end
29
+
30
+ def compiled_save_object_method
31
+ "def save_object_to_cache;" +
32
+ "Cached.store.write(object_cache_key, self);" +
33
+ "end;" +
34
+
35
+ "def expire_object_in_cache;" +
36
+ "Cached.store.delete(object_cache_key);" +
37
+ "end;"
38
+ end
39
+
40
+ def compiled_save_index_method
41
+
42
+ keys = @config.indexes.collect { |index| index_cache_key(index) }
43
+
44
+ "def save_indexes_to_cache;" +
45
+ "v = #{@config.primary_key};" +
46
+ keys.collect{|k| "Cached.store.write(#{k}, v);"}.join +
47
+ "end;" +
48
+
49
+ "def expire_indexes_in_cache;" +
50
+ keys.collect{|k| "Cached.store.delete(#{k});"}.join +
51
+ "end;"
52
+ end
53
+
54
+ def compiled_fetch_method_for(index)
55
+ index_name = index_name(index)
56
+ cache_key = index_cache_key(index)
57
+
58
+ method_suffix_and_parameters = "#{index_name}(#{index.join(', ')})"
59
+
60
+ delegation = @config.delegates.collect { |delegate| "|| #{delegate}_by_#{method_suffix_and_parameters}" }
61
+
62
+ "def self.lookup_by_#{method_suffix_and_parameters};" +
63
+ " if key = Cached.store.read(#{cache_key});"+
64
+ " lookup(key);"+
65
+ " else;"+
66
+ " obj = nil #{delegation};" +
67
+ " obj.save_indexes_to_cache if obj.respond_to?(:save_indexes_to_cache);" +
68
+ " obj;" +
69
+ " end;" +
70
+ "end;"
71
+ end
72
+
73
+ def compiled_fetch_method_for_primary_key
74
+
75
+ delegation = @config.delegates.collect{|c| "|| #{c}(pk)" }.join
76
+
77
+ "def self.lookup(pk);" +
78
+ " Cached.store.fetch(\"#\{object_cache_prefix}:#\{pk}\") { nil #{delegation} };" +
79
+ "end;" +
80
+
81
+
82
+ "def self.lookup_by_#{@config.primary_key}(pk);" +
83
+ " lookup(pk); "+
84
+ "end;"
85
+ end
86
+
87
+ def compiled_fetch_methods
88
+ compiled_fetch_method_for_primary_key + @config.indexes.collect { |index| compiled_fetch_method_for(index) }.join(';')
89
+ end
90
+
91
+ private
92
+
93
+ def index_cache_key(index)
94
+ "\"#\{object_cache_prefix}/#{index_name(index)}:#\{object_cache_hash(#{index.join(', ')})}\""
95
+ end
96
+
97
+ def index_name(index)
98
+ index.collect(&:to_s).collect(&:downcase).collect(&:underscore).join('_and_')
99
+ end
100
+ end
101
+
102
+
103
+ end
@@ -0,0 +1,27 @@
1
+ module Cached
2
+
3
+ module Model
4
+
5
+ module ClassMethods
6
+ def cache_by_key(primary_key, &block)
7
+ config = Config.new(name.underscore.downcase, primary_key)
8
+ config.instance_eval(&block)
9
+
10
+ self.class_eval ConfigCompiler.new(config).to_ruby, __FILE__, __LINE__
11
+ end
12
+ end
13
+
14
+ def self.included(base)
15
+ base.extend ClassMethods
16
+ end
17
+
18
+
19
+ def save_to_cache
20
+ save_object_to_cache
21
+ save_indexes_to_cache
22
+ end
23
+
24
+ end
25
+
26
+
27
+ end
@@ -0,0 +1,25 @@
1
+ module Cached
2
+ module Record
3
+
4
+ def self.included?(base)
5
+
6
+ if base.respond_to?(:save)
7
+ base.alias_method_chain :save, :cached
8
+ end
9
+
10
+ end
11
+
12
+
13
+ def save_with_cached
14
+ save_without_cached
15
+
16
+ # expire the cache, the object will be stored in it's prestine form
17
+ # after the next lookup call hopefull.
18
+ expire_object_in_cache
19
+
20
+ # update the indexes for the new values.
21
+ store_indexes_in_cache
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => '/tmp/people.db')
4
+
5
+ ActiveRecord::Schema.define do
6
+
7
+ create_table :people, :force => true do |t|
8
+ t.column :first_name, :string
9
+ t.column :last_name, :string
10
+ end
11
+ end
12
+
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class Product < Struct.new(:id, :name, :price, :vendor)
4
+ include Cached::Model
5
+
6
+ cache_by_key :id do
7
+ index :name
8
+ index [:vendor, :name]
9
+ end
10
+
11
+ end
12
+
13
+
14
+ class TestCached < Test::Unit::TestCase
15
+
16
+ def setup
17
+ @product = Product.new(1, 'ipod', 149.00, 'apple')
18
+ end
19
+
20
+ context "cache storage" do
21
+
22
+ test "product can be stored to cache" do
23
+ @product.respond_to?(:save_to_cache)
24
+ end
25
+
26
+ test "product stores meta data in instance methods" do
27
+ assert_equal "id", @product.object_cache_primary_key
28
+ end
29
+
30
+ test "product has efficient object_cache_key instance method" do
31
+ assert_equal "product:1", @product.object_cache_key
32
+ end
33
+
34
+ test "product stores itself to memcached on save_to_cache call" do
35
+ assert @product.save_to_cache
36
+ assert_equal @product, Cached.store.read('product:1')
37
+ end
38
+
39
+ test "product stores defined indexes as backreference to product key" do
40
+ assert @product.save_to_cache
41
+ assert_equal 1, Cached.store.read("product/name:#{hash('ipod')}")
42
+ assert_equal 1, Cached.store.read("product/vendor_and_name:#{hash('appleipod')}")
43
+ end
44
+
45
+ end
46
+
47
+ context "lookups" do
48
+
49
+ test "product explicit lookup by primary_key" do
50
+ @product.save_to_cache
51
+ Cached.store.expects(:read).with('product:1', {})
52
+ Product.lookup_by_id(1)
53
+ end
54
+
55
+ test "product lookup by primary_key" do
56
+ @product.save_to_cache
57
+ Cached.store.expects(:read).with('product:1', {})
58
+ Product.lookup(1)
59
+ end
60
+
61
+ test "product lookup by index" do
62
+ @product.save_to_cache
63
+ Cached.store.expects(:read).with("product/name:#{hash('ipod')}").returns(1)
64
+ Cached.store.expects(:read).with('product:1', {})
65
+ Product.lookup_by_name('ipod')
66
+ end
67
+
68
+ test "product lookup by multi index" do
69
+ @product.save_to_cache
70
+ Cached.store.expects(:read).with("product/vendor_and_name:#{hash('appleipod')}").returns(1)
71
+ Cached.store.expects(:read).with('product:1', {})
72
+ Product.lookup_by_vendor_and_name('apple', 'ipod')
73
+ end
74
+
75
+ end
76
+
77
+ private
78
+
79
+ def hash(text)
80
+ text.hash
81
+ end
82
+
83
+ end
84
+
85
+
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+
4
+ class DelegatingProduct < Struct.new(:id, :name, :price, :vendor)
5
+ include Cached::Model
6
+
7
+ cache_by_key :id do
8
+ index :name
9
+ index [:vendor, :name]
10
+
11
+ delegate_to :find
12
+ end
13
+ end
14
+
15
+ class TestCachedDelegation < Test::Unit::TestCase
16
+
17
+ def setup
18
+ @delegating_product = DelegatingProduct.new(1, 'ipod', 149.00, 'apple')
19
+ end
20
+
21
+
22
+ test "lookup miss will delegate to find method" do
23
+ DelegatingProduct.expects(:find).with(2)
24
+ DelegatingProduct.lookup(2)
25
+ end
26
+
27
+ test "lookup by index miss will delegate to find_by_index method" do
28
+ DelegatingProduct.expects(:find).with(2)
29
+ DelegatingProduct.lookup(2)
30
+ end
31
+
32
+ private
33
+
34
+ def hash(text)
35
+ text.hash
36
+ end
37
+
38
+ end
39
+
40
+
41
+
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestConfigCompiler < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @dump = Class.new
7
+ @config = Cached::ConfigCompiler.new(Cached::Config.new('product', 'id'))
8
+ end
9
+
10
+ test "syntax compiled_meta_methods" do
11
+ @dump.instance_eval @config.compiled_meta_methods
12
+ @dump.respond_to?(:object_cache_primary_key)
13
+ @dump.respond_to?(:object_cache_key)
14
+ @dump.respond_to?(:object_cache_prefix)
15
+ @dump.respond_to?(:object_cache_hash)
16
+ end
17
+
18
+ test "syntax compiled_save_object_method" do
19
+ @dump.instance_eval @config.compiled_save_object_method
20
+
21
+ @dump.respond_to?(:save_object_to_cache)
22
+ end
23
+
24
+ test "syntax compiled_save_index_method" do
25
+ @dump.instance_eval @config.compiled_save_index_method
26
+
27
+ @dump.respond_to?(:save_indexes_to_cache)
28
+ end
29
+
30
+ test "syntax compiled_fetch_method_for single column" do
31
+ @dump.instance_eval @config.compiled_fetch_method_for([:name])
32
+
33
+ @dump.respond_to?(:lookup_by_name)
34
+ end
35
+
36
+ test "syntax compiled_fetch_method_for multi column" do
37
+ @dump.instance_eval @config.compiled_fetch_method_for([:name, :brand])
38
+
39
+ @dump.respond_to?(:lookup_by_name_and_brand)
40
+ end
41
+
42
+ test "syntax compiled_fetch_method_for_primary_key" do
43
+ @dump.instance_eval @config.compiled_fetch_method_for_primary_key
44
+
45
+ @dump.respond_to?(:lookup)
46
+ @dump.respond_to?(:lookup_by_id)
47
+ end
48
+
49
+ test "all syntax" do
50
+ @dump.instance_eval @config.to_ruby
51
+ end
52
+
53
+ end
@@ -0,0 +1,24 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require 'rubygems'
4
+ require 'mocha'
5
+ require File.dirname(__FILE__) + '/../lib/cached'
6
+
7
+ require 'active_support/cache'
8
+ require 'active_record'
9
+
10
+ Cached.store = ActiveSupport::Cache.lookup_store(:memory_store)
11
+ #Cached.store = ActiveSupport::Cache.lookup_store(:mem_cache_store)
12
+
13
+
14
+ class Test::Unit::TestCase
15
+
16
+ def self.test(string, &block)
17
+ define_method("test:#{string}", &block)
18
+ end
19
+
20
+ def self.context(string)
21
+ yield
22
+ end
23
+
24
+ end
@@ -0,0 +1,56 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require File.dirname(__FILE__) + '/people_database'
3
+
4
+ require 'cached/record'
5
+
6
+ class Person < ActiveRecord::Base
7
+ include Cached::Model
8
+ include Cached::Record
9
+
10
+ def name
11
+ "#{first_name} #{last_name}"
12
+ end
13
+
14
+ cache_by_key :id do
15
+ index :first_name
16
+ index :last_name
17
+ index [:first_name, :last_name]
18
+
19
+ delegate_to :find
20
+ end
21
+ end
22
+
23
+ class TestRecord < Test::Unit::TestCase
24
+
25
+ def setup
26
+ @bob = Person.create(:first_name => 'Bob', :last_name => 'Bobsen')
27
+ end
28
+
29
+ test "cachemiss delegates to find" do
30
+ assert !Cached.store.read("person:1")
31
+ assert_equal @bob, Person.lookup(@bob.id)
32
+ end
33
+
34
+ test "load bob from cache store" do
35
+ @bob.save_to_cache
36
+
37
+ assert_equal @bob, Person.lookup_by_first_name('Bob')
38
+ assert_equal @bob, Person.lookup_by_last_name('Bobsen')
39
+ assert_equal @bob, Person.lookup_by_first_name_and_last_name('Bob', 'Bobsen')
40
+ end
41
+
42
+ test "cache miss on index query will make returned object re-save its indexes" do
43
+ assert !Cached.store.read("person/first_name:#{hash('Bob')}")
44
+ assert_equal @bob, Person.lookup_by_first_name('Bob')
45
+
46
+ assert Cached.store.read("person/first_name:#{hash('Bob')}")
47
+ end
48
+
49
+
50
+ private
51
+
52
+ def hash(text)
53
+ text.hash
54
+ end
55
+
56
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tobi-cached
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - "Tobias L\xC3\xBCtke"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-10 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.3.2
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: newgem
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.4.1
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.8.0
44
+ version:
45
+ description: Small trial project that attempts to accelerate common active record like operations without too much black magic.
46
+ email:
47
+ - tobi@leetsoft.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - History.txt
54
+ - Manifest.txt
55
+ - PostInstall.txt
56
+ - README.rdoc
57
+ files:
58
+ - History.txt
59
+ - Manifest.txt
60
+ - PostInstall.txt
61
+ - README.rdoc
62
+ - Rakefile
63
+ - cached.gemspec
64
+ - init.rb
65
+ - lib/cached.rb
66
+ - lib/cached/config.rb
67
+ - lib/cached/config_compiler.rb
68
+ - lib/cached/model.rb
69
+ - lib/cached/record.rb
70
+ - test/people_database.rb
71
+ - test/test_cached.rb
72
+ - test/test_cached_delegation.rb
73
+ - test/test_config_compiler.rb
74
+ - test/test_helper.rb
75
+ - test/test_record.rb
76
+ has_rdoc: true
77
+ homepage: http://github.com/tobi/cached
78
+ post_install_message:
79
+ rdoc_options:
80
+ - --main
81
+ - README.rdoc
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ version:
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ version:
96
+ requirements: []
97
+
98
+ rubyforge_project: cached
99
+ rubygems_version: 1.2.0
100
+ signing_key:
101
+ specification_version: 2
102
+ summary: Small trial project that attempts to accelerate common active record like operations without too much black magic.
103
+ test_files:
104
+ - test/test_cached.rb
105
+ - test/test_cached_delegation.rb
106
+ - test/test_config_compiler.rb
107
+ - test/test_helper.rb
108
+ - test/test_record.rb