acts_as_comparable 1.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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ # Copyright (c) 2007 Mark Van Holstyn, Zach Dennis
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,25 @@
1
+ acts_as_comparable
2
+ -------------------
3
+
4
+ acts_as_comparable allows you to compare ActiveRecord models.
5
+ To test or build documentation see the rake tasks available.
6
+ rake -T
7
+
8
+
9
+ TESTING
10
+ -------
11
+ Testing acts_as_comparable relies on:
12
+ * ActiveRecord (any version, tested up to 1.15.3)
13
+ * Mocha 0.4.0 or higher (tested with 0.4.0)
14
+ * Ruby 1.8.4, 1.8.5 or 1.8.6
15
+
16
+ SVN
17
+ ----
18
+ Public anonymous read svn:
19
+ http://rails.lotswholetime.com/svn/acts_as_comparable/trunk
20
+
21
+ AUTHORS
22
+ -------
23
+ * Mark Van Holstyn - http://www.lotswholetime.com
24
+ * Zach Dennis - http://www.continuousthinking.com
25
+
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc "Default Task"
6
+ task :default => :test
7
+
8
+ desc "Test acts_as_comparable"
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc "Generate documentation for acts_as_comparable"
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = "rdoc"
18
+ rdoc.title = "acts_as_comparable"
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join( File.dirname( __FILE__ ), 'lib', 'acts_as_comparable' )
@@ -0,0 +1,170 @@
1
+ # == acts_as_comparable
2
+ # acts_as_comparable provides comparison to ActiveRecord models.
3
+ # It allows you to capture what fields are different, as well as
4
+ # easy access to those diferrent values.
5
+ #
6
+ # class MyModel < ActiveRecord::Base
7
+ # acts_as_comparable
8
+ # end
9
+ #
10
+ #
11
+ # == EXAMPLES
12
+ #
13
+ # # default options which treats all fields as comparable
14
+ # class Person < ActiveRecord::Base
15
+ # acts_as_comparable
16
+ # end
17
+ #
18
+ # # specifying which fields that should act as comparable
19
+ # class Person < ActiveRecord::Base
20
+ # acts_as_comparable :only => [ :first_name, :last_name, :age ]
21
+ # end
22
+ #
23
+ #
24
+ # # specifying which fields shouldn't act as comparable
25
+ # class Person < ActiveRecord::Base
26
+ # acts_as_comparable :except => [ :eyecolor ]
27
+ # end
28
+ #
29
+ #
30
+ # # specifying fields which compare to another field on the same model
31
+ # class Account < ActiveRecord::Base
32
+ # acts_as_comparable :attrs_map => { :accountno => :parent_accountno }
33
+ # end
34
+ #
35
+ # See unit tests for more usage examples.
36
+ #
37
+ # == AUTHORS
38
+ # * Mark Van Holstyn http://www.lotswholetime.com
39
+ # * Zach Dennis http://www.continuousthinking.com
40
+ #
41
+ module ActiveRecord::Acts::Comparable
42
+ def self.included( base )
43
+ base.extend ClassMethods
44
+ end
45
+
46
+ module ClassMethods
47
+
48
+ # Sets up the current model to be comparable against other models or instances.
49
+ #
50
+ # == Options
51
+ # * :only - an array of fields as symbols which should be held onto for comparison
52
+ # * :except - an array of fields as symbols which should not be held onto for comparison
53
+ # * :attrs_map - a hash of field to field mappings as symbols which define how fields should be compared
54
+ def acts_as_comparable( options = {} )
55
+ #pullin in necessary methods
56
+ cattr_accessor :comparable_attributes, :comparable_options
57
+ include ActiveRecord::Acts::Comparable::InstanceMethods
58
+
59
+ #setup options
60
+ self.comparable_options = options
61
+ self.comparable_attributes = comparable_options_to_attributes_hash options
62
+ end
63
+
64
+ private
65
+
66
+ def comparable_options_to_attributes_hash( options )
67
+ #setup attributes
68
+ attrs = {}
69
+
70
+ if options[:only]
71
+ options[:only].to_a.each { |attr| attrs[attr.to_sym] = attr.to_sym }
72
+ else
73
+ self.column_names.each { |attr| attrs[attr.to_sym] = attr.to_sym }
74
+ end
75
+
76
+ if options[:attrs_map]
77
+ options[:attrs_map].each_pair do |attr,action|
78
+ attrs[attr.to_sym] = action
79
+ end
80
+ end
81
+
82
+ if options[:except]
83
+ options[:except].to_a.each { |attr| attrs.delete attr.to_sym }
84
+ end
85
+
86
+ attrs
87
+ end
88
+ end
89
+
90
+ module InstanceMethods
91
+
92
+ # Returns true if the passed in +other+ model is different then this
93
+ # model given the fields that are marked as comparable. Otherwise
94
+ # returns false.
95
+ #
96
+ # == Arguments
97
+ # * other - another ActiveRecord model to compare this model against
98
+ # * options - a hash of options. All options for ActiveRecord::Acts::Comparable::ClassMethods.acts_as_comparable apply.
99
+ #
100
+ def different?( other = nil, options = nil )
101
+ other ||= self.new_record? ? self.class.new : self.class.find( self.id )
102
+ comparable_attributes_for( options ).each_pair do |attr, action|
103
+ if action.is_a? Proc
104
+ return true unless action.call( self ) == action.call( other )
105
+ else
106
+ return true unless self.send( attr ) == other.send( attr )
107
+ end
108
+ end
109
+ false
110
+ end
111
+
112
+ # Returns true if the passed in +other+ model is comparable to this
113
+ # model given the fields that are marked as comparable. Otherwise
114
+ # returns false.
115
+ #
116
+ # == Arguments
117
+ # * other - another ActiveRecord model to compare this model against
118
+ # * options - a hash of options. All options for ActiveRecord::Acts::Comparable::ClassMethods.acts_as_comparable apply.
119
+ #
120
+ def same?( other = nil, options = nil )
121
+ not different?( other, options )
122
+ end
123
+
124
+ # Returns a hash of field to value mappings which signify the differences between
125
+ # this model object and the passed in +other+ model object given an optional
126
+ # set of options. Returns an empty hash if there are no comparable differences.
127
+ #
128
+ # The value of the field to value mappings is an array of the values that differ.
129
+ #
130
+ # == Arguments
131
+ # * other - another ActiveRecord model to compare this model against
132
+ # * options - a hash of options. All options for ActiveRecord::Acts::Comparable::ClassMethods.acts_as_comparable apply.
133
+ #
134
+ # == Example
135
+ #
136
+ # class Pet < ActiveRecord::Base ; end
137
+ #
138
+ # pet1 = Pet.new :id=>1, :name=>"dog", :value=>"Tiny"
139
+ # pet2 = Pet.new :id=>5, :name=>"cat", :value=>"Norm"
140
+ #
141
+ # differences = pet1.differences(pet2)
142
+ # # => {:value=>["Tiny", "Norm"], :name=>["dog", "cat"], :id=>[1, 5]}
143
+ #
144
+ def differences( other = nil, options = nil )
145
+ other ||= self.new_record? ? self.class.new : self.class.find( self.id )
146
+ diffs = {}
147
+ comparable_attributes_for( options ).each_pair do |attr, action|
148
+ unless self.send( attr ) == other.send( attr )
149
+ if action.is_a? Proc
150
+ diffs[attr] = [ action.call( self ), action.call( other ) ]
151
+ else
152
+ diffs[attr] = [ self.send( attr ), other.send( attr ) ]
153
+ end
154
+ end
155
+ end
156
+ diffs.symbolize_keys
157
+ end
158
+
159
+ # Returns an hash of comparable attribute mappings given the passed in options.
160
+ #
161
+ # == Arguments
162
+ # * options - a hash of options. All options for ActiveRecord::Acts::Comparable::ClassMethods.acts_as_comparable apply.
163
+ def comparable_attributes_for( options )
164
+ attrs = options ? self.class.send( :comparable_options_to_attributes_hash, options ) : self.class.comparable_attributes
165
+ end
166
+ end
167
+
168
+ end
169
+
170
+ ActiveRecord::Base.send( :include, ActiveRecord::Acts::Comparable )
@@ -0,0 +1,136 @@
1
+ require File.join( File.dirname( __FILE__ ), "test_helper")
2
+
3
+ class ActsAsComparableTest < Test::Unit::TestCase
4
+
5
+ def test_models_are_different_when_both_records_are_new
6
+ model1 = MockModel.new :name=>"dog"
7
+ model2 = MockModel.new :name=>"cat"
8
+
9
+ assert model1.different?(model2), "models should have been different!"
10
+ assert !model1.same?(model2), "models shouldn't have been the same!"
11
+ end
12
+
13
+ def test_models_are_different_when_one_records_is_new
14
+ model1 = MockModel.new :name=>"dog"
15
+ model1.instance_variable_set "@new_record", false
16
+
17
+ model2 = MockModel.new :name=>"cat"
18
+
19
+ assert model1.different?(model2), "models should have been different!"
20
+ assert !model1.same?(model2), "models shouldn't have been the same!"
21
+ end
22
+
23
+ def test_models_are_different_when_neither_record_is_new
24
+ model1 = MockModel.new :name=>"dog"
25
+ model1.instance_variable_set "@new_record", false
26
+
27
+ model2 = MockModel.new :name=>"cat"
28
+ model2.instance_variable_set "@new_record", false
29
+
30
+ assert model1.different?(model2), "models should have been different!"
31
+ assert !model1.same?(model2), "models shouldn't have been the same!"
32
+ end
33
+
34
+ def test_models_are_not_different_when_both_records_are_new
35
+ model1 = MockModel.new :name=>"cat"
36
+ model2 = MockModel.new :name=>"cat"
37
+
38
+ assert model1.same?(model2), "models should have been the same!"
39
+ assert !model1.different?(model2), "models shouldn't have been different!"
40
+ end
41
+
42
+ def test_models_are_not_different_when_one_record_is_new
43
+ model1 = MockModel.new :name=>"cat"
44
+ model1.instance_variable_set "@new_record", false
45
+
46
+ model2 = MockModel.new :name=>"cat"
47
+
48
+ assert model1.same?(model2), "models should have been the same!"
49
+ assert !model1.different?(model2), "models shouldn't have been different!"
50
+ end
51
+
52
+ def test_models_are_not_different_when_neither_record_is_new
53
+ model1 = MockModel.new :name=>"cat"
54
+ model1.instance_variable_set "@new_record", false
55
+
56
+ model2 = MockModel.new :name=>"cat"
57
+ model2.instance_variable_set "@new_record", false
58
+
59
+ assert model1.same?(model2), "models should have been the same!"
60
+ assert !model1.different?(model2), "models shouldn't have been different!"
61
+ end
62
+
63
+ def test_differences_with_new_records
64
+ model1 = MockModel.new :id=>nil, :name=>"dog", :value=>"Tiny"
65
+ model2 = MockModel.new :id=>nil, :name=>"cat", :value=>"Norm"
66
+ model1.instance_variable_set "@new_record", false
67
+
68
+ differences = model1.differences(model2)
69
+
70
+ assert differences[:name] == [ "dog", "cat" ], "Name was expected to be different!"
71
+ assert differences[:value] == [ "Tiny", "Norm" ], "Value was expected to be different!"
72
+ assert 2 == differences.size, "Wrong number of differences!"
73
+ end
74
+
75
+ def test_differences_with_one_new_record
76
+ model1 = MockModel.new :id=>nil, :name=>"dog", :value=>"Tiny"
77
+ model2 = MockModel.new :id=>5, :name=>"cat", :value=>"Norm"
78
+ model2.instance_variable_set "@new_record", false
79
+
80
+ differences = model1.differences(model2)
81
+
82
+ assert differences[:id] == [ nil, 5 ], "ID was expected to be different!"
83
+ assert differences[:name] == [ "dog", "cat" ], "Name was expected to be different!"
84
+ assert differences[:value] == [ "Tiny", "Norm" ], "Value was expected to be different!"
85
+ assert 3 == differences.size, "Wrong number of differences!"
86
+ end
87
+
88
+ def test_differences_with_existing_records
89
+ model1 = MockModel.new :id=>1, :name=>"dog", :value=>"Tiny"
90
+ model1.instance_variable_set "@new_record", false
91
+
92
+ model2 = MockModel.new :id=>5, :name=>"cat", :value=>"Norm"
93
+ model1.instance_variable_set "@new_record", false
94
+
95
+ differences = model1.differences(model2)
96
+
97
+ assert differences[:id] == [ 1, 5 ], "ID was expected to be different!"
98
+ assert differences[:name] == [ "dog", "cat" ], "Name was expected to be different!"
99
+ assert differences[:value] == [ "Tiny", "Norm" ], "Value was expected to be different!"
100
+ assert 3 == differences.size, "Wrong number of differences!"
101
+ end
102
+
103
+ def test_comparable_attributes_for_without_options
104
+ comparable_attributes = MockModel.new.comparable_attributes_for( {} )
105
+ expected_comparable_attributes = { :id=>:id, :name=>:name, :value=>:value }
106
+
107
+ assert expected_comparable_attributes == comparable_attributes, "Expected attributes were not comparable!"
108
+ end
109
+
110
+ def test_comparable_attributes_for_with_only_option
111
+ comparable_attributes = MockModel.new.comparable_attributes_for(
112
+ :only=>[:value]
113
+ )
114
+ expected_comparable_attributes = { :value=>:value }
115
+
116
+ assert expected_comparable_attributes == comparable_attributes, "Expected attributes were not comparable!"
117
+ end
118
+
119
+ def test_comparable_attributes_for_with_except_option
120
+ comparable_attributes = MockModel.new.comparable_attributes_for(
121
+ :except=>[:value]
122
+ )
123
+ expected_comparable_attributes = { :id=>:id, :name=>:name }
124
+
125
+ assert expected_comparable_attributes == comparable_attributes, "Expected attributes were not comparable!"
126
+ end
127
+
128
+ def test_comparable_attributes_for_with_attrs_map_option
129
+ comparable_attributes = MockModel.new.comparable_attributes_for(
130
+ :attrs_map=> {:name=>:value, :value=>:id}
131
+ )
132
+ expected_comparable_attributes = { :id=>:id, :name=>:value, :value=>:id }
133
+ assert expected_comparable_attributes == comparable_attributes, "Expected attributes were not comparable!"
134
+ end
135
+
136
+ end
@@ -0,0 +1,33 @@
1
+ unless Object.const_defined?( :ActiveRecord )
2
+ begin
3
+ require 'active_record'
4
+ rescue LoadError => ex
5
+ require 'rubygems'
6
+ require 'active_record'
7
+ end
8
+ end
9
+
10
+ require File.join( File.dirname( __FILE__ ), '..', 'init' )
11
+ require 'test/unit'
12
+ require 'mocha'
13
+
14
+ ###### SETUP a partially mocked out Model for testing #######
15
+
16
+ class MockModel < ActiveRecord::Base
17
+ class << self
18
+ def column_names
19
+ %w[ id name value ]
20
+ end
21
+ end
22
+
23
+ acts_as_comparable
24
+
25
+ def initialize( attributes_hsh={} )
26
+ @attributes = { :id=>nil, :name=>"", :value=>"" }.merge( attributes_hsh )
27
+ @new_record = true
28
+
29
+ @attributes.keys.each do |column_name|
30
+ self.class.send( :define_method, column_name ) { @attributes[column_name] }
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: acts_as_comparable
5
+ version: !ruby/object:Gem::Version
6
+ version: "1.0"
7
+ date: 2007-04-20 00:00:00 -04:00
8
+ summary: Adds ActiveRecord model comparison functionality.
9
+ require_paths:
10
+ - lib
11
+ email: mvette13@gmail.com zach.dennis@gmail.com
12
+ homepage: http://www.continuousthinking.com/tags/acts_as_comparable
13
+ rubyforge_project: arext
14
+ description: Adds ActiveRecord model comparison functionality.
15
+ autorequire: acts_as_comparable.rb
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Mark Van Holstyn
31
+ - Zach Dennis
32
+ files:
33
+ - init.rb
34
+ - Rakefile
35
+ - LICENSE
36
+ - README
37
+ - lib/acts_as_comparable.rb
38
+ - test/acts_as_comparable_test.rb
39
+ - test/test_helper.rb
40
+ test_files: []
41
+
42
+ rdoc_options:
43
+ - --main
44
+ - README
45
+ extra_rdoc_files:
46
+ - README
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ requirements: []
52
+
53
+ dependencies:
54
+ - !ruby/object:Gem::Dependency
55
+ name: activerecord
56
+ version_requirement:
57
+ version_requirements: !ruby/object:Gem::Version::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.14.1
62
+ version: