ar-deltas 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 Arya Asemanfar
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ lib/ar-deltas.rb
2
+ MIT-LICENSE
3
+ Rakefile
4
+ Manifest
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('ar-deltas', '0.6') do |p|
6
+ p.description = "ActiveRecord extension to allow for updating numerical attributes using deltas."
7
+ p.url = "https://github.com/arya/ar-deltas/"
8
+ p.author = "Arya Asemanfar"
9
+ p.email = "aryaasemanfar@gmail.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*", 'test/*']
11
+ p.runtime_dependencies = ["activerecord"]
12
+ p.development_dependencies = ["shoulda"]
13
+ end
14
+
15
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ar-deltas}
5
+ s.version = "0.6"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Arya Asemanfar"]
9
+ s.date = %q{2009-09-30}
10
+ s.description = %q{ActiveRecord extension to allow for updating numerical attributes using deltas.}
11
+ s.email = %q{aryaasemanfar@gmail.com}
12
+ s.extra_rdoc_files = ["lib/ar-deltas.rb"]
13
+ s.files = ["lib/ar-deltas.rb", "MIT-LICENSE", "Rakefile", "Manifest", "ar-deltas.gemspec", "test/deltas_test.rb", "test/test_helper.rb"]
14
+ s.homepage = %q{https://github.com/arya/ar-deltas/}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ar-deltas", "--main", "README.markdown"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{ar-deltas}
18
+ s.rubygems_version = %q{1.3.4}
19
+ s.summary = %q{ActiveRecord extension to allow for updating numerical attributes using deltas.}
20
+ s.test_files = ["test/deltas_test.rb", "test/test_helper.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<activerecord>, [">= 0"])
28
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
29
+ else
30
+ s.add_dependency(%q<activerecord>, [">= 0"])
31
+ s.add_dependency(%q<shoulda>, [">= 0"])
32
+ end
33
+ else
34
+ s.add_dependency(%q<activerecord>, [">= 0"])
35
+ s.add_dependency(%q<shoulda>, [">= 0"])
36
+ end
37
+ end
@@ -0,0 +1,48 @@
1
+ require 'set'
2
+
3
+ module ActiveRecord::Deltas
4
+ def self.included(klass)
5
+ klass.class_eval do
6
+ alias_method_chain :attributes_with_quotes, :deltas
7
+ end
8
+ end
9
+
10
+ def attributes_with_quotes_with_deltas(*args)
11
+ with_deltas = attributes_with_quotes_without_deltas(*args)
12
+ return with_deltas if self.new_record?
13
+ with_deltas.keys.each do |attribute_name|
14
+ if self.class.delta_attributes.include?(attribute_name.intern) && !self.excluded_deltas.include?(attribute_name.intern)
15
+ delta_string = "#{self.connection.quote_column_name(attribute_name)} "
16
+ old_value, new_value = self.changes[attribute_name]
17
+ delta_string << (old_value > new_value ? "-" : "+")
18
+ delta_string << " #{(old_value - new_value).abs}"
19
+ with_deltas[attribute_name] = delta_string
20
+ end
21
+ end
22
+ with_deltas
23
+ end
24
+
25
+ def excluded_deltas
26
+ @_excluded_deltas ||= Set.new
27
+ end
28
+
29
+ def force_clobber(attr_name, value)
30
+ self.excluded_deltas.add(attr_name.to_s.intern)
31
+ send("#{attr_name}=", value)
32
+ end
33
+ end
34
+
35
+ class ActiveRecord::Base
36
+ include ActiveRecord::Deltas
37
+ class InvalidDeltaColumn < StandardError; end
38
+ def self.delta_attributes(*args)
39
+ @_delta_attributes ||= Set.new
40
+
41
+ return @_delta_attributes if args.empty?
42
+
43
+ args.each do |attribute|
44
+ raise InvalidDeltaColumn.new("Delta attributes only work with number attributes, column `#{attribute}` is not a number.") unless self.columns_hash[attribute.to_s].number?
45
+ @_delta_attributes.add(attribute)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+ puts ActiveRecord::VERSION::STRING
3
+
4
+ class DeltasTest < Test::Unit::TestCase
5
+ include TestHelper
6
+ context "with an blank AR class" do
7
+ setup do
8
+ conn = connection_specification # because it changes context in the block
9
+ @klass = Class.new(ActiveRecord::Base) do
10
+ self.table_name = "widgets"
11
+ establish_connection(conn)
12
+ end
13
+ end
14
+
15
+ should "should throw exception for deltaing non-number fields" do
16
+ assert_raises(ActiveRecord::Base::InvalidDeltaColumn) do
17
+ @klass.class_eval { delta_attributes :name }
18
+ end
19
+ end
20
+
21
+ should "override values with latest update" do
22
+ original = @klass.create
23
+ one, two = @klass.find(original.id), @klass.find(original.id)
24
+ one.counter += 2
25
+ two.counter += 3
26
+ one.save
27
+ two.save
28
+ assert_equal 3, original.reload.counter
29
+ end
30
+
31
+ context "with a delta attribute" do
32
+ setup do
33
+ @klass.class_eval { delta_attributes :counter }
34
+ end
35
+
36
+ should "update value using delta (additions)" do
37
+ original = @klass.create
38
+ one, two = @klass.find(original.id), @klass.find(original.id)
39
+ one.counter += 2
40
+ two.counter += 3
41
+ one.save
42
+ two.save
43
+ assert_equal 5, original.reload.counter
44
+ end
45
+
46
+ should "update value using delta (subtractions)" do
47
+ original = @klass.create
48
+ one, two = @klass.find(original.id), @klass.find(original.id)
49
+ one.counter -= 6
50
+ two.counter -= 7
51
+ one.save
52
+ two.save
53
+ assert_equal -13, original.reload.counter
54
+ end
55
+
56
+ should "exclude delta attribute if explictly specified" do
57
+ original = @klass.create
58
+ one, two = @klass.find(original.id), @klass.find(original.id)
59
+ one.force_clobber(:counter, 100)
60
+ two.force_clobber(:counter, 3000)
61
+ one.save
62
+ two.save
63
+ assert_equal 3000, original.reload.counter
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,20 @@
1
+ TEST_DIR = File.dirname(__FILE__)
2
+ %w(lib test).each do |dir|
3
+ $LOAD_PATH.unshift File.join(TEST_DIR, "..", dir)
4
+ end
5
+
6
+ require 'test/unit'
7
+ require 'rubygems'
8
+ require 'shoulda'
9
+
10
+ require 'activerecord'
11
+ require 'ar-deltas'
12
+
13
+ # To run the tests, you need a MySQL database as described below.
14
+ # create table widgets (id int auto_increment primary key, counter int default 0, name varchar(255));
15
+
16
+ module TestHelper
17
+ def connection_specification
18
+ {:username => "root", :password => "", :database => "ar_deltas", :adapter => "mysql"}
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ar-deltas
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.6"
5
+ platform: ruby
6
+ authors:
7
+ - Arya Asemanfar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-30 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: shoulda
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: ActiveRecord extension to allow for updating numerical attributes using deltas.
36
+ email: aryaasemanfar@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - lib/ar-deltas.rb
43
+ files:
44
+ - lib/ar-deltas.rb
45
+ - MIT-LICENSE
46
+ - Rakefile
47
+ - Manifest
48
+ - ar-deltas.gemspec
49
+ - test/deltas_test.rb
50
+ - test/test_helper.rb
51
+ has_rdoc: true
52
+ homepage: https://github.com/arya/ar-deltas/
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --line-numbers
58
+ - --inline-source
59
+ - --title
60
+ - Ar-deltas
61
+ - --main
62
+ - README.markdown
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: "1.2"
76
+ version:
77
+ requirements: []
78
+
79
+ rubyforge_project: ar-deltas
80
+ rubygems_version: 1.3.4
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: ActiveRecord extension to allow for updating numerical attributes using deltas.
84
+ test_files:
85
+ - test/deltas_test.rb
86
+ - test/test_helper.rb