constant_cache 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.
- data/HISTORY +4 -0
- data/MIT-LICENSE +20 -0
- data/README +75 -0
- data/Rakefile +46 -0
- data/lib/constant_cache.rb +6 -0
- data/lib/constant_cache/cache_methods.rb +44 -0
- data/lib/constant_cache/format.rb +9 -0
- data/lib/constant_cache/version.rb +11 -0
- data/spec/examples/constant_cache/cache_methods_spec.rb +63 -0
- data/spec/examples/constant_cache/format_spec.rb +35 -0
- data/spec/spec_helper.rb +45 -0
- metadata +85 -0
data/HISTORY
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 [name of plugin creator]
|
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
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
ConstantCache
|
2
|
+
===============
|
3
|
+
|
4
|
+
When your database has tables that store lookup data, there is a tendency
|
5
|
+
to provide those values as constants in the model. If you have an
|
6
|
+
account_statuses table with a corresponding model, your constants may look
|
7
|
+
like this:
|
8
|
+
|
9
|
+
class AccountStatus
|
10
|
+
ACTIVE = 1
|
11
|
+
PENDING = 2
|
12
|
+
DISABLED = 3
|
13
|
+
end
|
14
|
+
|
15
|
+
There are a couple of problems with this approach:
|
16
|
+
|
17
|
+
As you add more lookup data to the table, you need to ensure that you're
|
18
|
+
updating your models along with the data.
|
19
|
+
|
20
|
+
The constants are stored as integer values and need to match up exactly
|
21
|
+
with the data that's in the table (not necessarily a bad thing), but this
|
22
|
+
solution forces you to write code like this:
|
23
|
+
|
24
|
+
Account.new(:username => 'preagan', :status => AccountStatus.find(AccountStatus::PENDING))
|
25
|
+
|
26
|
+
This requires multiple calls to find and obfuscates the code a bit. Since classes
|
27
|
+
in Ruby are executable code, we can cache the objects from the database at runtime
|
28
|
+
and use them in your application.
|
29
|
+
|
30
|
+
Installation
|
31
|
+
============
|
32
|
+
|
33
|
+
This code is packaged as a gem, so simply use the `gem` command to install:
|
34
|
+
|
35
|
+
gem install constant_cache
|
36
|
+
|
37
|
+
Example
|
38
|
+
=======
|
39
|
+
|
40
|
+
"Out of the box," the constant_cache gem assumes that you want to use the 'name' column to generate
|
41
|
+
constants from a column called 'name' in your database table. Assuming this schema:
|
42
|
+
|
43
|
+
create_table :account_statuses do |t|
|
44
|
+
t.string :name, :description
|
45
|
+
end
|
46
|
+
|
47
|
+
AccountStatus.create!(:name => 'Active', :description => 'Active user account')
|
48
|
+
AccountStatus.create!(:name => 'Pending', :description => 'Pending user account')
|
49
|
+
AccountStatus.create!(:name => 'Disabled', :description => 'Disabled user account')
|
50
|
+
|
51
|
+
We can use the plugin to cache the data in the table:
|
52
|
+
|
53
|
+
class AccountStatus
|
54
|
+
caches_constants
|
55
|
+
end
|
56
|
+
|
57
|
+
Now you can write code that's a little cleaner and not use multiple unnecessary find calls:
|
58
|
+
|
59
|
+
Account.new(:username => 'preagan', :status => AccountStatus::PENDING)
|
60
|
+
|
61
|
+
If the column you want to use as the constant isn't 'name', you can set that in the model. If
|
62
|
+
we have :name, :slug, and :description, we can use 'slug' instead:
|
63
|
+
|
64
|
+
class AccountStatus
|
65
|
+
caches_constants :key => :slug
|
66
|
+
end
|
67
|
+
|
68
|
+
The value for the constant is truncated at 64 characters by default, but you can adjust this as
|
69
|
+
well:
|
70
|
+
|
71
|
+
class AccountStatus
|
72
|
+
caches_constants :limit => 16
|
73
|
+
end
|
74
|
+
|
75
|
+
Copyright (c) 2007 Patrick Reagan of Viget Labs (patrick.reagan@viget.com), released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
|
5
|
+
require 'lib/constant_cache/version'
|
6
|
+
|
7
|
+
GEM = "constant_cache"
|
8
|
+
AUTHOR = "Patrick Reagan"
|
9
|
+
EMAIL = "patrick.reagan@viget.com"
|
10
|
+
HOMEPAGE = "http://www.viget.com/extend/"
|
11
|
+
SUMMARY = "Patches active record to add a caches_constants class method that will cache lookup data for your application."
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
s.name = GEM
|
15
|
+
s.version = ConstantCache::VERSION::STRING
|
16
|
+
s.platform = Gem::Platform::RUBY
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.extra_rdoc_files = %w(README MIT-LICENSE HISTORY)
|
19
|
+
s.summary = SUMMARY
|
20
|
+
s.description = s.summary
|
21
|
+
s.author = AUTHOR
|
22
|
+
s.email = EMAIL
|
23
|
+
s.homepage = HOMEPAGE
|
24
|
+
|
25
|
+
s.add_dependency('activerecord', '>= 2.0.2')
|
26
|
+
s.add_dependency('activesupport', '>= 2.0.2')
|
27
|
+
|
28
|
+
s.require_path = 'lib'
|
29
|
+
s.autorequire = GEM
|
30
|
+
s.files = %w(MIT-LICENSE README Rakefile HISTORY) + Dir.glob("{lib,spec}/**/*")
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
34
|
+
pkg.gem_spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
task :install => [:package] do
|
38
|
+
sh %{sudo gem install pkg/#{GEM}-#{VERSION}}
|
39
|
+
end
|
40
|
+
|
41
|
+
Spec::Rake::SpecTask.new do |t|
|
42
|
+
t.spec_files = FileList['spec/examples/**/*_spec.rb']
|
43
|
+
t.rcov = true
|
44
|
+
t.rcov_opts = ['--exclude', 'spec']
|
45
|
+
t.spec_opts = ['--format', 'specdoc']
|
46
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
require 'constant_cache/format'
|
2
|
+
require 'constant_cache/cache_methods'
|
3
|
+
|
4
|
+
String.send(:include, ConstantCache::Format)
|
5
|
+
ActiveRecord::Base.send(:extend, ConstantCache::CacheMethods::ClassMethods)
|
6
|
+
ActiveRecord::Base.send(:include, ConstantCache::CacheMethods::InstanceMethods)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ConstantCache
|
2
|
+
|
3
|
+
class DuplicateConstantError < StandardError; end
|
4
|
+
class InvalidLimitError < StandardError; end
|
5
|
+
|
6
|
+
module CacheMethods
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def caches_constants(additional_options = {})
|
10
|
+
cattr_accessor :cache_options
|
11
|
+
|
12
|
+
self.cache_options = {:key => :name, :limit => 64}.merge(additional_options)
|
13
|
+
|
14
|
+
raise ConstantCache::InvalidLimitError, "Limit of #{self.cache_options[:limit]} is invalid" if self.cache_options[:limit] < 1
|
15
|
+
find(:all).each {|model| model.set_instance_as_constant }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module InstanceMethods
|
20
|
+
|
21
|
+
def constant_name
|
22
|
+
constant_name = self.send(self.class.cache_options[:key].to_sym).constant_name
|
23
|
+
constant_name = constant_name[0, self.class.cache_options[:limit]] unless constant_name.blank?
|
24
|
+
constant_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_instance_as_constant
|
28
|
+
const = constant_name
|
29
|
+
if !const.blank?
|
30
|
+
raise ConstantCache::DuplicateConstantError, "Constant #{self.class.to_s}::#{const} has already been defined" if self.class.const_defined?(const)
|
31
|
+
self.class.const_set(const, self) if !const.blank?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO: do we want this behavior?
|
36
|
+
# def constant_cache_destroy
|
37
|
+
# constant_name = constant_name()
|
38
|
+
# self.class.send(:remove_const, constant_name) if self.class.const_defined?(constant_name)
|
39
|
+
# end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe SimpleClass, "with constant_cache mix-in" do
|
4
|
+
|
5
|
+
before { @value = 'pony' }
|
6
|
+
|
7
|
+
it "should set some default options" do
|
8
|
+
enable_caching(SimpleClass)
|
9
|
+
SimpleClass.cache_options.should == {:key => :name, :limit => 64}
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should overwrite default options when passed new ones" do
|
13
|
+
additional_options = {:key => :new_key, :limit => 100}
|
14
|
+
|
15
|
+
enable_caching(SimpleClass, [], additional_options)
|
16
|
+
SimpleClass.cache_options.should == additional_options
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should use name as the default constant key" do
|
20
|
+
enable_caching(SimpleClass, [{:name => 'one', :value => @value}])
|
21
|
+
SimpleClass::ONE.value.should == @value
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not set constant when value is nil" do
|
25
|
+
proc = lambda { enable_caching(SimpleClass, [{:name => '?', :value => @pony}]) }
|
26
|
+
proc.should_not change(SimpleClass.constants, :size)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise an exception with message when encountering a duplicate constant" do
|
30
|
+
proc = lambda { enable_caching(SimpleClass, [{:name => 'duplicate'}, {:name => 'duplicate'}]) }
|
31
|
+
proc.should raise_error(ConstantCache::DuplicateConstantError, 'Constant SimpleClass::DUPLICATE has already been defined')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should truncate long constant names" do
|
35
|
+
enable_caching(SimpleClass, [{:name => 'a' * 65, :value => @value}])
|
36
|
+
SimpleClass.const_get('A' * 64).value.should == @value
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should honor configuration of truncation point" do
|
40
|
+
enable_caching(SimpleClass, [{:name => 'abcdef', :value => @value}], {:limit => 3})
|
41
|
+
SimpleClass::ABC.value.should == @value
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should raise an exception when truncated constant names collide" do
|
45
|
+
proc = lambda { enable_caching(SimpleClass, [{:name => 'abcd'}, {:name => 'abef'}], {:limit => 2}) }
|
46
|
+
proc.should raise_error(ConstantCache::DuplicateConstantError)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should raise an exception when an invalid limit is set" do
|
50
|
+
limit = 0
|
51
|
+
proc = lambda { SimpleClass.caches_constants(:limit => limit) }
|
52
|
+
proc.should raise_error(ConstantCache::InvalidLimitError, "Limit of #{limit} is invalid")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe AlternateClass, "with constant_cache mix-in" do
|
57
|
+
|
58
|
+
it "should allow override of key" do
|
59
|
+
enable_caching(AlternateClass, [{:name2 => 'foo bar', :value => @value}], {:key => :name2})
|
60
|
+
AlternateClass::FOO_BAR.value.should == @value
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe String, "with constant_name method" do
|
4
|
+
|
5
|
+
before { String.send(:include, ConstantCache::Format) }
|
6
|
+
|
7
|
+
it "should upcase its characters" do
|
8
|
+
'test'.constant_name.should == 'TEST'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should replace whitespace with a single underscore" do
|
12
|
+
"test this \tformat\nplease.".constant_name.should == 'TEST_THIS_FORMAT_PLEASE'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should remove leading and trailing whitespace" do
|
16
|
+
' test '.constant_name.should == 'TEST'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should remove non-word characters" do
|
20
|
+
'!test?'.constant_name.should == 'TEST'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not singularize plural name" do
|
24
|
+
'tests'.constant_name.should == 'TESTS'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return nil when all characters are removed" do
|
28
|
+
'?'.constant_name.should be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should collapse multiple underscores" do
|
32
|
+
'test__me'.constant_name.should == 'TEST_ME'
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
require 'activesupport'
|
6
|
+
require 'activerecord'
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__), %w(.. lib constant_cache))
|
11
|
+
|
12
|
+
Dir.glob("#{lib_dir}/*.rb").each {|file| require file }
|
13
|
+
|
14
|
+
module ConstantCache
|
15
|
+
module SpecHelper
|
16
|
+
|
17
|
+
def enable_caching(klass, values = [], additional_options = {})
|
18
|
+
return_values = values.empty? ? [] : values.map {|params| klass.new(params) }
|
19
|
+
|
20
|
+
klass.expects(:find).with(:all).returns(return_values)
|
21
|
+
klass.caches_constants(additional_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Runner.configuration.mock_with :mocha
|
28
|
+
Spec::Runner.configuration.include ConstantCache::SpecHelper
|
29
|
+
|
30
|
+
String.send(:include, ConstantCache::Format)
|
31
|
+
ActiveRecord::Base.send(:include, ConstantCache::CacheMethods::InstanceMethods)
|
32
|
+
ActiveRecord::Base.send(:extend, ConstantCache::CacheMethods::ClassMethods)
|
33
|
+
|
34
|
+
class BaseClass < ActiveRecord::Base
|
35
|
+
def self.columns; []; end
|
36
|
+
end
|
37
|
+
|
38
|
+
class SimpleClass < BaseClass
|
39
|
+
PREDEFINED = 'foo'
|
40
|
+
attr_accessor :name, :value
|
41
|
+
end
|
42
|
+
|
43
|
+
class AlternateClass < BaseClass;
|
44
|
+
attr_accessor :name2, :value
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: constant_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Patrick Reagan
|
8
|
+
autorequire: constant_cache
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-04-08 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.0.2
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: activesupport
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 2.0.2
|
32
|
+
version:
|
33
|
+
description: Patches active record to add a caches_constants class method that will cache lookup data for your application.
|
34
|
+
email: patrick.reagan@viget.com
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README
|
41
|
+
- MIT-LICENSE
|
42
|
+
- HISTORY
|
43
|
+
files:
|
44
|
+
- MIT-LICENSE
|
45
|
+
- README
|
46
|
+
- Rakefile
|
47
|
+
- HISTORY
|
48
|
+
- lib/constant_cache
|
49
|
+
- lib/constant_cache/cache_methods.rb
|
50
|
+
- lib/constant_cache/format.rb
|
51
|
+
- lib/constant_cache/version.rb
|
52
|
+
- lib/constant_cache.rb
|
53
|
+
- spec/examples
|
54
|
+
- spec/examples/constant_cache
|
55
|
+
- spec/examples/constant_cache/cache_methods_spec.rb
|
56
|
+
- spec/examples/constant_cache/format_spec.rb
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://www.viget.com/extend/
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.0.0
|
81
|
+
signing_key:
|
82
|
+
specification_version: 2
|
83
|
+
summary: Patches active record to add a caches_constants class method that will cache lookup data for your application.
|
84
|
+
test_files: []
|
85
|
+
|