validates_immutability 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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ .rspec
4
+ .rvmrc
5
+ Gemfile.lock
6
+ pkg/*
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ 1.0.0
2
+ * can make attributes immutable
3
+ * can make record as a whole immutable
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in validates_immutability.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Austin Schneider
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
+ NON-INFRINGEMENT. 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.rdoc ADDED
@@ -0,0 +1,54 @@
1
+ = ValidatesImmutability
2
+
3
+ Validations for making ActiveRecord objects immutable.
4
+
5
+ == Examples
6
+
7
+ class Person < ActiveRecord::Base
8
+ immutable :unless => :can_change?, :message => "I don't like being changed."
9
+
10
+ def can_change?
11
+ true
12
+ end
13
+ end
14
+
15
+ > p = Person.first
16
+ > p.plays = "soccer"
17
+ > p.valid?
18
+ => false
19
+ > p.errors
20
+ => {:base=>["I don't like being changed."]}
21
+
22
+
23
+
24
+ class Car < ActiveRecord::Base
25
+ validates :color, :immutable => {
26
+ :if => lambda { !color_can_change? },
27
+ :message => "is beautiful already."
28
+ }
29
+
30
+ def color_can_change?
31
+ true
32
+ end
33
+ end
34
+
35
+ > c = Car.first
36
+ > c.color = "red"
37
+ > c.valid?
38
+ => false
39
+ > c.errors
40
+ => {:color=>["is beautiful already."]}
41
+
42
+ == Note on Patches/Pull Requests
43
+
44
+ * Fork the project.
45
+ * Make your feature addition or bug fix.
46
+ * Add tests for it. This is important so I don't break it in a
47
+ future version unintentionally.
48
+ * Commit, do not mess with rakefile, version, or changelog.
49
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
50
+ * Send me a pull request. Bonus points for topic branches.
51
+
52
+ == Copyright
53
+
54
+ See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,25 @@
1
+ require "active_support"
2
+
3
+ module ValidatesImmutability
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def immutable(options = {})
8
+ if options.key?(:on)
9
+ raise ArgumentError, "Unknown option :on"
10
+ end
11
+ options.merge!(:on => :update)
12
+ error_msg = options.delete(:message) || "Updates are not allowed."
13
+ validate options do
14
+ errors[:base] << error_msg if changed?
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ require "validates_immutability/version"
21
+
22
+ ActiveSupport.on_load :active_record do
23
+ ActiveRecord::Base.send(:include, ValidatesImmutability)
24
+ require "validates_immutability/immutable_validator"
25
+ end
@@ -0,0 +1,17 @@
1
+ module ValidatesImmutability
2
+ class ImmutableValidator < ActiveModel::EachValidator
3
+ def validate_each(record, attribute, value)
4
+ if options.key?(:on)
5
+ raise ArgumentError, "Unknown option :on"
6
+ end
7
+ return if record.new_record?
8
+ if record.send("#{attribute}_changed?")
9
+ record.errors.add(attribute, (options[:message] || "can't be modified"))
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ # ImmutableValidator needs to be in global scope to be recognized up by AR
16
+ class ImmutableValidator < ValidatesImmutability::ImmutableValidator
17
+ end
@@ -0,0 +1,3 @@
1
+ module ValidatesImmutability
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+
3
+ class Widget4 < ActiveRecord::Base
4
+ set_table_name :widgets
5
+ validates :attr1, :immutable => true
6
+ end
7
+
8
+ describe Widget4, "validations" do
9
+ context "when persisted" do
10
+ subject { Widget4.create! }
11
+
12
+ context "when attr1 is changed" do
13
+ before do
14
+ subject.attr1 = "changed"
15
+ subject.valid?
16
+ p subject.errors
17
+ end
18
+
19
+ it { should be_invalid }
20
+ it { subject.errors.full_messages.should == ["Attr1 can't be modified"] }
21
+ end
22
+
23
+ context "when attr1 is not changed" do
24
+ it { should be_valid }
25
+ end
26
+ end
27
+
28
+ context "when new" do
29
+ subject { Widget4.new }
30
+ ["change", nil].each do |value|
31
+ context "when attr1 is #{value ? 'changed' : 'not changed'}" do
32
+ before { subject.attr1 = value if value }
33
+ it { should be_valid }
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ ##################################################
40
+
41
+ class Widget5 < ActiveRecord::Base
42
+ set_table_name :widgets
43
+ validates :attr1, :immutable => {:if => :validate_immutability}
44
+ attr_accessor :validate_immutability
45
+ end
46
+
47
+ describe Widget5, "validations" do
48
+ context "when persisted" do
49
+ subject { Widget5.create! }
50
+
51
+ context "when attr1 is changed" do
52
+ before { subject.attr1 = "changed" }
53
+
54
+ context "validate_immutability is true" do
55
+ before do
56
+ subject.validate_immutability = true
57
+ subject.valid?
58
+ end
59
+ it { should be_invalid }
60
+ it { subject.errors.full_messages.should == ["Attr1 can't be modified"] }
61
+ end
62
+
63
+ context "validate_immutability is not true" do
64
+ before { subject.validate_immutability = false }
65
+ it { should be_valid }
66
+ end
67
+ end
68
+
69
+ context "when attr1 is not changed" do
70
+ [true, false, nil].each do |value|
71
+ context "validate_immutability is #{value}" do
72
+ before { subject.validate_immutability = value }
73
+ it { should be_valid }
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ context "when new" do
80
+ subject { Widget5.new }
81
+
82
+ ["changed", nil].each do |value|
83
+ context "when attr1 is #{value ? 'changed' : 'not changed'}" do
84
+ before { subject.attr1 = value }
85
+ [true, false, nil].each do |value|
86
+ context "validate_immutability is #{value}" do
87
+ before { subject.validate_immutability = value }
88
+ it { should be_valid }
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ ##################################################
97
+
98
+ class Widget6 < ActiveRecord::Base
99
+ set_table_name :widgets
100
+ validates :attr1, :immutable => {:message => "is frozen!"}
101
+ end
102
+
103
+ describe Widget6, "validations" do
104
+ context "when persisted" do
105
+ subject { Widget6.create! }
106
+
107
+ context "when attr1 is changed" do
108
+ before do
109
+ subject.attr1 = "changed"
110
+ subject.valid?
111
+ end
112
+
113
+ it { should be_invalid }
114
+ it { subject.errors.full_messages.should == ["Attr1 is frozen!"] }
115
+ end
116
+
117
+ context "when attr1 is not changed" do
118
+ it { should be_valid }
119
+ end
120
+ end
121
+
122
+ context "when new" do
123
+ subject { Widget6.new }
124
+ ["change", nil].each do |value|
125
+ context "when attr1 is #{value ? 'changed' : 'not changed'}" do
126
+ before { subject.attr1 = value if value }
127
+ it { should be_valid }
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ class Widget1 < ActiveRecord::Base
4
+ set_table_name :widgets
5
+ end
6
+
7
+ describe Widget1, ".immutable" do
8
+ it "calls .validate" do
9
+ Widget1.should_receive(:validate).with(:a => 1, :b => 2, :on => :update)
10
+ Widget1.immutable(:a => 1, :b => 2, :message => 'some message')
11
+ end
12
+
13
+ context "when :on is given" do
14
+ it "raises an ArgumentError" do
15
+ lambda do
16
+ Widget1.immutable(:on => :create)
17
+ end.should raise_error(ArgumentError, "Unknown option :on")
18
+ end
19
+ end
20
+ end
21
+
22
+ ##################################################
23
+
24
+ class Widget2 < ActiveRecord::Base
25
+ set_table_name :widgets
26
+ immutable :message => 'My message'
27
+ end
28
+
29
+ describe Widget2, "validations" do
30
+ context "when persisted" do
31
+ subject { Widget2.create! }
32
+
33
+ context "when changed" do
34
+ before do
35
+ subject.attr1 = "changed"
36
+ subject.valid?
37
+ end
38
+
39
+ it { should be_invalid }
40
+ it { subject.errors.full_messages.should == ['My message'] }
41
+ end
42
+
43
+ context "when not changed" do
44
+ before { subject.valid? }
45
+ it { should be_valid }
46
+ end
47
+ end
48
+
49
+ context "when new" do
50
+ subject { Widget2.new }
51
+
52
+ context "when changed" do
53
+ before do
54
+ subject.attr1 = "changed"
55
+ subject.valid?
56
+ end
57
+ it { should be_valid }
58
+ end
59
+
60
+ context "when not changed" do
61
+ before { subject.valid? }
62
+ it { should be_valid }
63
+ end
64
+ end
65
+ end
66
+
67
+ ##################################################
68
+
69
+ class Widget3 < ActiveRecord::Base
70
+ set_table_name :widgets
71
+ immutable
72
+ end
73
+
74
+ describe Widget3, "validations" do
75
+ context "when persisted and changed" do
76
+ subject { Widget3.create! }
77
+ before do
78
+ subject.attr1 = "changed"
79
+ subject.valid?
80
+ end
81
+
82
+ it { should_not be_valid }
83
+ it { subject.errors.full_messages.should == ["Updates are not allowed."] }
84
+ end
85
+ end
@@ -0,0 +1,15 @@
1
+ require 'validates_immutability'
2
+ require 'active_record'
3
+
4
+ ActiveRecord::Base.establish_connection(
5
+ :adapter => 'sqlite3',
6
+ :database => ':memory:'
7
+ )
8
+
9
+ ActiveRecord::Schema.define(:version => 0) do
10
+ create_table :widgets, :force => true do |t|
11
+ t.string :attr1
12
+ t.string :attr2
13
+ t.string :attr3
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "validates_immutability/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "validates_immutability"
7
+ s.version = ValidatesImmutability::VERSION
8
+ s.authors = ["Austin Schneider"]
9
+ s.email = ["soccer022483@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = "Validations for making ActiveRecord objects immutable."
12
+ s.description = "Validations for making ActiveRecord objects immutable."
13
+
14
+ s.rubyforge_project = "validates_immutability"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec", "~> 2.6.0"
22
+ s.add_development_dependency "sqlite3", "~> 1.3.3"
23
+ s.add_development_dependency "activerecord", "~> 3.0.0"
24
+
25
+ s.add_dependency "activesupport", "~> 3.0.0"
26
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: validates_immutability
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Austin Schneider
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-06-01 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 6
31
+ - 0
32
+ version: 2.6.0
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: sqlite3
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 1
45
+ - 3
46
+ - 3
47
+ version: 1.3.3
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: activerecord
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ~>
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 3
60
+ - 0
61
+ - 0
62
+ version: 3.0.0
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: activesupport
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 3
75
+ - 0
76
+ - 0
77
+ version: 3.0.0
78
+ type: :runtime
79
+ version_requirements: *id004
80
+ description: Validations for making ActiveRecord objects immutable.
81
+ email:
82
+ - soccer022483@gmail.com
83
+ executables: []
84
+
85
+ extensions: []
86
+
87
+ extra_rdoc_files: []
88
+
89
+ files:
90
+ - .gitignore
91
+ - CHANGELOG
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.rdoc
95
+ - Rakefile
96
+ - lib/validates_immutability.rb
97
+ - lib/validates_immutability/immutable_validator.rb
98
+ - lib/validates_immutability/version.rb
99
+ - spec/lib/validates_immutability/immutable_validator_spec.rb
100
+ - spec/lib/validates_immutability_spec.rb
101
+ - spec/spec_helper.rb
102
+ - validates_immutability.gemspec
103
+ has_rdoc: true
104
+ homepage: ""
105
+ licenses: []
106
+
107
+ post_install_message:
108
+ rdoc_options: []
109
+
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ segments:
126
+ - 0
127
+ version: "0"
128
+ requirements: []
129
+
130
+ rubyforge_project: validates_immutability
131
+ rubygems_version: 1.3.7
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: Validations for making ActiveRecord objects immutable.
135
+ test_files:
136
+ - spec/lib/validates_immutability/immutable_validator_spec.rb
137
+ - spec/lib/validates_immutability_spec.rb
138
+ - spec/spec_helper.rb