active_model-better_errors 1.6.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/.document +5 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +20 -0
- data/README.md +183 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/active_model-better_errors.gemspec +113 -0
- data/lib/active_model/better_errors.rb +15 -0
- data/lib/active_model/error_collecting.rb +49 -0
- data/lib/active_model/error_collecting/array_reporter.rb +9 -0
- data/lib/active_model/error_collecting/core_ext.rb +6 -0
- data/lib/active_model/error_collecting/emulation.rb +65 -0
- data/lib/active_model/error_collecting/error_collection.rb +86 -0
- data/lib/active_model/error_collecting/error_message.rb +88 -0
- data/lib/active_model/error_collecting/error_message_set.rb +35 -0
- data/lib/active_model/error_collecting/errors.rb +52 -0
- data/lib/active_model/error_collecting/hash_reporter.rb +9 -0
- data/lib/active_model/error_collecting/human_array_reporter.rb +9 -0
- data/lib/active_model/error_collecting/human_hash_reporter.rb +15 -0
- data/lib/active_model/error_collecting/human_message_formatter.rb +60 -0
- data/lib/active_model/error_collecting/human_message_reporter.rb +32 -0
- data/lib/active_model/error_collecting/machine_array_reporter.rb +19 -0
- data/lib/active_model/error_collecting/machine_hash_reporter.rb +22 -0
- data/lib/active_model/error_collecting/message_reporter.rb +17 -0
- data/lib/active_model/error_collecting/reporter.rb +14 -0
- data/spec/lib/active_model/better_errors_spec.rb +7 -0
- data/spec/lib/active_model/error_collecting/emulation_spec.rb +45 -0
- data/spec/lib/active_model/error_collecting/error_collection_spec.rb +205 -0
- data/spec/lib/active_model/error_collecting/error_message_set_spec.rb +96 -0
- data/spec/lib/active_model/error_collecting/error_message_spec.rb +293 -0
- data/spec/lib/active_model/error_collecting/errors_spec.rb +95 -0
- data/spec/lib/active_model/error_collecting/human_array_reporter_spec.rb +33 -0
- data/spec/lib/active_model/error_collecting/human_hash_reporter_spec.rb +32 -0
- data/spec/lib/active_model/error_collecting/human_message_formatter_spec.rb +22 -0
- data/spec/lib/active_model/error_collecting/human_message_reporter_spec.rb +61 -0
- data/spec/lib/active_model/error_collecting/machine_array_reporter_spec.rb +40 -0
- data/spec/lib/active_model/error_collecting/machine_hash_reporter_spec.rb +40 -0
- data/spec/lib/active_model/error_collecting_spec.rb +22 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/models.rb +28 -0
- data/test/integration.rb +10 -0
- metadata +274 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module ErrorCollecting
|
3
|
+
class HumanMessageReporter < MessageReporter
|
4
|
+
def full_messages
|
5
|
+
@collection.map do |attribute, error_message|
|
6
|
+
formatter = HumanMessageFormatter.new(base, error_message)
|
7
|
+
message = formatter.format_message
|
8
|
+
full_message attribute, message
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def full_message(attribute, message)
|
13
|
+
return message if attribute == :base
|
14
|
+
attr_name = attribute.to_s.gsub('.', '_').humanize
|
15
|
+
attr_name = base.class.human_attribute_name(attribute, :default => attr_name)
|
16
|
+
I18n.t(:"errors.format", {
|
17
|
+
:default => "%{attribute} %{message}",
|
18
|
+
:attribute => attr_name,
|
19
|
+
:message => message
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
# This method is not used internally.
|
24
|
+
# This is for API Compatibility with ActiveModel::Errors only
|
25
|
+
def generate_message(attribute, type = :invalid, options = {})
|
26
|
+
error_message = ErrorMessage.build(base, attribute, type, options)
|
27
|
+
formatter = HumanMessageFormatter.new(base, error_message)
|
28
|
+
formatter.format_message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module ErrorCollecting
|
3
|
+
class MachineArrayReporter < ArrayReporter
|
4
|
+
def to_a
|
5
|
+
collection.to_a.map do |error_message|
|
6
|
+
format_error_message error_message
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def format_error_message(error_message)
|
11
|
+
result = {}
|
12
|
+
result[:attribute] = error_message.attribute.to_s
|
13
|
+
result[:type] = error_message.type || :invalid
|
14
|
+
result[:options] = error_message.options unless error_message.options.blank?
|
15
|
+
result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module ErrorCollecting
|
3
|
+
class MachineHashReporter < HashReporter
|
4
|
+
def to_hash
|
5
|
+
collection.to_hash.inject({}) do |hash, kv|
|
6
|
+
attribute, error_message_set = kv
|
7
|
+
hash[attribute] = error_message_set.map do |error_message|
|
8
|
+
format_error_message(error_message)
|
9
|
+
end
|
10
|
+
hash
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_error_message(error_message)
|
15
|
+
result = {}
|
16
|
+
result[:type] = error_message.type || :invalid
|
17
|
+
result[:options] = error_message.options unless error_message.options.blank?
|
18
|
+
result
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module ErrorCollecting
|
3
|
+
class MessageReporter < Reporter
|
4
|
+
def full_messages
|
5
|
+
raise "abstract method"
|
6
|
+
end
|
7
|
+
|
8
|
+
def full_message(attribute, message)
|
9
|
+
raise "abstract method"
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_message(attribute, type = :invalid, options = {})
|
13
|
+
raise "abstract method"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for "a delegated method" do
|
4
|
+
let(:target_instance) { mock() }
|
5
|
+
before do
|
6
|
+
target_instance.should_receive method
|
7
|
+
instance.stub(target).and_return(target_instance)
|
8
|
+
end
|
9
|
+
|
10
|
+
specify { instance.send method }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ActiveModel::ErrorCollecting::Emulation do
|
14
|
+
subject(:instance) { klass.new }
|
15
|
+
let(:klass) { Class.new { include ActiveModel::ErrorCollecting::Emulation } }
|
16
|
+
|
17
|
+
delegation_map = {
|
18
|
+
error_collection: [
|
19
|
+
:clear, :include?, :get, :set, :delete, :[], :[]=, :each, :size,
|
20
|
+
:values, :keys, :count, :empty?, :added?, :any?, :entries
|
21
|
+
],
|
22
|
+
|
23
|
+
message_reporter: [
|
24
|
+
:full_messages, :full_message, :generate_message
|
25
|
+
],
|
26
|
+
|
27
|
+
hash_reporter: [
|
28
|
+
:to_hash
|
29
|
+
],
|
30
|
+
|
31
|
+
hash_reporter: [
|
32
|
+
:to_hash
|
33
|
+
]
|
34
|
+
}
|
35
|
+
|
36
|
+
delegation_map.each do |target, methods|
|
37
|
+
methods.each do |method|
|
38
|
+
describe "delegating ##{method} to ##{target}" do
|
39
|
+
let(:target) { target }
|
40
|
+
let(:method) { method }
|
41
|
+
it_should_behave_like "a delegated method"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveModel::ErrorCollecting::ErrorCollection do
|
4
|
+
subject(:collection) { klass.new(base) }
|
5
|
+
let(:klass) { ActiveModel::ErrorCollecting::ErrorCollection }
|
6
|
+
let(:base) { User.new }
|
7
|
+
let(:errors){{
|
8
|
+
:first_name => [ [ :too_long, { count: 3 } ] ],
|
9
|
+
'last_name' => [ [ :invalid, { message: "Invalid" } ] ],
|
10
|
+
:email => [ :invalid ],
|
11
|
+
}}
|
12
|
+
|
13
|
+
before do
|
14
|
+
errors.each do |attribute, error_list|
|
15
|
+
error_list.each do |error|
|
16
|
+
collection[attribute] = error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#clear" do
|
22
|
+
before { collection.clear }
|
23
|
+
it { should be_empty }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#include?" do
|
27
|
+
it { should be_include :first_name }
|
28
|
+
it { should be_include :last_name }
|
29
|
+
it { should be_include :email }
|
30
|
+
it { should_not be_include 'first_name' }
|
31
|
+
it { should_not be_include 'last_name' }
|
32
|
+
it { should_not be_include 'email' }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#get" do
|
36
|
+
subject { collection.get(:first_name) }
|
37
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessageSet }
|
38
|
+
its(:length) { should be 1 }
|
39
|
+
|
40
|
+
describe "when value is nil" do
|
41
|
+
before { collection.delete :first_name }
|
42
|
+
it { should be nil }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#set" do
|
47
|
+
subject { collection.get :first_name }
|
48
|
+
|
49
|
+
describe "when value is array" do
|
50
|
+
before { collection.set(:first_name, []) }
|
51
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessageSet }
|
52
|
+
its(:length) { should be 0 }
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "when value is nil" do
|
56
|
+
before { collection.set(:first_name, nil) }
|
57
|
+
it { should be_nil }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#delete" do
|
62
|
+
subject { collection.get(:first_name) }
|
63
|
+
before { collection.delete(:first_name) }
|
64
|
+
it { should be_nil }
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#[]" do
|
68
|
+
subject { collection[:first_name] }
|
69
|
+
|
70
|
+
describe "when no error messages" do
|
71
|
+
before { collection.clear }
|
72
|
+
it { should be_blank }
|
73
|
+
it { should_not be_nil }
|
74
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessageSet }
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "when there are error messages" do
|
78
|
+
it { should_not be_blank }
|
79
|
+
it { should_not be_nil }
|
80
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessageSet }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#[]=" do
|
85
|
+
subject(:error_message_set) { collection.get field }
|
86
|
+
|
87
|
+
describe "when assigning existing attribute" do
|
88
|
+
let(:field) { :first_name }
|
89
|
+
it "should append to existing set" do
|
90
|
+
expect {
|
91
|
+
collection[field] = "I'm invalid."
|
92
|
+
}.to change { error_message_set.length }.by(1)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "when assigning to new attribute" do
|
97
|
+
let(:field) { :a_new_attribute }
|
98
|
+
before { collection[field] = "I'm invalid" }
|
99
|
+
it { should_not be_nil }
|
100
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessageSet }
|
101
|
+
its(:length) { should be 1 }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#each" do
|
106
|
+
it "should loop through each error" do
|
107
|
+
count = 0
|
108
|
+
collection.each do |attribute, error|
|
109
|
+
attribute.should be_a Symbol
|
110
|
+
error.should be_a ActiveModel::ErrorCollecting::ErrorMessage
|
111
|
+
count += 1
|
112
|
+
end
|
113
|
+
|
114
|
+
expect(count).to be collection.size
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#size" do
|
119
|
+
subject { collection.size }
|
120
|
+
it { should be 3 }
|
121
|
+
|
122
|
+
describe "when adding one more error" do
|
123
|
+
before { collection[:name] = "Not Valid" }
|
124
|
+
it { should be 4 }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#values" do
|
129
|
+
subject { collection.values }
|
130
|
+
|
131
|
+
it { should be_a Array }
|
132
|
+
its(:length) { should be 3 }
|
133
|
+
|
134
|
+
it "should contain ErrorMessageSet as elements" do
|
135
|
+
collection.values.each do |el|
|
136
|
+
el.should be_a ActiveModel::ErrorCollecting::ErrorMessageSet
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "#keys" do
|
142
|
+
subject { collection.keys }
|
143
|
+
it { should == [:first_name, :last_name, :email] }
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "#to_a" do
|
147
|
+
subject { collection.to_a }
|
148
|
+
its(:size) { should == 3 }
|
149
|
+
|
150
|
+
describe "when adding one more error" do
|
151
|
+
before { collection[:name] = "Not Valid" }
|
152
|
+
its(:size) { should == 4 }
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should contain ErrorMessage as elements" do
|
156
|
+
collection.to_a.each do |error|
|
157
|
+
error.should be_a ActiveModel::ErrorCollecting::ErrorMessage
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "#to_hash" do
|
163
|
+
subject { collection.to_hash }
|
164
|
+
|
165
|
+
it { should be_a Hash }
|
166
|
+
it { should == collection.instance_variable_get(:@collection) }
|
167
|
+
it { should_not be collection.instance_variable_get(:@collection) }
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "#empty?" do
|
171
|
+
subject { collection.empty? }
|
172
|
+
it{ should be false }
|
173
|
+
|
174
|
+
describe "after clearing the collection" do
|
175
|
+
before { collection.clear }
|
176
|
+
|
177
|
+
it { should be true }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "#add" do
|
182
|
+
it "should add error to collection" do
|
183
|
+
expect {
|
184
|
+
collection.add :name, "Invalid"
|
185
|
+
}.to change { collection[:name].length }.by(1)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "#added?" do
|
190
|
+
describe "when an error message is not added" do
|
191
|
+
subject { collection.added? :name, :not_there }
|
192
|
+
it { should be false }
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "when an error message with the same option is added" do
|
196
|
+
subject { collection.added? :first_name, :too_long, { :count => 3 } }
|
197
|
+
it { should be true }
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "when an error message with the different option is added" do
|
201
|
+
subject { collection.added? :first_name, :too_long, { :count => 4 } }
|
202
|
+
it { should be false }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveModel::ErrorCollecting::ErrorMessageSet do
|
4
|
+
subject(:set) { klass.new base, attribute, errors }
|
5
|
+
let(:klass) { ActiveModel::ErrorCollecting::ErrorMessageSet }
|
6
|
+
let(:attribute) { :first_name }
|
7
|
+
let(:errors) { [] }
|
8
|
+
let(:base) { User.new }
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
context "with no errors" do
|
12
|
+
its(:length) { should == 0 }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "with one error" do
|
16
|
+
let(:errors) { [:invalid] }
|
17
|
+
its(:length) { should == 1 }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#push" do
|
22
|
+
before { set.push error, options }
|
23
|
+
let(:error) { :invalid }
|
24
|
+
let(:options) { nil }
|
25
|
+
subject { set.first }
|
26
|
+
|
27
|
+
describe "without options" do
|
28
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessage }
|
29
|
+
its(:message) { should == nil }
|
30
|
+
its(:type) { should == error }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "with options" do
|
34
|
+
let(:options) { { message: 'Invalid' } }
|
35
|
+
|
36
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessage }
|
37
|
+
its(:message) { should == options[:message] }
|
38
|
+
its(:type) { should == error }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#<<" do
|
43
|
+
before { set << error }
|
44
|
+
subject { set.first }
|
45
|
+
|
46
|
+
describe "when accepting error as a symbol" do
|
47
|
+
let(:error) { :invalid }
|
48
|
+
|
49
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessage }
|
50
|
+
its(:message) { should == nil }
|
51
|
+
its(:type) { should == error }
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "when accepting error as a tuple" do
|
55
|
+
let(:error) { [ :invalid, { message: "OMG!!" } ]}
|
56
|
+
|
57
|
+
it { should be_a ActiveModel::ErrorCollecting::ErrorMessage }
|
58
|
+
its(:message) { should == "OMG!!" }
|
59
|
+
its(:type) { should == :invalid }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#to_a" do
|
64
|
+
let(:errors) { [:invalid, :too_long] }
|
65
|
+
subject { set.to_a }
|
66
|
+
|
67
|
+
it { should be_a Array }
|
68
|
+
its(:length) { should == 2 }
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#empty?" do
|
72
|
+
subject { set.empty? }
|
73
|
+
|
74
|
+
describe "when no error messages" do
|
75
|
+
it { should be_true }
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "when contains error messages" do
|
79
|
+
let(:errors) { [:invalid, :too_long] }
|
80
|
+
it { should be_false }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#==" do
|
85
|
+
subject { errors == set }
|
86
|
+
let(:errors) { [:invalid] }
|
87
|
+
let(:expected) { ["is invalid"] }
|
88
|
+
specify do
|
89
|
+
set.should == expected
|
90
|
+
end
|
91
|
+
|
92
|
+
specify do
|
93
|
+
expected.should == set
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|