attribute_changer 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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=d
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in attribute_changer.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Zbigniew Humeniuk
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,72 @@
1
+ # AttributeChanger
2
+
3
+ Allows step change for attributes.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'attribute_changer'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install attribute_changer
18
+
19
+ ## Usage
20
+
21
+ class Dummy < ActiveRecord::Base
22
+ include AttributeChanger::Allower
23
+
24
+ attributes_allowed_for_step_change [:attr1, :attr2]
25
+
26
+ validates :attr1, presence: true, inclusion:{in: %w(foo bar)}
27
+ validates :attr2, presence: true, if: ->(obj){ obj.attr1 == 'bar' }
28
+ validates :attr3, presence: true
29
+ end
30
+
31
+ dummy = Dummy.create do |obj|
32
+ obj.attr1 = 'foo'
33
+ obj.attr3 = false
34
+ end
35
+
36
+ performer = AttributeChanger::Performer.new obj: dummy, attrib: :attr3, value: true
37
+ performer.save # false
38
+ performer.result.message # :not_allowed
39
+
40
+ performer = AttributeChanger::Performer.new obj: dummy, attrib: :attr1, value: 'bar'
41
+ performer.save # true
42
+
43
+ AttributeChanger::AttributeChange.from_obj(dummy).pending.count # 1
44
+
45
+ committer = AttributeChanger::Committer.new performer.attrib_change
46
+ committer.accept # false
47
+ committer.result.message # :invalid_obj
48
+ committer.invalid_attribs # [:attr2]
49
+
50
+ AttributeChanger::AttributeChange.from_obj(dummy).waiting.count # 1
51
+
52
+ performer = AttributeChanger::Performer.new obj: dummy, attrib: :attr2, value: true
53
+ performer.save # true
54
+
55
+ dummy.reload
56
+ dummy.attr1 # 'foo'
57
+ dummy.attr2 # nil
58
+
59
+ AttributeChanger::Committer.new(performer.attrib_change).accept # true
60
+
61
+ dummy.reload
62
+ dummy.attr1 # bar
63
+ dummy.attr2 # true
64
+
65
+
66
+ ## Contributing
67
+
68
+ 1. Fork it
69
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
70
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
71
+ 4. Push to the branch (`git push origin my-new-feature`)
72
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'attribute_changer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "attribute_changer"
8
+ spec.version = AttributeChanger::VERSION
9
+ spec.authors = ["Zbigniew Humeniuk"]
10
+ spec.email = ["zbigniew.humeniuk@gmail.com"]
11
+ spec.description = %q{Allows step change for attributes.}
12
+ spec.summary = %q{Allows step change for attributes.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'activesupport', '>= 3.0.0'
22
+ spec.add_dependency 'activerecord', '>= 3.0.0'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec", "~> 2.13.0"
27
+ spec.add_development_dependency "activemodel", "~> 3.2.13"
28
+ spec.add_development_dependency "sqlite3", "~> 1.3.7"
29
+ spec.add_development_dependency 'database_cleaner', '~> 0.9.1'
30
+ spec.add_development_dependency 'factory_girl', '~> 4.2.0'
31
+ end
@@ -0,0 +1,12 @@
1
+ module AttributeChanger
2
+ end
3
+
4
+ require 'active_record' unless defined?(ActiveRecord)
5
+ require 'active_support/concern' unless defined?(ActiveSupport::Concern)
6
+
7
+ require "attribute_changer/version"
8
+ require 'attribute_changer/committer'
9
+ require 'attribute_changer/performer'
10
+ require 'attribute_changer/allower'
11
+ require 'attribute_changer/attribute_change'
12
+ require 'attribute_changer/utils/result'
@@ -0,0 +1,15 @@
1
+ module AttributeChanger::Allower
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ class_attribute :_attributes_allowed_for_step_change
6
+ end
7
+
8
+ module ClassMethods
9
+ def attributes_allowed_for_step_change(attribs = nil)
10
+ self._attributes_allowed_for_step_change ||= []
11
+ self._attributes_allowed_for_step_change = *attribs if attribs
12
+ _attributes_allowed_for_step_change
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,76 @@
1
+ class AttributeChanger::AttributeChange < ::ActiveRecord::Base
2
+ self.table_name_prefix = 'attribute_changer_'
3
+
4
+ attr_accessible nil
5
+
6
+ validates :obj_id, presence: true
7
+ validates :obj_type, presence: true
8
+ validates :attrib, presence: true
9
+ validates :status, presence: true, inclusion:{in: %w(obsolete pending rejected accepted waiting)}
10
+
11
+ after_initialize :set_default_values
12
+ after_create :change_status
13
+
14
+ class << self
15
+ def from_obj(obj); where("obj_type = ? AND obj_id = ?", obj.class.name, obj.id) end
16
+ def pending; where("status = ?", 'pending') end
17
+ def waiting; where("status = ?", 'waiting') end
18
+ end
19
+
20
+ def obj_type
21
+ if val = read_attribute(:obj_type)
22
+ val.constantize
23
+ end
24
+ end
25
+
26
+ def obj
27
+ if obj_type && obj_id
28
+ @obj ||= obj_type.find_by_id obj_id
29
+ end
30
+ end
31
+
32
+ def obj=(val)
33
+ self.obj_id = val.id
34
+ self.obj_type = val.class.to_s
35
+ end
36
+
37
+ def value=(val)
38
+ write_attribute :value, serialize(val)
39
+ end
40
+
41
+ def value
42
+ deserialize
43
+ end
44
+
45
+ def dependent_attribs(o = obj)
46
+ attrib_was = o.send "#{attrib}"
47
+ o.send "#{attrib}=", value
48
+ o.valid?
49
+ da = o.errors.messages.map{|attr, errors| attr if errors.any?}.compact
50
+ o.send "#{attrib}=", attrib_was
51
+ o.valid?
52
+ da
53
+ end
54
+
55
+
56
+ private
57
+
58
+ def set_default_values
59
+ self.status ||= 'pending'
60
+ end
61
+
62
+ def change_status
63
+ self.class.where('obj_id = ?', obj_id).where('obj_type = ?', obj_type.to_s).where('attrib = ?', attrib).
64
+ where('status = ?', 'pending').where('created_at < ?', created_at).each do |o|
65
+ o.update_attribute :status, 'obsolete'
66
+ end
67
+ end
68
+
69
+ def serialize(val)
70
+ Base64.encode64(Marshal.dump(val))
71
+ end
72
+
73
+ def deserialize
74
+ Marshal.load Base64.decode64(read_attribute(:value))
75
+ end
76
+ end
@@ -0,0 +1,69 @@
1
+ class AttributeChanger::Committer
2
+ attr_reader :result, :error, :invalid_attribs
3
+
4
+ def initialize(attribute_change)
5
+ @result = AttributeChanger::Utils::Result.new nil, nil
6
+ @attribute_change = attribute_change
7
+ end
8
+
9
+ def attrib_change; @attribute_change end
10
+
11
+ def accept
12
+ if update_obj
13
+ @result.success = true
14
+ else
15
+ @result.success = false
16
+ false
17
+ end
18
+ end
19
+
20
+ def reject
21
+ update_status :rejected
22
+ end
23
+
24
+
25
+ private
26
+
27
+ def update_obj
28
+ @obj = @attribute_change.obj
29
+ @obj.send "#{@attribute_change.attrib}=", @attribute_change.value
30
+ return update_status(:accepted) if @obj.save
31
+ assign_error
32
+ assign_invalid_attribs
33
+ if @obj.errors[@attribute_change.attrib].any?
34
+ return update_status(:accepted) if take_into_consideration_waiting_changes
35
+ @result.message = :invalid_attrib
36
+ else
37
+ return update_status(:accepted) if take_into_consideration_waiting_changes
38
+ @result.message = :invalid_obj
39
+ update_status :waiting
40
+ end
41
+ false
42
+ end
43
+
44
+ def update_status(status)
45
+ @attribute_change.status = status.to_s
46
+ @attribute_change.save!
47
+ end
48
+
49
+ def assign_error
50
+ @error = @obj.class.human_attribute_name(@obj.errors.first.first) + ' ' + @obj.errors.first.last
51
+ end
52
+
53
+ def assign_invalid_attribs
54
+ @invalid_attribs = @obj.errors.messages.map{ |attr, errors| attr if errors.any? }.compact
55
+ end
56
+
57
+ def take_into_consideration_waiting_changes
58
+ attrib_changes = AttributeChanger::AttributeChange.from_obj(@obj).waiting.all
59
+ attrib_changes.each{ |ac| @obj.send "#{ac.attrib}=", ac.value }
60
+ saved = @obj.save
61
+ if saved
62
+ attrib_changes.each do |ac|
63
+ ac.status = 'accepted'
64
+ ac.save!
65
+ end
66
+ end
67
+ saved
68
+ end
69
+ end
@@ -0,0 +1,82 @@
1
+ class AttributeChanger::Performer
2
+ attr_reader :obj, :error, :result, :attrib, :attrib_change
3
+
4
+ def initialize(attribs)
5
+ @obj = attribs[:obj]
6
+ @attrib = attribs[:attrib]
7
+ @value = attribs[:value]
8
+ end
9
+
10
+ def save
11
+ valid
12
+ return false if result && !result.success
13
+ create_attribute_change
14
+ @result = AttributeChanger::Utils::Result.new true, nil
15
+ true
16
+ end
17
+
18
+
19
+ private
20
+
21
+ def attrib_exists?
22
+ (@obj.attributes.keys - %w(id created_at updated_at)).include? @attrib.to_s
23
+ end
24
+
25
+ def attribute_allowed?
26
+ @obj.class.attributes_allowed_for_step_change.include? @attrib
27
+ end
28
+
29
+ #BEGIN validation
30
+ def valid
31
+ unless attribute_allowed?
32
+ @result = AttributeChanger::Utils::Result.new false, :not_allowed
33
+ return
34
+ end
35
+
36
+ unless attrib_exists?
37
+ @result = AttributeChanger::Utils::Result.new false, :missing_attribute
38
+ return
39
+ end
40
+
41
+ if same_value?
42
+ @result = AttributeChanger::Utils::Result.new false, :same
43
+ return
44
+ end
45
+
46
+ unless valid_attrib?
47
+ assign_error
48
+ reset_obj
49
+ @result = AttributeChanger::Utils::Result.new false, :invalid
50
+ return
51
+ end
52
+ end
53
+
54
+ def valid_attrib?
55
+ @obj.send "#{@attrib}=", @value
56
+ @obj.valid?
57
+ @obj.errors[@attrib].empty?
58
+ end
59
+
60
+ def same_value?
61
+ @obj.send(@attrib) == @value
62
+ end
63
+
64
+ def assign_error
65
+ @error = @obj.errors[@attrib].first
66
+ end
67
+
68
+ def reset_obj
69
+ @obj.errors.clear
70
+ @obj.reload
71
+ end
72
+ # END validation
73
+
74
+ def create_attribute_change
75
+ @attrib_change = AttributeChanger::AttributeChange.new do |o|
76
+ o.obj = @obj
77
+ o.attrib = @attrib
78
+ o.value = @value
79
+ end
80
+ @attrib_change.save!
81
+ end
82
+ end
@@ -0,0 +1,3 @@
1
+ module AttributeChanger::Utils
2
+ Result = Struct.new :success, :message
3
+ end
@@ -0,0 +1,3 @@
1
+ module AttributeChanger
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ class AttributeChangerGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('../templates', __FILE__)
3
+
4
+ desc "Create migration"
5
+
6
+ def copy_migration
7
+ copy_file "create_attribute_changer_attribute_changes.rb", "db/migrate/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_create_attribute_changer_attribute_changes.rb"
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ class CreateAttributeChangerAttributeChanges < ActiveRecord::Migration
2
+ def change
3
+ create_table :attribute_changer_attribute_changes do |t|
4
+ t.string :obj_type
5
+ t.integer :obj_id
6
+ t.string :attrib
7
+ t.string :value
8
+ t.string :status
9
+
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :attribute_change, class: AttributeChanger::AttributeChange do
3
+ obj{ Dummy.new({attr1: 'foo', attr2: true}) }
4
+ attrib 'attr1'
5
+ value 'bar'
6
+ end
7
+ end
@@ -0,0 +1,84 @@
1
+ class Dummy
2
+ include ActiveModel::Validations
3
+ include ActiveModel::Conversion
4
+ include AttributeChanger::Allower
5
+
6
+ @@objects = []
7
+
8
+ attr_reader :id
9
+ attr_accessor :attr2
10
+ attributes_allowed_for_step_change [:attr1, :attr3, :attr4]
11
+
12
+ validates :attr1, presence: true, inclusion:{in: %w(foo bar baz boo)}
13
+ validates :attr2, presence: true
14
+ validates :attr3, presence: true, if: ->(ac){ ac.attr1 == 'boo' }
15
+ validates :attr4, presence: true, if: ->(ac){ ac.attr3.present? }
16
+
17
+ def initialize attributes={}
18
+ attributes.each do |name, value|
19
+ send "#{name}=", value
20
+ end
21
+ @id = @@objects.size + 1
22
+ @@objects << self
23
+ end
24
+
25
+ class << self
26
+ def find_by_id id
27
+ @@objects.find{ |o| o.id == id }
28
+ end
29
+ end
30
+
31
+ def attr1; @attr1 end
32
+ def attr3; @attr3 end
33
+ def attr4; @attr4 end
34
+
35
+ def attr1= val
36
+ @attr1_was = @attr1 if val != @attr1
37
+ @attr1 = val
38
+ end
39
+
40
+ def attr3= val
41
+ @attr3_was = @attr3 if val != @attr3
42
+ @attr3 = val
43
+ end
44
+
45
+ def attr4= val
46
+ @attr4_was = @attr4 if val != @attr4
47
+ @attr4 = val
48
+ end
49
+
50
+ def persisted?
51
+ false
52
+ end
53
+
54
+ def attributes
55
+ attrs = {}
56
+ %w(attr1 attr2 attr3 attr4).each{ |name| attrs[name] = send(name) }
57
+ attrs
58
+ end
59
+
60
+ def save
61
+ if valid?
62
+ clear_changes
63
+ true
64
+ else
65
+ false
66
+ end
67
+ end
68
+
69
+ def reload
70
+ @attr1 = @attr1_was if @attr1_was
71
+ @attr3 = @attr3_was if @attr3_was
72
+ @attr4 = @attr4_was if @attr4_was
73
+ self
74
+ end
75
+
76
+
77
+ private
78
+
79
+ def clear_changes
80
+ @attr1_was = nil
81
+ @attr3_was = nil
82
+ @attr4_was = nil
83
+ end
84
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttributeChanger::Allower do
4
+ it "includes attributes_allowed_for_step_change class method" do
5
+ Dummy.stub(:attributes_allowed_for_step_change){ |arg1| true }
6
+ Dummy.attributes_allowed_for_step_change(:attrib1).should be_true
7
+ end
8
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttributeChanger::AttributeChange do
4
+ describe "attributes" do
5
+ it "has obj attribute" do
6
+ subject.obj.should be_nil
7
+ end
8
+
9
+ describe "obj" do
10
+ it "sets obj_type and obj_id from obj" do
11
+ obj = Dummy.new attr1: 'foo', attr2: true
12
+ subject.obj = obj
13
+ subject.obj_id.should eq obj.id
14
+ subject.obj_type.should eq Dummy
15
+ end
16
+ end
17
+
18
+ describe "status" do
19
+ it "has default value equals pending" do
20
+ subject.status.should eq 'pending'
21
+ end
22
+ end
23
+
24
+ describe "value" do
25
+ it "is serialized" do
26
+ ac = FactoryGirl.create :attribute_change, value: 'baz'
27
+ AttributeChanger::AttributeChange.find(ac.id).value.should eql 'baz'
28
+ end
29
+
30
+ it "could be nil" do
31
+ ac = FactoryGirl.create :attribute_change, value: nil
32
+ AttributeChanger::AttributeChange.find(ac.id).value.should be_nil
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "instance methods" do
38
+ describe "#dependent_attribs" do
39
+ it "returns dependent attributes"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,123 @@
1
+ require "spec_helper"
2
+
3
+ describe AttributeChanger::Committer do
4
+ describe "attributes" do
5
+ describe "result" do
6
+ it "is instance of AttributeChanger::Utils::Result" do
7
+ AttributeChanger::Committer.new(nil).result.should be_instance_of AttributeChanger::Utils::Result
8
+ end
9
+ end
10
+ end
11
+
12
+ describe "instance methods" do
13
+ let(:dummy_obj){ Dummy.new attr1: 'foo', attr2: true }
14
+ let(:performer){ AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr1, value: 'bar') }
15
+ let(:committer){ AttributeChanger::Committer.new performer.attrib_change }
16
+
17
+ before do
18
+ performer.save
19
+ dummy_obj.reload
20
+ end
21
+
22
+ describe "#accept" do
23
+ before { committer.accept }
24
+
25
+ context "change is valid" do
26
+ it "changes status of attribute's change to accepted" do
27
+ committer.attrib_change.reload.status.should eq "accepted"
28
+ end
29
+
30
+ it "changes attribute's value" do
31
+ dummy_obj.reload.attr1.should == 'bar'
32
+ end
33
+
34
+ it "returns true" do
35
+ performer = AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr1, value: 'baz')
36
+ performer.save
37
+ AttributeChanger::Committer.new(performer.attrib_change).accept.should be_true
38
+ end
39
+ end
40
+
41
+ context "change is invalid" do
42
+ let(:committer) do
43
+ attrib_change = performer.attrib_change
44
+ attrib_change.value = 'buz'
45
+ AttributeChanger::Committer.new attrib_change
46
+ end
47
+
48
+ it "leaves pending status" do
49
+ committer.attrib_change.reload.status.should eq "pending"
50
+ end
51
+
52
+ it "does not change attribute's value" do
53
+ dummy_obj.reload.attr1.should == 'foo'
54
+ end
55
+
56
+ it "returns false" do
57
+ committer.accept.should be_false
58
+ end
59
+
60
+ it "has result attribute with success equals false" do
61
+ committer.result.success.should be_false
62
+ end
63
+
64
+ it "has result attribute with proper message" do
65
+ committer.result.message.should eq :invalid_attrib
66
+ end
67
+
68
+ it "assigns error attribute" do
69
+ committer.error.should eq 'Attr1 is not included in the list'
70
+ end
71
+ end
72
+
73
+ context "change is valid but whole object is invalid" do
74
+ let(:performer){ AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr1, value: 'boo') }
75
+
76
+ it "sets status to waiting" do
77
+ committer.attrib_change.reload.status.should eq "waiting"
78
+ end
79
+
80
+ it "has result attribute with proper message" do
81
+ committer.result.message.should eq :invalid_obj
82
+ end
83
+
84
+ it "allows to get invalid attributes through getter" do
85
+ committer.invalid_attribs.should eq [:attr3]
86
+ end
87
+
88
+ context "changes for invalid attributes are waiting" do
89
+ before do
90
+ p1 = AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr3, value: 'foo')
91
+ p1.save
92
+ AttributeChanger::Committer.new(p1.attrib_change).accept # false, :invalid_obj
93
+ dummy_obj.attr3 = nil
94
+ p2 = AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr4, value: 'foo')
95
+ p2.save
96
+ AttributeChanger::Committer.new(p2.attrib_change).accept
97
+ committer.accept
98
+ end
99
+
100
+ it "takes into consideration all valid waiting changes and change status to accepted" do
101
+ committer.attrib_change.reload.status.should eq "accepted"
102
+ end
103
+
104
+ it "changes status of waiting changes to accepted" do
105
+ AttributeChanger::AttributeChange.waiting.count.should eq 0
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ describe "#reject" do
112
+ before { committer.reject }
113
+
114
+ it "changes status of attribute's change to rejected" do
115
+ committer.attrib_change.reload.status.should eq "rejected"
116
+ end
117
+
118
+ it "does not change attribute's value" do
119
+ dummy_obj.attr1.should == 'foo'
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttributeChanger::Performer do
4
+ describe "instance methods" do
5
+ describe "#save" do
6
+ let(:dummy_obj){ Dummy.new attr1: 'foo' }
7
+
8
+ it "sets Utils::Result object to result attribute" do
9
+ ac = AttributeChanger::Performer.new({obj: dummy_obj, attrib: :attr1, value: 'bar'})
10
+ ac.save
11
+ ac.result.should be_instance_of AttributeChanger::Utils::Result
12
+ end
13
+
14
+ context "value is allowed" do
15
+ context "new value is valid" do
16
+ context "new value if different" do
17
+ it "creates attribute's change object" do
18
+ AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr1, value: 'bar').save
19
+ AttributeChanger::AttributeChange.count.should eq 1
20
+ end
21
+ end
22
+ context "new value is the same" do
23
+ it "does not create attribute's change object" do
24
+ AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr1, value: 'foo').save
25
+ AttributeChanger::AttributeChange.count.should eq 0
26
+ end
27
+ end
28
+ end
29
+
30
+ context "new value is invalid" do
31
+ let(:attribute_changer){ AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr1, value: 'buz') }
32
+
33
+ before{ attribute_changer.save }
34
+
35
+ it "assigns error attribute" do
36
+ attribute_changer.error.should eq "is not included in the list"
37
+ end
38
+
39
+ it "do not change the object" do
40
+ attribute_changer.obj.attr1.should eq 'foo'
41
+ end
42
+
43
+ it "do not assign error to object" do
44
+ attribute_changer.obj.errors.should be_empty
45
+ end
46
+ end
47
+ end
48
+
49
+ context "value is not allowed" do
50
+ subject{ AttributeChanger::Performer.new(obj: dummy_obj, attrib: :attr2, value: 'foo') }
51
+
52
+ before{ subject.save }
53
+
54
+ it("returns false") { subject.save.should be_false }
55
+
56
+ it("has result with success attribute equals false") { subject.result.success.should be_false }
57
+
58
+ it("has result with proper message") { subject.result.message.should == :not_allowed }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ describe AttributeChanger do
2
+ it "must be defined" do
3
+ AttributeChanger::VERSION.should_not be_nil
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'bundler/setup'
5
+ require 'active_model'
6
+ require 'factory_girl'
7
+ require 'database_cleaner'
8
+
9
+ Bundler.require
10
+
11
+ Dir["#{File.dirname(__FILE__)}/fixtures/**/*.rb"].each{|f| require f}
12
+ Dir["#{File.dirname(__FILE__)}/factories/**/*.rb"].each{|f| require f}
13
+
14
+ RSpec.configure do |config|
15
+ config.order = "random"
16
+
17
+ config.before :suite do
18
+ DatabaseCleaner.strategy = :truncation
19
+ end
20
+
21
+ config.before :each do
22
+ DatabaseCleaner.start
23
+ end
24
+
25
+ config.after :each do
26
+ DatabaseCleaner.clean
27
+ end
28
+ end
29
+
30
+ ActiveRecord::Base.establish_connection({
31
+ adapter: 'sqlite3',
32
+ database: ':memory:'
33
+ })
34
+
35
+ ActiveRecord::Schema.define do
36
+ self.verbose = false
37
+
38
+ create_table "attribute_changer_attribute_changes", force: true do |t|
39
+ t.string "obj_type"
40
+ t.integer "obj_id"
41
+ t.string "attrib"
42
+ t.string "value"
43
+ t.string "status"
44
+ t.datetime "created_at", null: false
45
+ t.datetime "updated_at", null: false
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,222 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attribute_changer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Zbigniew Humeniuk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.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: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: activerecord
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 3.0.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 3.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 2.13.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 2.13.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: activemodel
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 3.2.13
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 3.2.13
110
+ - !ruby/object:Gem::Dependency
111
+ name: sqlite3
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 1.3.7
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 1.3.7
126
+ - !ruby/object:Gem::Dependency
127
+ name: database_cleaner
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: 0.9.1
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: 0.9.1
142
+ - !ruby/object:Gem::Dependency
143
+ name: factory_girl
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ version: 4.2.0
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: 4.2.0
158
+ description: Allows step change for attributes.
159
+ email:
160
+ - zbigniew.humeniuk@gmail.com
161
+ executables: []
162
+ extensions: []
163
+ extra_rdoc_files: []
164
+ files:
165
+ - .gitignore
166
+ - .rspec
167
+ - Gemfile
168
+ - LICENSE.txt
169
+ - README.md
170
+ - Rakefile
171
+ - attribute_changer.gemspec
172
+ - lib/attribute_changer.rb
173
+ - lib/attribute_changer/allower.rb
174
+ - lib/attribute_changer/attribute_change.rb
175
+ - lib/attribute_changer/committer.rb
176
+ - lib/attribute_changer/performer.rb
177
+ - lib/attribute_changer/utils/result.rb
178
+ - lib/attribute_changer/version.rb
179
+ - lib/generators/attribute_changer_generator.rb
180
+ - lib/generators/templates/create_attribute_changer_attribute_changes.rb
181
+ - spec/factories/attribute_change.rb
182
+ - spec/fixtures/dummy.rb
183
+ - spec/lib/attribute_changer/allower_spec.rb
184
+ - spec/lib/attribute_changer/attribute_change_spec.rb
185
+ - spec/lib/attribute_changer/committer_spec.rb
186
+ - spec/lib/attribute_changer/performer_spec.rb
187
+ - spec/lib/attribute_changer/version_spec.rb
188
+ - spec/spec_helper.rb
189
+ homepage: ''
190
+ licenses:
191
+ - MIT
192
+ post_install_message:
193
+ rdoc_options: []
194
+ require_paths:
195
+ - lib
196
+ required_ruby_version: !ruby/object:Gem::Requirement
197
+ none: false
198
+ requirements:
199
+ - - ! '>='
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ required_rubygems_version: !ruby/object:Gem::Requirement
203
+ none: false
204
+ requirements:
205
+ - - ! '>='
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ requirements: []
209
+ rubyforge_project:
210
+ rubygems_version: 1.8.24
211
+ signing_key:
212
+ specification_version: 3
213
+ summary: Allows step change for attributes.
214
+ test_files:
215
+ - spec/factories/attribute_change.rb
216
+ - spec/fixtures/dummy.rb
217
+ - spec/lib/attribute_changer/allower_spec.rb
218
+ - spec/lib/attribute_changer/attribute_change_spec.rb
219
+ - spec/lib/attribute_changer/committer_spec.rb
220
+ - spec/lib/attribute_changer/performer_spec.rb
221
+ - spec/lib/attribute_changer/version_spec.rb
222
+ - spec/spec_helper.rb