cached_values 1.0.0

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.txt ADDED
@@ -0,0 +1,3 @@
1
+ === 1.0.0 / 2008-03-06
2
+
3
+ * Converted from a Rails plugin
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/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ History.txt
2
+ MIT-LICENSE
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ init.rb
7
+ install.rb
8
+ lib/cached_values.rb
9
+ lib/cached_values/cached_value.rb
10
+ lib/cached_values/caches_value.rb
11
+ tasks/cached_values_tasks.rake
12
+ test/database.yml
13
+ test/leprechaun.rb
14
+ test/schema.rb
15
+ test/test_cached_values.rb
16
+ test/test_helper.rb
17
+ uninstall.rb
data/README.txt ADDED
@@ -0,0 +1,66 @@
1
+ = Cached Values
2
+
3
+ * http://github.com/JackDanger/cached_values/
4
+
5
+ A dead-simple way to calculate any value via Ruby or SQL and (optionally) have it saved in a database field.
6
+
7
+ == REQUIREMENTS:
8
+
9
+ * ObjectProxy
10
+
11
+ == INSTALL:
12
+
13
+ * as gem: sudo gem install cached_values
14
+ * as plugin: ./script/plugin install git://github.com/JackDanger/cached_values.git
15
+
16
+ == USAGE:
17
+
18
+ You can calculate values with a single line in any ActiveRecord model. To actually save those values you'll need to create
19
+ an attribute in your schema. By default the cached_value instance will look for an attribute with the same name as itself.
20
+ You can override this by specifying a :cache => :some_attribute option
21
+
22
+ A very simple case in which cached_values works just like the .count method on a has_many association:
23
+
24
+ class Leprechaun < ActiveRecord::Base
25
+ caches_value :total_gold_coins, :sql => 'select count(*) from gold_coins where leprechaun_id = #{id}'
26
+ end
27
+
28
+ Company.find(4).total_employees # => 45
29
+
30
+ A more sophisticated example:
31
+
32
+ class Leprechaun < ActiveRecord::Base
33
+ has_many :lucky_charms
34
+ has_many :deceived_children, :through => :lucky_charms
35
+ caches_value :total_children_remaining_to_be_deceived, :sql => '... very complicated sql here ...'
36
+ end
37
+
38
+ Leprechaun.find(14).total_children_remaining_to_be_deceived # => 6,692,243,122
39
+
40
+ The values can be of any type. The plugin will attempt to cast SQL results to the type corresponding with their database cache
41
+ but calculations in Ruby are left alone.
42
+
43
+ You can also calculate the value in Ruby using a string to be eval'ed or a Proc. Both are evaluated
44
+ in the context of the record instance.
45
+
46
+ class Leprechaun < ActiveRecord::Base
47
+ caches_value :total_gold, :eval => "some_archaic_and_silly_calculation(self.gold_coins)"
48
+ caches_value :total_lucky_charms, :eval => Proc.new {|record| record.calculate_total_lucky_charms }
49
+ end
50
+
51
+ The cache is customizable, you can specify which attribute should be used as a cache:
52
+
53
+ caches_value :runic_formula, :sql => '...' # uses 'full_formula' column if it exists
54
+ caches_value :standard_deviation_of_gold_over_time, # uses 'std' column if it exists
55
+ :sql => '...', :cache => 'std'
56
+ caches_value :id, :sql => '...', :cache => false # does NOT save any cache. This avoids overwriting an attribute
57
+
58
+ ActiveRecord callbacks can be used to call load (make sure the value is in memory), clear (flush the cache and
59
+ delete the instance), or reload (flush cache and reload instance) at certain times:
60
+
61
+ caches_value :standard_deviation, :sql => '...', :reload => [:after_save, :before_validation]
62
+ caches_value :full_formula, :sql => '...', :clear => :after_find
63
+
64
+ Bugs can be filed at http://code.lighthouseapp.com/projects/4502-hoopla-rails-plugins/
65
+
66
+ Copyright (c) 2007 Jack Danger Canty @ http://6brand.com, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # -*- ruby -*-
2
+
3
+ $:.unshift(File.dirname(__FILE__) + '/lib')
4
+ $:.unshift(File.dirname(__FILE__) + '/lib/cached_values')
5
+
6
+
7
+ require 'rubygems'
8
+ require 'hoe'
9
+ require "cached_values"
10
+
11
+ Hoe.new('cached_values', CachedValues::VERSION) do |p|
12
+ p.rubyforge_name = 'cachedvalues' # if different than lowercase project name
13
+ p.remote_rdoc_dir = '' # Release to root
14
+ p.developer('Jack Danger Canty', 'rubygems_cached_values@6brand.com')
15
+ end
16
+
17
+ # vim: syntax=Ruby
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'cached_value'
2
+ require 'cached_values'
3
+ ActiveRecord::Base.send :include, CachedValues
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ puts IO.read(File.join(File.dirname(__FILE__), 'README.txt'))
@@ -0,0 +1,145 @@
1
+ require 'object_proxy'
2
+
3
+ module ActiveRecord
4
+ class CachedValue < ObjectProxy
5
+
6
+ def initialize(owner, reflection)
7
+ @owner, @reflection = owner, reflection
8
+ reset
9
+ end
10
+
11
+ def reset
12
+ @target = nil
13
+ @loaded = false
14
+ end
15
+
16
+ def load
17
+ reset
18
+ load_target
19
+ end
20
+
21
+ def reload
22
+ @owner.instance_variable_set("@#{@reflection.name}", nil)
23
+ reset
24
+ @target = find_target(true)
25
+ @owner.send @reflection.name
26
+ end
27
+
28
+ alias update reload
29
+
30
+ def clear
31
+ clear_cache
32
+ @owner.instance_variable_set("@#{@reflection.name}", nil)
33
+ end
34
+
35
+ def loaded?
36
+ @loaded
37
+ end
38
+
39
+ def loaded
40
+ @loaded = true
41
+ end
42
+
43
+ def target
44
+ @target
45
+ end
46
+
47
+ protected
48
+
49
+ def load_target
50
+ return nil unless defined?(@loaded)
51
+ @target = find_target unless loaded?
52
+ @loaded = true
53
+ @target
54
+ end
55
+
56
+ def find_target(skip_cache = false)
57
+ target = find_target_from_cache unless skip_cache
58
+ unless target
59
+ target ||= @reflection.options[:sql] ? find_target_by_sql : find_target_by_eval
60
+ update_cache(target)
61
+ end
62
+ target
63
+ end
64
+
65
+ def find_target_from_cache
66
+ @owner.send(:read_attribute, cache_column) if has_cache?
67
+ end
68
+
69
+ def find_target_by_sql
70
+ sql = sanitize_sql(interpolate_sql(@reflection.options[:sql]))
71
+ result = @owner.class.connection.select_value(sql)
72
+ result = typecast_result(result)
73
+ result
74
+ end
75
+
76
+ def find_target_by_eval
77
+ if @reflection.options[:eval].is_a?(String)
78
+ eval(@reflection.options[:eval], @owner.send(:binding))
79
+ elsif @reflection.options[:eval].is_a?(Proc)
80
+ @reflection.options[:eval].call(@owner)
81
+ elsif @reflection.options[:eval].is_a?(Symbol)
82
+ @owner.send @reflection.options[:eval]
83
+ else
84
+ raise ArgumentError.new("The :eval option on a cached_values must be a String or a Proc or a Symbol")
85
+ end
86
+ end
87
+
88
+ def cache_column
89
+ @reflection.options[:cache]
90
+ end
91
+
92
+ def has_cache?
93
+ @reflection.options[:cache] && @owner.attribute_names.include?(@reflection.options[:cache].to_s)
94
+ end
95
+
96
+ def clear_cache
97
+ update_cache(nil)
98
+ end
99
+
100
+ def update_cache(value)
101
+ return unless has_cache?
102
+ unless @owner.new_record?
103
+ @owner.class.update_all(["#{cache_column} = ?", value], ["id = ?", @owner.id])
104
+ end
105
+ @owner.send(:write_attribute, cache_column, value)
106
+ end
107
+
108
+ def typecast_result(result)
109
+ if has_cache?
110
+ typecast_sql_result_by_cache_column_type(result)
111
+ else
112
+ if result =~ /^\d+\.\d+$/
113
+ result.to_f
114
+ elsif result =~ /^\d+$/
115
+ result.to_i
116
+ else
117
+ result
118
+ end
119
+ end
120
+ end
121
+
122
+ def typecast_sql_result_by_cache_column_type(result)
123
+ type = @owner.column_for_attribute(cache_column).type
124
+ case type
125
+ when :integer
126
+ result.to_i
127
+ when :float
128
+ result.to_f
129
+ when :boolean
130
+ [0,'0', 'NULL', 'nil', 'false', '', 'FALSE', 'False'].include?(result)
131
+ else
132
+ result
133
+ end
134
+ end
135
+
136
+ def interpolate_sql(sql, record = nil)
137
+ @owner.send(:interpolate_sql, sql, record)
138
+ end
139
+
140
+ def sanitize_sql(sql)
141
+ @owner.class.send(:sanitize_sql, sql)
142
+ end
143
+
144
+ end
145
+ end
@@ -0,0 +1,104 @@
1
+ require 'active_record'
2
+ require File.expand_path(File.dirname(__FILE__) + '/cached_value')
3
+
4
+ module CachesValues # :nodoc:
5
+
6
+ def self.included(base)
7
+ unless base.extended_by.include?(CachesValues::ClassMethods)
8
+ base.extend(ClassMethods)
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ # USAGE:
14
+ #
15
+ # a very simple case in which cached_values works just like the .count method on a has_many association:
16
+ #
17
+ # class Company < ActiveRecord::Base
18
+ # caches_value :total_employees, :sql => 'select count(*) from employees where company_id = #{id}'
19
+ # end
20
+ #
21
+ # a more sophisticated example:
22
+ #
23
+ # class User < ActiveRecord::Base
24
+ # has_many :trinkets
25
+ # has_many :sales, :through => :trinkets
26
+ # caches_value :remaining_trinket_sales_allotted, :sql => '... very complicated sql here ...'
27
+ # end
28
+ #
29
+ # user = User.find(:first)
30
+ # user.remaining_trinket_sales_allotted # => 70
31
+ # Trinket.delete_all # <= any operation that would affect our value
32
+ # user.remaining_trinket_sales_allotted # => 70
33
+ # user.remaining_trinket_sales_allotted.reload # => 113
34
+ #
35
+ # You can also calculate the value in Ruby. This can be done by a string to be eval'ed or a Proc. Both are evaluated
36
+ # in the context of the record instance.
37
+ #
38
+ # class User < ActiveRecord::Base
39
+ # caches_value :expensive_calculation, :eval => "some_big_expensize_calculation(self.id)"
40
+ # caches_value :other_expensive_process, :eval => Proc.new {|record| record.other_expensize_process }
41
+ # end
42
+ #
43
+
44
+ def caches_value(name, options = {})
45
+ reflection = create_cached_value_reflection(name, options)
46
+
47
+ configure_dependency_for_cached_value(reflection)
48
+
49
+ reflection.options[:cache] ||= reflection.name unless false == options[:cache]
50
+
51
+ cached_value_accessor_method(reflection, ActiveRecord::CachedValue)
52
+ cached_value_callback_methods(reflection)
53
+ end
54
+
55
+ private
56
+
57
+ def configure_dependency_for_cached_value(reflection)
58
+
59
+ if !reflection.options[:sql] && !reflection.options[:eval]
60
+ raise ArgumentError, "You must specify either the :eval or :sql options for caches_value in #{self.name}"
61
+ end
62
+
63
+ if reflection.options[:sql] && reflection.options[:eval]
64
+ raise ArgumentError, ":eval and :sql are mutually exclusive options. You may specify one or the other for caches_value in #{self.name}"
65
+ end
66
+ end
67
+
68
+ def create_cached_value_reflection(name, options)
69
+ options.assert_valid_keys(:sql, :eval, :cache, :clear, :load, :reload)
70
+
71
+ reflection = ActiveRecord::Reflection::MacroReflection.new(:cached_value, name, options, self)
72
+ write_inheritable_hash :reflections, name => reflection
73
+ reflection
74
+ end
75
+
76
+ def cached_value_accessor_method(reflection, association_proxy_class)
77
+ define_method(reflection.name) do |*params|
78
+ force_reload = params.first unless params.empty?
79
+ association = instance_variable_get("@#{reflection.name}")
80
+
81
+ if association.nil? || force_reload
82
+ association = association_proxy_class.new(self, reflection)
83
+ instance_variable_set("@#{reflection.name}", association)
84
+ force_reload ? association.reload : association.load
85
+ end
86
+ association.target.nil? ? nil : association
87
+ end
88
+ end
89
+
90
+ def cached_value_callback_methods(reflection)
91
+ %w{clear reload}.each do |operation|
92
+ if events = reflection.options[operation.to_sym]
93
+ events = [events] unless events.is_a?(Array)
94
+ events.map! { |event| event.to_s }
95
+ ActiveRecord::Callbacks::CALLBACKS.each do |callback|
96
+ if events.include?(callback)
97
+ send(callback, Proc.new {|record| record.send(reflection.name).send(operation)})
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,9 @@
1
+ require 'active_record'
2
+ require File.expand_path(File.dirname(__FILE__) + "/cached_values/cached_value")
3
+ require File.expand_path(File.dirname(__FILE__) + "/cached_values/caches_value")
4
+
5
+ module CachedValues # :nodoc:
6
+ VERSION = '1.0.0'
7
+ end
8
+
9
+ ActiveRecord::Base.send :include, CachesValues
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :cached_values do
3
+ # # Task goes here
4
+ # end
data/test/database.yml ADDED
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: ":memory:"
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: rails
17
+ :password:
18
+ :database: plugin_test
@@ -0,0 +1,17 @@
1
+ class Leprechaun < ActiveRecord::Base
2
+ caches_value :favorite_color_in_rot_13, :eval => Proc.new {|leprechaun| leprechaun.favorite_color.tr "A-Za-z", "N-ZA-Mn-za-m" }
3
+ caches_value :favorite_color_turned_uppercase, :eval => "favorite_color.upcase"
4
+ caches_value :number_of_gold_coins, :eval => :calculate_gold
5
+ caches_value :id_of_first_leprechaun_with_same_favorite_color, :sql => 'select id from leprechauns where leprechauns.favorite_color = "#{favorite_color}" and leprechauns.id <> #{id} limit 1'
6
+ caches_value :favorite_color_in_rot_13_without_cache, :eval => Proc.new {|leprechaun| leprechaun.favorite_color.tr "A-Za-z", "N-ZA-Mn-za-m" }, :cache => false
7
+ caches_value :favorite_color_turned_uppercase_with_explicit_cache, :eval => "favorite_color.upcase", :cache => 'some_other_cache_field'
8
+ caches_value :reload_callback, :eval => "rand(1000)", :reload => [:before_save, :after_validation]
9
+ caches_value :clear_callback, :eval => "rand(1000)", :clear => :before_validation
10
+ caches_value :float_cast, :sql => "select 82343.222"
11
+ caches_value :integer_cast, :sql => "select 19"
12
+ caches_value :string_cast, :sql => 'select "Top \'o the mornin\' to ya"'
13
+
14
+ def calculate_gold
15
+ '127 gold coins'
16
+ end
17
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,22 @@
1
+
2
+ require File.expand_path(File.dirname(__FILE__) + "/leprechaun")
3
+
4
+ ActiveRecord::Schema.define(:version => 1) do
5
+
6
+ create_table :leprechauns do |t|
7
+ t.column :name, :string
8
+ t.column :favorite_color, :string
9
+ t.column :favorite_color_in_rot_13, :string
10
+ t.column :favorite_color_in_rot_13_without_cache, :string
11
+ t.column :favorite_color_turned_uppercase, :string
12
+ t.column :id_of_first_leprechaun_with_same_favorite_color, :integer
13
+ t.column :some_other_cache_field, :string
14
+ t.column :reload_callback, :float
15
+ t.column :clear_callback, :float
16
+ end
17
+
18
+ Leprechaun.create!(:name => 'Mc Nairn', :favorite_color => 'blue')
19
+ Leprechaun.create!(:name => "O' Houhlihan", :favorite_color => 'ochre')
20
+ Leprechaun.create!(:name => "Danger Cáinte", :favorite_color => 'blue')
21
+
22
+ end
@@ -0,0 +1,118 @@
1
+ require 'test/unit'
2
+ require File.expand_path(File.dirname(__FILE__) + "/test_helper")
3
+
4
+ class CachedValuesTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @mc_nairn = Leprechaun.find(:first)
8
+ @mc_nairn.favorite_color_in_rot_13.clear
9
+ @mc_nairn.favorite_color_turned_uppercase.clear
10
+ @mc_nairn.id_of_first_leprechaun_with_same_favorite_color.clear
11
+ @mc_nairn.favorite_color_in_rot_13_without_cache.clear
12
+ @mc_nairn.favorite_color_turned_uppercase_with_explicit_cache.clear
13
+ @mc_nairn.favorite_color = 'blue'
14
+ @mc_nairn.save!
15
+ end
16
+
17
+ def test_proc_should_properly_calculate_value
18
+ assert_equal 'blue', @mc_nairn.favorite_color
19
+ assert_equal 'oyhr', @mc_nairn.favorite_color.tr("A-Za-z", "N-ZA-Mn-za-m")
20
+ assert_equal 'oyhr', @mc_nairn.favorite_color_in_rot_13
21
+ end
22
+
23
+ def test_string_should_properly_calculate_value
24
+ assert_equal 'blue', @mc_nairn.favorite_color
25
+ assert_equal 'BLUE', @mc_nairn.favorite_color_turned_uppercase
26
+ @mc_nairn.update_attribute(:favorite_color, 'gold')
27
+ assert_equal 'BLUE', @mc_nairn.favorite_color_turned_uppercase
28
+ assert_equal 'GOLD', @mc_nairn.favorite_color_turned_uppercase.reload
29
+ end
30
+
31
+ def test_symbol_should_calculate_value_from_method_call
32
+ assert_equal '127 gold coins', @mc_nairn.number_of_gold_coins
33
+ assert_equal '127 gold coins', @mc_nairn.calculate_gold
34
+ @mc_nairn.class.class_eval { def calculate_gold; '255 gold coins'; end }
35
+ assert_equal '255 gold coins', @mc_nairn.calculate_gold
36
+ assert_equal '127 gold coins', @mc_nairn.number_of_gold_coins
37
+ assert_equal '255 gold coins', @mc_nairn.number_of_gold_coins.reload
38
+ end
39
+
40
+ def test_sql_should_properly_calculate_value
41
+ assert_equal 3, @mc_nairn.id_of_first_leprechaun_with_same_favorite_color
42
+ Leprechaun.find_by_name("O' Houhlihan").update_attribute(:favorite_color, 'blue')
43
+ assert_equal 3, @mc_nairn.id_of_first_leprechaun_with_same_favorite_color
44
+ assert_equal 2, @mc_nairn.id_of_first_leprechaun_with_same_favorite_color.reload
45
+ end
46
+
47
+ def test_should_cache_value
48
+ assert_equal 'blue', @mc_nairn.favorite_color
49
+ assert_equal 'oyhr', @mc_nairn.favorite_color_in_rot_13
50
+ @mc_nairn.update_attribute(:favorite_color, 'red')
51
+ assert_equal 'erq', @mc_nairn.favorite_color.tr("A-Za-z", "N-ZA-Mn-za-m")
52
+ assert_equal 'oyhr', @mc_nairn.favorite_color_in_rot_13
53
+ end
54
+
55
+ def test_cache_should_be_invalidated_on_clear
56
+ assert_equal 'blue', @mc_nairn.favorite_color
57
+ assert_equal 'oyhr', @mc_nairn.favorite_color_in_rot_13
58
+ @mc_nairn.favorite_color_in_rot_13.clear
59
+ assert_nil @mc_nairn.send(:read_attribute, :favorite_color_in_rot_13)
60
+ end
61
+
62
+ def test_value_should_be_updated_after_its_cleared
63
+ assert_equal 'blue', @mc_nairn.favorite_color
64
+ assert_equal 'oyhr', @mc_nairn.favorite_color_in_rot_13
65
+ @mc_nairn.update_attribute(:favorite_color, 'red')
66
+ assert_equal 'oyhr', @mc_nairn.favorite_color_in_rot_13
67
+ @mc_nairn.favorite_color_in_rot_13.clear
68
+ assert_equal 'erq', @mc_nairn.favorite_color_in_rot_13
69
+ end
70
+
71
+ def test_should_not_cache_explicitly_noncaching_values
72
+ assert_equal 'blue', @mc_nairn.favorite_color
73
+ assert_equal 'oyhr', @mc_nairn.favorite_color_in_rot_13_without_cache
74
+ assert_nil @mc_nairn.send(:read_attribute, :favorite_color_in_rot_13_without_cache)
75
+ @mc_nairn.update_attribute(:favorite_color, 'red')
76
+ assert_equal 'erq', @mc_nairn.favorite_color.tr("A-Za-z", "N-ZA-Mn-za-m")
77
+ assert_equal 'erq', @mc_nairn.favorite_color_in_rot_13_without_cache.reload
78
+ assert_nil @mc_nairn.send(:read_attribute, :favorite_color_in_rot_13_without_cache)
79
+ end
80
+
81
+ def test_should_respect_explicit_cache_column
82
+ assert_equal 'BLUE', @mc_nairn.favorite_color_turned_uppercase_with_explicit_cache
83
+ assert_equal 'BLUE', @mc_nairn.send(:read_attribute, :some_other_cache_field)
84
+ @mc_nairn.update_attribute(:favorite_color, 'red')
85
+ assert_equal 'BLUE', @mc_nairn.send(:read_attribute, :some_other_cache_field)
86
+ assert_equal 'RED', @mc_nairn.favorite_color_turned_uppercase_with_explicit_cache.reload
87
+ end
88
+
89
+ def test_reload_callback_should_fire
90
+ value = @mc_nairn.reload_callback.to_s
91
+ assert_equal value.to_i, @mc_nairn.reload_callback
92
+ @mc_nairn.save!
93
+ assert_not_equal value.to_i, @mc_nairn.reload_callback.reload
94
+ value = @mc_nairn.reload_callback.to_s
95
+ assert_equal value.to_i, @mc_nairn.reload_callback
96
+ @mc_nairn.valid?
97
+ assert_not_equal value.to_i, @mc_nairn.reload_callback
98
+ end
99
+
100
+ def test_clear_callback_should_fire
101
+ assert @mc_nairn.clear_callback
102
+ assert @mc_nairn.instance_variable_get("@clear_callback")
103
+ @mc_nairn.valid?
104
+ assert_nil @mc_nairn.instance_variable_get("@clear_callback")
105
+ end
106
+
107
+ def test_sql_should_cast_to_integer
108
+ assert @mc_nairn.integer_cast.is_a?(Fixnum)
109
+ end
110
+
111
+ def test_sql_should_cast_to_string
112
+ assert @mc_nairn.string_cast.is_a?(String)
113
+ end
114
+
115
+ def test_sql_should_cast_to_float
116
+ assert @mc_nairn.float_cast.is_a?(Float)
117
+ end
118
+ end
@@ -0,0 +1,36 @@
1
+ # Include this file in your test by copying the following line to your test:
2
+ # require File.expand_path(File.dirname(__FILE__) + "/test_helper")
3
+
4
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
5
+
6
+ require 'rubygems'
7
+ require 'test/unit'
8
+ require 'active_record'
9
+ require 'active_record/fixtures'
10
+ require "cached_values"
11
+ require File.expand_path(File.dirname(__FILE__) + "/leprechaun")
12
+
13
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
14
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
15
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3'])
16
+
17
+ load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
18
+
19
+ class Test::Unit::TestCase #:nodoc:
20
+
21
+ # def create_fixtures(*table_names)
22
+ # if block_given?
23
+ # Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
24
+ # else
25
+ # Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
26
+ # end
27
+ # end
28
+
29
+ # Turn off transactional fixtures if you're working with MyISAM tables in MySQL
30
+ self.use_transactional_fixtures = true
31
+
32
+ # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
33
+ self.use_instantiated_fixtures = false
34
+
35
+ # Add more helper methods to be used by all tests here...
36
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cached_values
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jack Danger Canty
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-07 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.5.1
23
+ version:
24
+ description: ""
25
+ email:
26
+ - rubygems_cached_values@6brand.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ files:
36
+ - History.txt
37
+ - MIT-LICENSE
38
+ - Manifest.txt
39
+ - README.txt
40
+ - Rakefile
41
+ - init.rb
42
+ - install.rb
43
+ - lib/cached_values.rb
44
+ - lib/cached_values/cached_value.rb
45
+ - lib/cached_values/caches_value.rb
46
+ - tasks/cached_values_tasks.rake
47
+ - test/database.yml
48
+ - test/leprechaun.rb
49
+ - test/schema.rb
50
+ - test/test_cached_values.rb
51
+ - test/test_helper.rb
52
+ - uninstall.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/JackDanger/cached_values/
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --main
58
+ - README.txt
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ requirements: []
74
+
75
+ rubyforge_project: cachedvalues
76
+ rubygems_version: 1.0.1
77
+ signing_key:
78
+ specification_version: 2
79
+ summary: ""
80
+ test_files:
81
+ - test/test_cached_values.rb
82
+ - test/test_helper.rb