delta_changes 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/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - ree
3
+ - 1.9.2
4
+ - 1.9.3
data/Appraisals ADDED
@@ -0,0 +1,15 @@
1
+ appraise "rails2" do
2
+ version = "2.3.14"
3
+ gem 'activerecord', version
4
+ end
5
+
6
+ appraise "rails30" do
7
+ version = "3.2.3"
8
+ gem 'activerecord', version
9
+ end
10
+
11
+
12
+ appraise "rails32" do
13
+ version = "3.2.3"
14
+ gem 'activerecord', version
15
+ end
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem "appraisal"
5
+ gem "rake"
6
+ gem "rspec", "~>2"
7
+ gem "sqlite3"
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ delta_changes (0.0.1)
5
+ activerecord
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activemodel (3.2.8)
11
+ activesupport (= 3.2.8)
12
+ builder (~> 3.0.0)
13
+ activerecord (3.2.8)
14
+ activemodel (= 3.2.8)
15
+ activesupport (= 3.2.8)
16
+ arel (~> 3.0.2)
17
+ tzinfo (~> 0.3.29)
18
+ activesupport (3.2.8)
19
+ i18n (~> 0.6)
20
+ multi_json (~> 1.0)
21
+ appraisal (0.4.1)
22
+ bundler
23
+ rake
24
+ arel (3.0.2)
25
+ builder (3.0.3)
26
+ diff-lcs (1.1.3)
27
+ i18n (0.6.1)
28
+ multi_json (1.3.6)
29
+ rake (0.9.2)
30
+ rspec (2.6.0)
31
+ rspec-core (~> 2.6.0)
32
+ rspec-expectations (~> 2.6.0)
33
+ rspec-mocks (~> 2.6.0)
34
+ rspec-core (2.6.4)
35
+ rspec-expectations (2.6.0)
36
+ diff-lcs (~> 1.1.2)
37
+ rspec-mocks (2.6.0)
38
+ sqlite3 (1.3.6)
39
+ tzinfo (0.3.33)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ appraisal
46
+ delta_changes!
47
+ rake
48
+ rspec (~> 2)
49
+ sqlite3
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require "bundler/gem_tasks"
2
+ require "appraisal"
3
+
4
+ task :spec do
5
+ sh "rspec spec/"
6
+ end
7
+
8
+ task :default do
9
+ sh "bundle exec rake appraisal:install && bundle exec rake appraisal spec"
10
+ end
11
+
12
+ # extracted from https://github.com/grosser/project_template
13
+ rule /^version:bump:.*/ do |t|
14
+ file = "lib/delta_changes/version.rb"
15
+
16
+ sh "git status | grep 'nothing to commit'" # ensure we are not dirty
17
+ index = ["major", "minor", "patch"].index(t.name.split(':').last)
18
+ version_file = File.read(file)
19
+ old_version, *version_parts = version_file.match(/(\d+)\.(\d+)\.(\d+)/).to_a
20
+ version_parts[index] = version_parts[index].to_i + 1
21
+ version_parts[2] = 0 if index < 2 # remove patch for minor
22
+ version_parts[1] = 0 if index < 1 # remove minor for major
23
+ new_version = version_parts * '.'
24
+
25
+ File.open(file,"w"){|f| f.write(version_file.sub(old_version, new_version)) }
26
+ sh "bundle && git add #{file} Gemfile.lock && git commit -m 'bump version to #{new_version}'"
27
+ end
data/Readme.md ADDED
@@ -0,0 +1,34 @@
1
+ Additional real/virtual attribute change tracking independent of ActiveRecords
2
+
3
+
4
+ Install
5
+ =======
6
+
7
+ gem install delta_changes
8
+
9
+ Usage
10
+ =====
11
+
12
+ class User < ActiveRecord::Base
13
+ include DeltaChanges::Extension
14
+ delta_changes :columns => [:name], :attributes => [:full_name]
15
+ end
16
+
17
+ user.name = "bar"
18
+ user.delta_changes # => {"name" => [nil, "bar"]}
19
+
20
+ user.full_name_will_change!
21
+ user.delta_changes # => {"name" => [nil, "bar"], "full_name" => [nil, "Mr. Bar"]}
22
+
23
+ user.save!
24
+ user.delta_changes # => {"name" => [nil, "bar"], "full_name" => [nil, "Mr. Bar"]}
25
+
26
+ user.reset_delta_changes!
27
+ user.delta_changes # => {}
28
+
29
+ Author
30
+ ======
31
+ [Michael Grosser](http://grosser.it)<br/>
32
+ michael@grosser.it<br/>
33
+ License: MIT<br/>
34
+ [![Build Status](https://secure.travis-ci.org/grosser/delta_changes.png)](http://travis-ci.org/grosser/delta_changes)
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+ name = "delta_changes"
3
+ require "#{name}/version"
4
+
5
+ Gem::Specification.new name, DeltaChanges::VERSION do |s|
6
+ s.summary = "Additional real/virtual attribute change tracking independent of ActiveRecords"
7
+ s.authors = ["Michael Grosser"]
8
+ s.email = "michael@grosser.it"
9
+ s.homepage = "http://github.com/grosser/#{name}"
10
+ s.files = `git ls-files`.split("\n")
11
+ s.add_runtime_dependency "activerecord"
12
+ s.license = "MIT"
13
+ end
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source :rubygems
4
+
5
+ gem "appraisal"
6
+ gem "rake"
7
+ gem "rspec", "~>2"
8
+ gem "sqlite3"
9
+ gem "activerecord", "2.3.14"
10
+
11
+ gemspec :path=>"../"
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: /Users/mgrosser/code/tools/delta_changes
3
+ specs:
4
+ delta_changes (0.0.0)
5
+ activerecord
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activerecord (2.3.14)
11
+ activesupport (= 2.3.14)
12
+ activesupport (2.3.14)
13
+ appraisal (0.4.1)
14
+ bundler
15
+ rake
16
+ diff-lcs (1.1.3)
17
+ rake (0.9.2.2)
18
+ rspec (2.11.0)
19
+ rspec-core (~> 2.11.0)
20
+ rspec-expectations (~> 2.11.0)
21
+ rspec-mocks (~> 2.11.0)
22
+ rspec-core (2.11.1)
23
+ rspec-expectations (2.11.3)
24
+ diff-lcs (~> 1.1.3)
25
+ rspec-mocks (2.11.2)
26
+ sqlite3 (1.3.6)
27
+
28
+ PLATFORMS
29
+ ruby
30
+
31
+ DEPENDENCIES
32
+ activerecord (= 2.3.14)
33
+ appraisal
34
+ delta_changes!
35
+ rake
36
+ rspec (~> 2)
37
+ sqlite3
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source :rubygems
4
+
5
+ gem "appraisal"
6
+ gem "rake"
7
+ gem "rspec", "~>2"
8
+ gem "sqlite3"
9
+ gem "activerecord", "3.2.3"
10
+
11
+ gemspec :path=>"../"
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: /Users/mgrosser/code/tools/delta_changes
3
+ specs:
4
+ delta_changes (0.0.0)
5
+ activerecord
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activemodel (3.2.3)
11
+ activesupport (= 3.2.3)
12
+ builder (~> 3.0.0)
13
+ activerecord (3.2.3)
14
+ activemodel (= 3.2.3)
15
+ activesupport (= 3.2.3)
16
+ arel (~> 3.0.2)
17
+ tzinfo (~> 0.3.29)
18
+ activesupport (3.2.3)
19
+ i18n (~> 0.6)
20
+ multi_json (~> 1.0)
21
+ appraisal (0.4.1)
22
+ bundler
23
+ rake
24
+ arel (3.0.2)
25
+ builder (3.0.3)
26
+ diff-lcs (1.1.3)
27
+ i18n (0.6.1)
28
+ multi_json (1.3.6)
29
+ rake (0.9.2.2)
30
+ rspec (2.11.0)
31
+ rspec-core (~> 2.11.0)
32
+ rspec-expectations (~> 2.11.0)
33
+ rspec-mocks (~> 2.11.0)
34
+ rspec-core (2.11.1)
35
+ rspec-expectations (2.11.3)
36
+ diff-lcs (~> 1.1.3)
37
+ rspec-mocks (2.11.2)
38
+ sqlite3 (1.3.6)
39
+ tzinfo (0.3.33)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ activerecord (= 3.2.3)
46
+ appraisal
47
+ delta_changes!
48
+ rake
49
+ rspec (~> 2)
50
+ sqlite3
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source :rubygems
4
+
5
+ gem "appraisal"
6
+ gem "rake"
7
+ gem "rspec", "~>2"
8
+ gem "sqlite3"
9
+ gem "activerecord", "3.2.3"
10
+
11
+ gemspec :path=>"../"
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: /Users/mgrosser/code/tools/delta_changes
3
+ specs:
4
+ delta_changes (0.0.0)
5
+ activerecord
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activemodel (3.2.3)
11
+ activesupport (= 3.2.3)
12
+ builder (~> 3.0.0)
13
+ activerecord (3.2.3)
14
+ activemodel (= 3.2.3)
15
+ activesupport (= 3.2.3)
16
+ arel (~> 3.0.2)
17
+ tzinfo (~> 0.3.29)
18
+ activesupport (3.2.3)
19
+ i18n (~> 0.6)
20
+ multi_json (~> 1.0)
21
+ appraisal (0.4.1)
22
+ bundler
23
+ rake
24
+ arel (3.0.2)
25
+ builder (3.0.3)
26
+ diff-lcs (1.1.3)
27
+ i18n (0.6.1)
28
+ multi_json (1.3.6)
29
+ rake (0.9.2.2)
30
+ rspec (2.11.0)
31
+ rspec-core (~> 2.11.0)
32
+ rspec-expectations (~> 2.11.0)
33
+ rspec-mocks (~> 2.11.0)
34
+ rspec-core (2.11.1)
35
+ rspec-expectations (2.11.3)
36
+ diff-lcs (~> 1.1.3)
37
+ rspec-mocks (2.11.2)
38
+ sqlite3 (1.3.6)
39
+ tzinfo (0.3.33)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ activerecord (= 3.2.3)
46
+ appraisal
47
+ delta_changes!
48
+ rake
49
+ rspec (~> 2)
50
+ sqlite3
@@ -0,0 +1,3 @@
1
+ module DeltaChanges
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,109 @@
1
+ require "delta_changes/version"
2
+
3
+ module DeltaChanges
4
+ module Extension
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ base.cattr_accessor :delta_changes_options
8
+ base.attribute_method_suffix '_delta_changed?', '_delta_change', '_delta_was', '_delta_will_change!'
9
+ base.alias_method_chain :write_attribute, :delta_changes
10
+ end
11
+
12
+ module ClassMethods
13
+ def delta_changes(options)
14
+ self.delta_changes_options = options
15
+ define_virtual_attribute_delta_methods
16
+ end
17
+
18
+ #
19
+ # Provide for delta tracking of virtual (non-column) attributes.
20
+ #
21
+ def define_virtual_attribute_delta_methods
22
+ delta_changes_options[:attributes].each do |tracked_attribute|
23
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
24
+ def #{tracked_attribute}_delta_changed?
25
+ attribute_delta_changed?('#{tracked_attribute}')
26
+ end
27
+
28
+ def #{tracked_attribute}_delta_change
29
+ attribute_delta_change('#{tracked_attribute}')
30
+ end
31
+
32
+ def #{tracked_attribute}_delta_was
33
+ attribute_delta_was('#{tracked_attribute}')
34
+ end
35
+
36
+ def #{tracked_attribute}_delta_will_change!
37
+ attribute_delta_will_change!('#{tracked_attribute}')
38
+ end
39
+ RUBY
40
+ end
41
+ end
42
+ end
43
+
44
+ def delta_changes
45
+ delta_changed_attributes.keys.inject({}) { |h, attr| h[attr] = attribute_delta_change(attr); h }
46
+ end
47
+
48
+ def delta_changes?
49
+ delta_changed_attributes.keys.present?
50
+ end
51
+
52
+ ####################################
53
+
54
+ def reset_delta_changes!
55
+ delta_changed_attributes.clear
56
+ end
57
+
58
+ private
59
+
60
+ # Map of change attr => original value.
61
+ def delta_changed_attributes
62
+ @delta_changed_attributes ||= {}
63
+ end
64
+
65
+ # Handle *_delta_changed? for method_missing.
66
+ def attribute_delta_changed?(attr)
67
+ delta_changed_attributes.include?(attr)
68
+ end
69
+
70
+ # Handle *_delta_change for method_missing.
71
+ def attribute_delta_change(attr)
72
+ [delta_changed_attributes[attr], __send__(attr)] if attribute_delta_changed?(attr)
73
+ end
74
+
75
+ # Handle *_delta_was for method_missing.
76
+ def attribute_delta_was(attr)
77
+ attribute_delta_changed?(attr) ? delta_changed_attributes[attr] : __send__(attr)
78
+ end
79
+
80
+ # Handle <tt>*_will_change!</tt> for +method_missing+.
81
+ def attribute_delta_will_change!(attr, options = {})
82
+ attribute_value = if self.class.delta_changes_options[:attributes].include?(attr)
83
+ value = send(attr)
84
+ value.duplicable? ? value.clone : value
85
+ else
86
+ options[:from] || clone_attribute_value(:read_attribute, attr)
87
+ end
88
+ delta_changed_attributes[attr] = attribute_value
89
+ end
90
+
91
+ # Wrap write_attribute to remember original attribute value.
92
+ def write_attribute_with_delta_changes(attr, value)
93
+ attr = attr.to_s
94
+
95
+ if self.class.delta_changes_options[:columns].include?(attr)
96
+ # The attribute already has an unsaved change.
97
+ if delta_changed_attributes.include?(attr)
98
+ old = delta_changed_attributes[attr]
99
+ delta_changed_attributes.delete(attr) unless field_changed?(attr, old, value)
100
+ else
101
+ old = clone_attribute_value(:read_attribute, attr)
102
+ delta_changed_attributes[attr] = old if field_changed?(attr, old, value)
103
+ end
104
+ end
105
+
106
+ write_attribute_without_delta_changes(attr, value)
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,99 @@
1
+ require "spec_helper"
2
+
3
+ describe DeltaChanges do
4
+ it "has a VERSION" do
5
+ DeltaChanges::VERSION.should =~ /^[\.\da-z]+$/
6
+ end
7
+
8
+ it "should not create methods on unspecified attributes" do
9
+ # TODO broken, but that might be rails 2 ...
10
+ #expect{
11
+ # User.new.email_delta_will_change!
12
+ #}.to raise_error
13
+
14
+ expect{
15
+ User.new.bar_delta_will_change!
16
+ }.to raise_error
17
+
18
+ expect{
19
+ User.new.does_not_exist_delta_will_change!
20
+ }.to raise_error
21
+ end
22
+
23
+ describe "#delta_changes" do
24
+ it "should be empty on unchanged" do
25
+ User.new.delta_changes.should == {}
26
+ end
27
+
28
+ it "should be filled by tracked column changes" do
29
+ User.new(:name => "Peter").delta_changes.should == {"name"=>[nil, "Peter"]}
30
+ end
31
+
32
+ it "should be filled by tracked number column change" do
33
+ User.new(:score => 5).delta_changes.should == {"score"=>[nil, 5]}
34
+ end
35
+
36
+ it "should be filled by tracked number column change that have the wrong type" do
37
+ User.new(:score => "5").delta_changes.should == {"score"=>[nil, 5]}
38
+ end
39
+
40
+ it "should not be filled by untracked column changes" do
41
+ User.new(:email => "Peter").delta_changes.should == {}
42
+ end
43
+
44
+ it "should not be filled implicit tracked attribute changes" do
45
+ user = User.new(:foo => 1)
46
+ user.delta_changes.should == {}
47
+ end
48
+
49
+ it "should be filled by explicit tracked attribute changes" do
50
+ user = User.new(:foo => 1)
51
+ user.foo_delta_will_change!
52
+ user.foo = 2
53
+ user.delta_changes.should == {"foo"=>[1, 2]}
54
+ end
55
+
56
+ it "should not mess with normal changes" do
57
+ User.new(:email => "EMAIL", :name => "NAME", :foo => "FOO").changes.should ==
58
+ {"email"=>[nil, "EMAIL"], "name"=>[nil, "NAME"]}
59
+ end
60
+
61
+ it "should not reset columns on save" do
62
+ user = User.create!(:name => "NAME", :foo => "FOO", :bar => "BAR")
63
+ user.delta_changes.should == {"name"=>[nil, "NAME"]}
64
+ end
65
+
66
+ it "should not reset columns on update" do
67
+ user = User.create!(:name => "NAME", :foo => "FOO", :bar => "BAR")
68
+ user.update_attributes(:name => "NAME-2")
69
+ user.delta_changes.should == {"name"=>[nil, "NAME-2"]}
70
+ end
71
+
72
+ # that might change, I'd consider this a bug ... but just documenting for now
73
+ it "should not reset columns on reload" do
74
+ user = User.create!(:name => "NAME", :foo => "FOO", :bar => "BAR")
75
+ user.reload
76
+ user.delta_changes.should == {"name"=>[nil, "NAME"]}
77
+ end
78
+
79
+ it "should have previouse value from db" do
80
+ user = User.create!(:name => "NAME", :foo => "FOO", :bar => "BAR")
81
+ user = User.find(user)
82
+ user.name = "NAME-2"
83
+ user.delta_changes.should == {"name"=>["NAME", "NAME-2"]}
84
+ end
85
+
86
+ it "should not track non-changes on tracked columns" do
87
+ user = User.create!(:score => 5).reload
88
+ user.reset_delta_changes!
89
+
90
+ user.delta_changes.should == {}
91
+
92
+ user.score = 5
93
+ user.delta_changes.should == {}
94
+
95
+ user.score = "5"
96
+ user.delta_changes.should == {}
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,31 @@
1
+ require "bundler/setup"
2
+ require "delta_changes"
3
+ require "active_record"
4
+
5
+ # connect
6
+ ActiveRecord::Base.establish_connection(
7
+ :adapter => "sqlite3",
8
+ :database => ":memory:"
9
+ )
10
+
11
+ # create tables
12
+ ActiveRecord::Schema.define(:version => 1) do
13
+ create_table :users do |t|
14
+ t.string :name
15
+ t.string :email
16
+ t.integer :score
17
+ t.timestamps
18
+ end
19
+ end
20
+
21
+ # create models
22
+ class User < ActiveRecord::Base
23
+ include DeltaChanges::Extension
24
+ attr_accessor :foo, :bar
25
+
26
+ delta_changes :columns => ["name", "score"], :attributes => ["foo"]
27
+
28
+ def full_name
29
+ "Mr. #{name}"
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delta_changes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Grosser
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description:
31
+ email: michael@grosser.it
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - .travis.yml
37
+ - Appraisals
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - Rakefile
41
+ - Readme.md
42
+ - delta_changes.gemspec
43
+ - gemfiles/rails2.gemfile
44
+ - gemfiles/rails2.gemfile.lock
45
+ - gemfiles/rails30.gemfile
46
+ - gemfiles/rails30.gemfile.lock
47
+ - gemfiles/rails32.gemfile
48
+ - gemfiles/rails32.gemfile.lock
49
+ - lib/delta_changes.rb
50
+ - lib/delta_changes/version.rb
51
+ - spec/delta_changes_spec.rb
52
+ - spec/spec_helper.rb
53
+ homepage: http://github.com/grosser/delta_changes
54
+ licenses:
55
+ - MIT
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ segments:
67
+ - 0
68
+ hash: 3940600882562868341
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ segments:
76
+ - 0
77
+ hash: 3940600882562868341
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.24
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Additional real/virtual attribute change tracking independent of ActiveRecords
84
+ test_files: []