activemodel-error 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/MIT-LICENSE +20 -0
- data/README.textile +87 -0
- data/RakeFile +27 -0
- data/VERSION +1 -0
- data/lib/active_model/attribute_errors.rb +44 -0
- data/lib/active_model/error.rb +13 -0
- data/lib/active_model/error/base.rb +13 -0
- data/lib/active_model/error/format.rb +11 -0
- data/lib/active_model/error/legacy.rb +30 -0
- data/lib/active_model/errors_ext.rb +30 -0
- data/lib/activemodel_error.rb +1 -0
- data/lib/core_ext/error_comparsion.rb +25 -0
- data/test/active_model/format_test.rb +74 -0
- data/test/active_model/interpolation_test.rb +54 -0
- data/test/active_model/lookup_test.rb +99 -0
- data/test/active_model/variants_test.rb +121 -0
- data/test/active_model_test.rb +175 -0
- data/test/all.rb +8 -0
- data/test/run_active_model_tests.rb +32 -0
- data/test/test_case_declarative.rb +23 -0
- data/test/test_helper.rb +29 -0
- metadata +89 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sven Fuchs & Mateo Murphy
|
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
|
+
NONINFRINGEMENT. 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.textile
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
h1. Proposal: validation error messages in ActiveModel
|
2
|
+
|
3
|
+
(requires I18n current master)
|
4
|
+
|
5
|
+
This stuff is a very rough draft of how I propose to deal with validation
|
6
|
+
error messages (and potentially other usecases that need I18n support, such as
|
7
|
+
form labels).
|
8
|
+
|
9
|
+
It might go into Rails or end up in some plugin or gem.
|
10
|
+
|
11
|
+
I'm not looking so much at the actual integration to ActiveModel, yet. So far
|
12
|
+
I'm just trying to sketch out the underlying stuff so that it covers all
|
13
|
+
requirements in a consistent way.
|
14
|
+
|
15
|
+
I want this stuff to be re-usable in other places where similar patterns occur
|
16
|
+
when it comes to I18n, such as form labels and potentially other stuff.
|
17
|
+
|
18
|
+
h2. Problems solved
|
19
|
+
|
20
|
+
* Messages in class method calls are treated as plain text by default
|
21
|
+
(users might optionally want to treat them as translation keys for
|
22
|
+
gettext-style class method calls).
|
23
|
+
* Symbols in class method calls are treated as translation keys.
|
24
|
+
* Use messages from class method calls consistently with translation keys that
|
25
|
+
are implicitly used for a particular validation.
|
26
|
+
* Different translation variants (such as :full_message) for the same message
|
27
|
+
must be possible.
|
28
|
+
* Translation calls should optionally be able to cascade over scopes.
|
29
|
+
* Support format strings, e.g. "{{attribute}} {{message}}", transparently
|
30
|
+
|
31
|
+
h2. Classes
|
32
|
+
|
33
|
+
The Error class is the meant to work as a default Error class in ActiveModel.
|
34
|
+
|
35
|
+
I18n::Message is the main base class and is supposed to work situations such as
|
36
|
+
error messages, form labels etc.
|
37
|
+
|
38
|
+
The Format class is used internally to format other strings (see below).
|
39
|
+
|
40
|
+
h2. Features
|
41
|
+
|
42
|
+
The Message class comes with six modules that each provide a single feature.
|
43
|
+
This way everything's completely optional and pluggable (thus extensible and
|
44
|
+
easy to customize) even though we might choose to not impose this complexity
|
45
|
+
on the enduser (and maybe pick a default configuration/provide a configuration
|
46
|
+
dsl instead).
|
47
|
+
|
48
|
+
h3. I18n::Message::Base
|
49
|
+
|
50
|
+
This module just takes a Message OR translation key (Symbol) and interpolation
|
51
|
+
values. Calling #to_s will use the string or translate the key and interpolate
|
52
|
+
the values. The module is organized in a way so that other modules can hook in
|
53
|
+
easily.
|
54
|
+
|
55
|
+
h3. I18n::Message::Gettext
|
56
|
+
|
57
|
+
This module will also translate Messages. This behavior is frequently asked for
|
58
|
+
by people who want to use Gettext-style translation keys in class-level calls
|
59
|
+
as in validates_presence_of :foo, :message => 'The message'
|
60
|
+
|
61
|
+
h3. I18n::Message::Variants
|
62
|
+
|
63
|
+
This module adds the ability to specify Hashes as strings both at class-level
|
64
|
+
and in translation data. E.g.:
|
65
|
+
|
66
|
+
validates_presence_of :foo, :message => { :short => 'Short!', :full => 'The full message!' }
|
67
|
+
|
68
|
+
Calling #to_s on the I18n::Message instance will take a variant key and try to
|
69
|
+
find and use the variant. It defaults to the :short variant.
|
70
|
+
|
71
|
+
h3. I18n::Message::Formatted
|
72
|
+
|
73
|
+
This module adds the ability to specify format strings both at class-level and
|
74
|
+
in translation data. E.g.:
|
75
|
+
|
76
|
+
validates_presence_of :foo, :format => 'The formatted {{message}}.'
|
77
|
+
|
78
|
+
This module also works in combination with the Variants module in the way one
|
79
|
+
would expect:
|
80
|
+
|
81
|
+
validates_presence_of :foo, :message => { :short => 'foo', :full => 'FOO' }
|
82
|
+
:format => { :full => 'The formatted {{message}}.' }
|
83
|
+
|
84
|
+
message.to_s(:full) would then wrap the :full variant 'FOO' into the :full
|
85
|
+
format string and yield 'The formatted FOO'. message.to_s (defaults to :short)
|
86
|
+
would just yield 'foo' as expected.
|
87
|
+
|
data/RakeFile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
task :default => [:test]
|
4
|
+
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
6
|
+
t.pattern = "#{File.dirname(__FILE__)}/test/all.rb"
|
7
|
+
t.verbose = true
|
8
|
+
end
|
9
|
+
Rake::Task['test'].comment = "Run all tests"
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |s|
|
14
|
+
s.name = "activemodel-error"
|
15
|
+
s.summary = "I18n for validation error messages in ActiveModel"
|
16
|
+
s.description = %(Provides I18n support for validation error messages in ActiveModel.
|
17
|
+
With Rails 3 ActiveModel validation error messages are not backwards
|
18
|
+
compatible with ActiveRecord 2.3.x. This Gem aims to restore this
|
19
|
+
backwards compatiblity and provide a richer feature set and better
|
20
|
+
implementation compared to ActiveRecord 2.3.x.)
|
21
|
+
s.homepage = "http://github.com/svenfuchs/activemodel-error"
|
22
|
+
s.authors = ["Sven Fuchs", "Mateo Murphy"]
|
23
|
+
s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
|
24
|
+
end
|
25
|
+
rescue LoadError
|
26
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
27
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class AttributeErrors
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_accessor :attribute, :errors
|
6
|
+
delegate :size, :empty?, :first, :second, :last, :to => :errors
|
7
|
+
|
8
|
+
def initialize(base, attribute)
|
9
|
+
@base = base
|
10
|
+
@attribute = attribute
|
11
|
+
@errors = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(message = nil, options = {})
|
15
|
+
message = generate_message(message, options) if message.is_a?(Symbol)
|
16
|
+
@errors << message
|
17
|
+
end
|
18
|
+
|
19
|
+
alias :<< :add
|
20
|
+
|
21
|
+
def each
|
22
|
+
@errors.each { |error| yield error }
|
23
|
+
end
|
24
|
+
|
25
|
+
def include?(message)
|
26
|
+
case message
|
27
|
+
when Symbol
|
28
|
+
@errors.any? { |error| error.subject == message }
|
29
|
+
when String
|
30
|
+
@errors.any? { |error| error.to_s == message }
|
31
|
+
else
|
32
|
+
@errors.include?(message)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_message(type = :invalid, options = {})
|
37
|
+
@base.generate_message(attribute, type, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_a
|
41
|
+
@errors
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'i18n/message'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
class Error < I18n::Message
|
5
|
+
autoload :Base, 'active_model/error/base'
|
6
|
+
autoload :Format, 'active_model/error/format'
|
7
|
+
autoload :Legacy, 'active_model/error/legacy'
|
8
|
+
|
9
|
+
include Base, Formatted, Variants, Legacy
|
10
|
+
|
11
|
+
self.format_class = ActiveModel::Error::Format
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class Error < I18n::Message
|
3
|
+
module Base
|
4
|
+
attr_reader :base, :attribute, :value
|
5
|
+
|
6
|
+
def initialize(subject = nil, options = {})
|
7
|
+
@base, @attribute, @value = options.values_at(:model, :attribute, :value)
|
8
|
+
@attribute = attribute
|
9
|
+
super(subject, options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class Error < I18n::Message
|
3
|
+
module Legacy
|
4
|
+
protected
|
5
|
+
|
6
|
+
def translate(subject, options = {})
|
7
|
+
options = translate_options(subject)
|
8
|
+
super(options[:default].shift, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def translate_options(subject)
|
12
|
+
defaults = base.class.lookup_ancestors.map do |klass|
|
13
|
+
[ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{subject}",
|
14
|
+
:"models.#{klass.name.underscore}.#{subject}" ]
|
15
|
+
end.flatten
|
16
|
+
|
17
|
+
defaults << :"messages.#{subject}"
|
18
|
+
|
19
|
+
options = @options.merge(
|
20
|
+
:scope => :errors,
|
21
|
+
:default => defaults,
|
22
|
+
:model => base.class.model_name.human,
|
23
|
+
:attribute => base.class.human_attribute_name(attribute),
|
24
|
+
:value => value,
|
25
|
+
:raise => true
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
2
|
+
require 'active_support/core_ext/module/delegation'
|
3
|
+
require 'active_model'
|
4
|
+
|
5
|
+
module ActiveModel
|
6
|
+
autoload :Error, 'active_model/error'
|
7
|
+
autoload :AttributeErrors, 'active_model/attribute_errors'
|
8
|
+
|
9
|
+
class Errors
|
10
|
+
cattr_accessor :error_class
|
11
|
+
@@error_class = ActiveModel::Error
|
12
|
+
|
13
|
+
def [](attribute)
|
14
|
+
if errors = get(attribute.to_sym)
|
15
|
+
errors
|
16
|
+
else
|
17
|
+
set(attribute.to_sym, AttributeErrors.new(self, attribute.to_sym))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(attribute, message = nil, options = {})
|
22
|
+
self[attribute].add(message, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_message(attribute, type = :invalid, options = {})
|
26
|
+
options.update(:model => @base, :attribute => attribute)
|
27
|
+
error_class.new(options.delete(:default) || type, options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_model/errors_ext'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Array
|
2
|
+
def equals_with_active_model_errors(other)
|
3
|
+
other = other.map { |e| e.to_s } if ActiveModel::AttributeErrors === other
|
4
|
+
equals_without_active_model_errors(other)
|
5
|
+
end
|
6
|
+
alias equals_without_active_model_errors ==
|
7
|
+
alias == equals_with_active_model_errors
|
8
|
+
end
|
9
|
+
|
10
|
+
class Message
|
11
|
+
def equals_with_active_model_error(other)
|
12
|
+
other = other.to_s if ActiveModel::Error === other
|
13
|
+
equals_without_active_model_error(other)
|
14
|
+
end
|
15
|
+
alias equals_without_active_model_error ==
|
16
|
+
alias == equals_with_active_model_error
|
17
|
+
|
18
|
+
def compare_with_active_model_error(other)
|
19
|
+
other = other.to_s if ActiveModel::Error === other
|
20
|
+
compare_without_active_model_error(other)
|
21
|
+
end
|
22
|
+
alias compare_without_active_model_error <=>
|
23
|
+
alias <=> compare_with_active_model_error
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../../test_helper', __FILE__)
|
3
|
+
|
4
|
+
class ActiveModelApiFormatTest < Test::Unit::TestCase
|
5
|
+
class Model
|
6
|
+
include ActiveModel::Validations
|
7
|
+
attr_reader :foo
|
8
|
+
def self.name; 'Model'; end
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
I18n.backend.send(:init_translations) # i.e. don't overwrite our translations
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
I18n.backend = nil
|
17
|
+
Model.reset_callbacks(:validate)
|
18
|
+
end
|
19
|
+
|
20
|
+
def error_on(attribute)
|
21
|
+
model = Model.new
|
22
|
+
model.valid?
|
23
|
+
model.errors[attribute].first
|
24
|
+
end
|
25
|
+
|
26
|
+
# FIXME this currently can't be supported because rails does not pass the
|
27
|
+
# format option through
|
28
|
+
#
|
29
|
+
# test "uses a format given at class level to format a message" do
|
30
|
+
# Model.validates_presence_of :foo, :message => 'message', :format => 'formatted %{message}'
|
31
|
+
# assert_equal "formatted message", error_on(:foo).to_s
|
32
|
+
# end
|
33
|
+
|
34
|
+
test "uses a format stored as a translation to wrap a message (messages namespace)" do
|
35
|
+
Model.validates_presence_of :foo, :message => 'message'
|
36
|
+
store_translations(:'errors.formats.default' => 'formatted %{message}')
|
37
|
+
assert_equal "formatted message", error_on(:foo).to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
# FIXME currently not supported and probably should be optional
|
41
|
+
#
|
42
|
+
# test "uses a format stored as a translation to wrap a message (models namespace)" do
|
43
|
+
# Model.validates_presence_of :foo, :message => 'message'
|
44
|
+
# store_translations(:'errors.formats.models.model.default' => 'formatted %{message}')
|
45
|
+
# assert_equal "formatted message", error_on(:foo).to_s
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# test "uses a format stored as a translation to wrap a message (attributes namespace)" do
|
49
|
+
# Model.validates_presence_of :foo, :message => 'message'
|
50
|
+
# store_translations(:'errors.formats.models.model.attributes.foo.default' => 'formatted %{message}')
|
51
|
+
# assert_equal "formatted message", error_on(:foo).to_s
|
52
|
+
# end
|
53
|
+
|
54
|
+
test "uses a format stored as a translation to wrap a message variant (messages namespace)" do
|
55
|
+
Model.validates_presence_of :foo, :message => 'message'
|
56
|
+
store_translations(:'errors.formats.full' => 'full %{message}')
|
57
|
+
assert_equal "full message", error_on(:foo).to_s(:full)
|
58
|
+
end
|
59
|
+
|
60
|
+
# FIXME currently not supported and probably should be optional
|
61
|
+
#
|
62
|
+
# test "uses a format stored as a translation to wrap a message variant (models namespace)" do
|
63
|
+
# Model.validates_presence_of :foo, :message => 'message'
|
64
|
+
# store_translations(:'errors.formats.models.model.default' => 'formatted %{message}')
|
65
|
+
# assert_equal "formatted message", error_on(:foo).to_s
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# test "uses a format stored as a translation to wrap a message variant (attributes namespace)" do
|
69
|
+
# Model.validates_presence_of :foo, :message => 'message'
|
70
|
+
# store_translations(:'errors.formats.models.model.attributes.foo.default' => 'formatted %{message}')
|
71
|
+
# assert_equal "formatted message", error_on(:foo).to_s
|
72
|
+
# end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../../test_helper', __FILE__)
|
3
|
+
|
4
|
+
class ActiveModelApiInterpolationTest < Test::Unit::TestCase
|
5
|
+
class Model
|
6
|
+
include ActiveModel::Validations
|
7
|
+
attr_reader :foo
|
8
|
+
def self.name; 'Model'; end
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
I18n.backend.send(:init_translations) # i.e. don't overwrite our translations
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
I18n.backend = nil
|
17
|
+
Model.reset_callbacks(:validate)
|
18
|
+
end
|
19
|
+
|
20
|
+
def error_on(attribute)
|
21
|
+
model = Model.new
|
22
|
+
model.valid?
|
23
|
+
model.errors[attribute].first
|
24
|
+
end
|
25
|
+
|
26
|
+
test "interpolates validation data to a translation from the messages namespace" do
|
27
|
+
store_translations(:'errors.models.model.too_short' => '%{count}')
|
28
|
+
Model.validates_length_of :foo, :minimum => 1
|
29
|
+
assert_equal '1', error_on(:foo).to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
test "interpolation: given a class level :message Message it interpolates validation data to the Message" do
|
33
|
+
Model.validates_length_of :foo, :minimum => 1, :message => '%{count}'
|
34
|
+
assert_equal '1', error_on(:foo).to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
test "interpolation: given a class level :message Symbol it interpolates validation data to the Symbol's translation" do
|
38
|
+
store_translations(:'errors.messages.broken' => '%{count}')
|
39
|
+
Model.validates_length_of :foo, :minimum => 1, :message => :broken
|
40
|
+
assert_equal '1', error_on(:foo).to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
test "interpolation: given a class level :message Proc returning a Message it interpolates validation data to the Message" do
|
44
|
+
Model.validates_length_of :foo, :minimum => 1, :message => proc { '%{count}' }
|
45
|
+
assert_equal '1', error_on(:foo).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
test "interpolation: given a class level :message Proc returning a Symbol it interpolates validation data to the Symbol's translation" do
|
49
|
+
store_translations(:'errors.messages.broken' => '%{count}')
|
50
|
+
Model.validates_length_of :foo, :minimum => 1, :message => proc { :broken }
|
51
|
+
assert_equal '1', error_on(:foo).to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../../test_helper', __FILE__)
|
3
|
+
|
4
|
+
class ActiveModelApiLookupTest < Test::Unit::TestCase
|
5
|
+
class Model
|
6
|
+
include ActiveModel::Validations
|
7
|
+
attr_reader :foo
|
8
|
+
def self.name; 'Model'; end
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
I18n.backend.send(:init_translations) # i.e. don't overwrite our translations
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
I18n.backend = nil
|
17
|
+
Model.reset_callbacks(:validate)
|
18
|
+
end
|
19
|
+
|
20
|
+
def error_on(attribute)
|
21
|
+
model = Model.new
|
22
|
+
model.valid?
|
23
|
+
model.errors[attribute].first
|
24
|
+
end
|
25
|
+
|
26
|
+
# LOOKUP
|
27
|
+
|
28
|
+
test "lookup: it returns a translation from the messages namespace" do
|
29
|
+
Model.validates_presence_of :foo
|
30
|
+
store_translations(:'errors.messages.blank' => 'message')
|
31
|
+
assert_equal "message", error_on(:foo).to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
test "lookup: it returns a translation from the model namespace" do
|
35
|
+
Model.validates_presence_of :foo
|
36
|
+
store_translations(:'errors.models.model.blank' => 'message')
|
37
|
+
assert_equal "message", error_on(:foo).to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
test "lookup: it returns a translation from the attribute namespace" do
|
41
|
+
Model.validates_presence_of :foo
|
42
|
+
store_translations(:'errors.models.model.attributes.foo.blank' => 'message')
|
43
|
+
assert_equal "message", error_on(:foo).to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
# given a :message Message in class level validation macros
|
47
|
+
|
48
|
+
test "lookup: given a class level :message Message it returns the Message" do
|
49
|
+
Model.validates_presence_of :foo, :message => 'message'
|
50
|
+
assert_equal 'message', error_on(:foo).to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
# given a :message Symbol in class level validation macros
|
54
|
+
|
55
|
+
test "lookup: given a class level :message Symbol it translates the Symbol (message namespace)" do
|
56
|
+
store_translations(:'errors.messages.broken' => 'translated')
|
57
|
+
Model.validates_presence_of :foo, :message => :broken
|
58
|
+
assert_equal 'translated', error_on(:foo).to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
test "lookup: given a class level :message Symbol it translates the Symbol (model namespace)" do
|
62
|
+
store_translations(:'errors.models.model.broken' => 'translated')
|
63
|
+
Model.validates_presence_of :foo, :message => :broken
|
64
|
+
assert_equal 'translated', error_on(:foo).to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
test "lookup: given a class level :message Symbol it translates the Symbol (attribute namespace)" do
|
68
|
+
store_translations(:'errors.models.model.attributes.foo.broken' => 'translated')
|
69
|
+
Model.validates_presence_of :foo, :message => :broken
|
70
|
+
assert_equal 'translated', error_on(:foo).to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
# given a :message Proc returning a Message in class level validation macros
|
74
|
+
|
75
|
+
test "lookup: given a class level :message Proc returning a Message it returns the Message" do
|
76
|
+
Model.validates_presence_of :foo, :message => proc { 'message' }
|
77
|
+
assert_equal 'message', error_on(:foo).to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
# given a :message Proc returning a Symbol in class level validation macros
|
81
|
+
|
82
|
+
test "lookup: given a class level :message Proc returning a Symbol it translates the Symbol (message namespace)" do
|
83
|
+
store_translations(:'errors.messages.broken' => 'translated')
|
84
|
+
Model.validates_presence_of :foo, :message => proc { :broken }
|
85
|
+
assert_equal 'translated', error_on(:foo).to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
test "lookup: given a class level :message Proc returning a Symbol it translates the Symbol (model namespace)" do
|
89
|
+
store_translations(:'errors.models.model.broken' => 'translated')
|
90
|
+
Model.validates_presence_of :foo, :message => proc { :broken }
|
91
|
+
assert_equal 'translated', error_on(:foo).to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
test "lookup: given a class level :message Proc returning a Symbol it translates the Symbol (attribute namespace)" do
|
95
|
+
store_translations(:'errors.models.model.attributes.foo.broken' => 'translated')
|
96
|
+
Model.validates_presence_of :foo, :message => proc { :broken }
|
97
|
+
assert_equal 'translated', error_on(:foo).to_s
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../../test_helper', __FILE__)
|
3
|
+
|
4
|
+
class ActiveModelApiVariantsTest < Test::Unit::TestCase
|
5
|
+
class Model
|
6
|
+
include ActiveModel::Validations
|
7
|
+
attr_reader :foo
|
8
|
+
def self.name; 'Model'; end
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
I18n.backend.send(:init_translations) # i.e. don't overwrite our translations
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
I18n.backend = nil
|
17
|
+
Model.reset_callbacks(:validate)
|
18
|
+
end
|
19
|
+
|
20
|
+
def error_on(attribute)
|
21
|
+
model = Model.new
|
22
|
+
model.valid?
|
23
|
+
model.errors[attribute].first
|
24
|
+
end
|
25
|
+
|
26
|
+
test "variants: it picks a translation message variant from the messages namespace" do
|
27
|
+
Model.validates_presence_of :foo
|
28
|
+
store_translations(:'errors.messages.blank' => { :short => 'short', :full => 'full' })
|
29
|
+
assert_equal "short", error_on(:foo).to_s
|
30
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
31
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
32
|
+
end
|
33
|
+
|
34
|
+
test "variants: it picks a translation message variant from the models namespace" do
|
35
|
+
Model.validates_presence_of :foo
|
36
|
+
store_translations(:'errors.models.model.blank' => { :short => 'short', :full => 'full' })
|
37
|
+
assert_equal "short", error_on(:foo).to_s
|
38
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
39
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
40
|
+
end
|
41
|
+
|
42
|
+
test "variants: it picks a translation message variant from the attributes namespace" do
|
43
|
+
Model.validates_presence_of :foo
|
44
|
+
store_translations(:'errors.models.model.attributes.foo.blank' => { :short => 'short', :full => 'full' })
|
45
|
+
assert_equal "short", error_on(:foo).to_s
|
46
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
47
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
48
|
+
end
|
49
|
+
|
50
|
+
# given a :message Message in class level validation macros
|
51
|
+
|
52
|
+
test "variants: given a class level :message Hash of Messages it picks a variant" do
|
53
|
+
Model.validates_presence_of :foo, :message => { :short => 'short', :full => 'full' }
|
54
|
+
assert_equal "short", error_on(:foo).to_s
|
55
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
56
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
57
|
+
end
|
58
|
+
|
59
|
+
# given a :message Symbol in class level validation macros
|
60
|
+
|
61
|
+
test "variants: given a class level :message Symbol it translates the Symbol (message namespace) and picks a variant" do
|
62
|
+
store_translations(:'errors.messages.broken' => { :short => 'short', :full => 'full' })
|
63
|
+
Model.validates_presence_of :foo, :message => :broken
|
64
|
+
assert_equal "short", error_on(:foo).to_s
|
65
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
66
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
67
|
+
end
|
68
|
+
|
69
|
+
test "variants: given a class level :message Symbol it translates the Symbol (model namespace) and picks a variant" do
|
70
|
+
store_translations(:'errors.models.model.broken' => { :short => 'short', :full => 'full' })
|
71
|
+
Model.validates_presence_of :foo, :message => :broken
|
72
|
+
assert_equal "short", error_on(:foo).to_s
|
73
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
74
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
75
|
+
end
|
76
|
+
|
77
|
+
test "variants: given a class level :message Symbol it translates the Symbol (attribute namespace) and picks a variant" do
|
78
|
+
store_translations(:'errors.models.model.attributes.foo.broken' => { :short => 'short', :full => 'full' })
|
79
|
+
Model.validates_presence_of :foo, :message => :broken
|
80
|
+
assert_equal "short", error_on(:foo).to_s
|
81
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
82
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
83
|
+
end
|
84
|
+
|
85
|
+
# given a :message Proc returning a Message in class level validation macros
|
86
|
+
|
87
|
+
# FIXME does not pass
|
88
|
+
#
|
89
|
+
# test "variants: given a class level :message Proc returning a Hash of variant Messages it picks a variant" do
|
90
|
+
# Model.validates_presence_of :foo, :message => proc { { :short => 'short', :full => 'full' } }
|
91
|
+
# assert_equal "short", error_on(:foo).to_s
|
92
|
+
# assert_equal "short", error_on(:foo).to_s(:short)
|
93
|
+
# assert_equal "full", error_on(:foo).to_s(:full)
|
94
|
+
# end
|
95
|
+
|
96
|
+
# given a :message Proc returning a Symbol in class level validation macros
|
97
|
+
|
98
|
+
test "variants: given a class level :message Proc returning a Symbol it translates the Symbol (message namespace) and picks a variant" do
|
99
|
+
store_translations(:'errors.messages.broken' => { :short => 'short', :full => 'full' })
|
100
|
+
Model.validates_presence_of :foo, :message => proc { :broken }
|
101
|
+
assert_equal "short", error_on(:foo).to_s
|
102
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
103
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
104
|
+
end
|
105
|
+
|
106
|
+
test "variants: given a class level :message Proc returning a Symbol it translates the Symbol (model namespace) and picks a variant" do
|
107
|
+
store_translations(:'errors.models.model.broken' => { :short => 'short', :full => 'full' })
|
108
|
+
Model.validates_presence_of :foo, :message => proc { :broken }
|
109
|
+
assert_equal "short", error_on(:foo).to_s
|
110
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
111
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
112
|
+
end
|
113
|
+
|
114
|
+
test "variants: given a class level :message Proc returning a Symbol it translates the Symbol (attribute namespace) and picks a variant" do
|
115
|
+
store_translations(:'errors.models.model.attributes.foo.broken' => { :short => 'short', :full => 'full' })
|
116
|
+
Model.validates_presence_of :foo, :message => proc { :broken }
|
117
|
+
assert_equal "short", error_on(:foo).to_s
|
118
|
+
assert_equal "short", error_on(:foo).to_s(:short)
|
119
|
+
assert_equal "full", error_on(:foo).to_s(:full)
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
3
|
+
|
4
|
+
$:.unshift('~/Development/shared/rails/rails-master/activemodel/lib')
|
5
|
+
$:.unshift('~/Development/shared/rails/rails-master/activesupport/lib')
|
6
|
+
$:.unshift('~/Projects/Ruby/rails/activemodel/lib')
|
7
|
+
$:.unshift('~/Projects/Ruby/rails/activesupport/lib')
|
8
|
+
|
9
|
+
require 'active_model/errors_ext'
|
10
|
+
|
11
|
+
class Model
|
12
|
+
include ActiveModel::Validations
|
13
|
+
attr_reader :foo
|
14
|
+
end
|
15
|
+
|
16
|
+
module ActiveModelValidationMessageTestSetup
|
17
|
+
|
18
|
+
def setup
|
19
|
+
I18n.backend = CascadingBackend.new
|
20
|
+
I18n.backend.send(:init_translations) # so our translations won't be overwritten by Rails
|
21
|
+
end
|
22
|
+
|
23
|
+
def teardown
|
24
|
+
I18n.backend = nil
|
25
|
+
Model.reset_callbacks(:validate)
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def model
|
30
|
+
model = Model.new
|
31
|
+
model.valid?
|
32
|
+
model
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class LegacyActiveModelValidationMessageTest < Test::Unit::TestCase
|
38
|
+
include ActiveModelValidationMessageTestSetup
|
39
|
+
|
40
|
+
class Error < ActiveModel::Error
|
41
|
+
include Legacy
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup
|
45
|
+
super
|
46
|
+
ActiveModel::Errors.error_class = Error
|
47
|
+
end
|
48
|
+
|
49
|
+
test "uses a translation from the messages namespace" do
|
50
|
+
Model.validates_presence_of :foo
|
51
|
+
store_translations(:'errors.messages.blank' => 'message')
|
52
|
+
assert_equal "message", model.errors[:foo].first.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
test "uses a translation from the messages namespace with a Proc" do
|
56
|
+
Model.validates_presence_of :foo, :message => proc { :foo }
|
57
|
+
store_translations(:'errors.messages.foo' => 'message')
|
58
|
+
assert_equal "message", model.errors[:foo].first.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
test "uses a translation from a model namespace" do
|
62
|
+
Model.validates_presence_of :foo
|
63
|
+
store_translations(:'errors.models.model.blank' => 'message')
|
64
|
+
assert_equal "message", model.errors[:foo].first.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
test "uses a translation from an attribute namespace" do
|
68
|
+
Model.validates_presence_of :foo
|
69
|
+
store_translations(:'errors.models.model.attributes.foo.blank' => 'message')
|
70
|
+
assert_equal "message", model.errors[:foo].first.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
test "interpolates validation data to a default message" do
|
74
|
+
Model.validates_length_of :foo, :minimum => 1
|
75
|
+
assert_equal "is too short (minimum is 1 characters)", model.errors[:foo].first.to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
test "AttributeErrors supports common methods" do
|
79
|
+
store_translations(:'errors.messages.blank' => 'message')
|
80
|
+
|
81
|
+
errors = model.errors[:foo]
|
82
|
+
assert errors.empty?
|
83
|
+
assert !errors.any?
|
84
|
+
|
85
|
+
errors << :blank
|
86
|
+
assert !errors.empty?
|
87
|
+
assert errors.any?
|
88
|
+
assert errors.include?(:blank)
|
89
|
+
assert errors.include?("message")
|
90
|
+
assert_equal "message", errors.first.to_s
|
91
|
+
end
|
92
|
+
|
93
|
+
test "errors added directly to AttributeErrors are accesible via Errors" do
|
94
|
+
foo = model
|
95
|
+
foo.errors[:bar] << :blank
|
96
|
+
|
97
|
+
assert_equal 1, foo.errors.size
|
98
|
+
assert_equal ['Bar can\'t be blank'], foo.errors.to_a
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
=begin
|
103
|
+
test "uses translation message formats from a model namespace" do
|
104
|
+
Model.validates_presence_of :foo
|
105
|
+
store_translations(:'errors.models.model.blank' => { :short => 'short', :full => 'full' })
|
106
|
+
assert_equal "short", model.errors[:foo].first.to_s
|
107
|
+
assert_equal "short", model.errors[:foo].first.to_s(:short)
|
108
|
+
assert_equal "full", model.errors[:foo].first.to_s(:full)
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
test "uses translation message formats from an attribute namespace" do
|
113
|
+
Model.validates_presence_of :foo
|
114
|
+
store_translations(:'errors.models.model.attributes.foo.blank' => { :short => 'short', :full => 'full' })
|
115
|
+
assert_equal "short", model.errors[:foo].first.to_s
|
116
|
+
assert_equal "short", model.errors[:foo].first.to_s(:short)
|
117
|
+
assert_equal "full", model.errors[:foo].first.to_s(:full)
|
118
|
+
end
|
119
|
+
=end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
class ActiveModelValidationMessageTest < Test::Unit::TestCase
|
124
|
+
|
125
|
+
include ActiveModelValidationMessageTestSetup
|
126
|
+
|
127
|
+
class Error < ActiveModel::Error
|
128
|
+
include Cascade, Variants, Formatted
|
129
|
+
|
130
|
+
self.cascade_options = { :step => 2, :skip_root => false, :scopes => [:model, :attribute] }
|
131
|
+
end
|
132
|
+
|
133
|
+
def setup
|
134
|
+
super
|
135
|
+
ActiveModel::Errors.error_class = Error
|
136
|
+
end
|
137
|
+
|
138
|
+
test "uses a class level Message message" do
|
139
|
+
Model.validates_presence_of :foo, :message => 'message'
|
140
|
+
assert_equal "message", model.errors[:foo].first.to_s
|
141
|
+
end
|
142
|
+
|
143
|
+
test "uses a class level Proc message" do
|
144
|
+
Model.validates_presence_of :foo, :message => proc {'message'}
|
145
|
+
assert_equal "message", model.errors[:foo].first.to_s
|
146
|
+
end
|
147
|
+
|
148
|
+
test "uses class level Message message formats" do
|
149
|
+
Model.validates_presence_of :foo, :message => { :short => 'short', :full => 'full'}
|
150
|
+
assert_equal "short", model.errors[:foo].first.to_s
|
151
|
+
assert_equal "short", model.errors[:foo].first.to_s(:short)
|
152
|
+
assert_equal "full", model.errors[:foo].first.to_s(:full)
|
153
|
+
end
|
154
|
+
|
155
|
+
=begin
|
156
|
+
test "uses translation message formats the messages namespace" do
|
157
|
+
Model.validates_presence_of :foo
|
158
|
+
store_translations(:'errors.messages.blank' => { :short => 'short', :full => 'full' })
|
159
|
+
assert_equal "short", model.errors[:foo].first.to_s
|
160
|
+
assert_equal "short", model.errors[:foo].first.to_s(:short)
|
161
|
+
assert_equal "full", model.errors[:foo].first.to_s(:full)
|
162
|
+
end
|
163
|
+
=end
|
164
|
+
|
165
|
+
test "interpolates validation data to a class level Message message" do
|
166
|
+
Model.validates_length_of :foo, :minimum => 1, :message => '%{count}'
|
167
|
+
assert_equal "1", model.errors[:foo].first.to_s
|
168
|
+
end
|
169
|
+
|
170
|
+
test "returns an instance of AttributeErrors" do
|
171
|
+
Model.validates_presence_of :foo
|
172
|
+
assert model.errors[:foo].is_a?(ActiveModel::AttributeErrors)
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
data/test/all.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# setup:
|
2
|
+
#
|
3
|
+
# git clone rails
|
4
|
+
# gem install bundler
|
5
|
+
# gem bundle (i had to comment out gem "pg", ">= 0.8.0" from rails/Gemfile)
|
6
|
+
# cd activemodel
|
7
|
+
# rake
|
8
|
+
# => should run the activemodel tests (outputs a ton of warnings for me)
|
9
|
+
#
|
10
|
+
# update line the following line, then running this file should run validations tests
|
11
|
+
|
12
|
+
dirs = %w(
|
13
|
+
~/Development/shared/rails/rails-master/activemodel
|
14
|
+
~/Projects/Ruby/rails/activemodel/
|
15
|
+
).map { |dir| File.expand_path(dir) }
|
16
|
+
|
17
|
+
dirs.each { |dir| $:.unshift "#{dir}/lib", "#{dir}/test" }
|
18
|
+
$:.unshift('~/Projects/Ruby/rails/activesupport/lib')
|
19
|
+
|
20
|
+
require File.expand_path('../test_helper', __FILE__)
|
21
|
+
require 'active_model/errors_ext'
|
22
|
+
require 'core_ext/error_comparsion'
|
23
|
+
|
24
|
+
class ActiveModel::Error
|
25
|
+
include Legacy
|
26
|
+
end
|
27
|
+
|
28
|
+
tests = dirs.map { |dir| Dir["#{dir}/test/cases/validations{/**/*,}_test.rb"] }.flatten
|
29
|
+
# tests = Dir["#{dir}/test/cases/validations_test.rb"]
|
30
|
+
# tests.reject! { |test| test.include?('i18n_validation_test.rb') }
|
31
|
+
tests.each { |test| require test }
|
32
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Declarative
|
2
|
+
def self.included(base)
|
3
|
+
base.class_eval do
|
4
|
+
def test(name, &block)
|
5
|
+
name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
6
|
+
block ||= lambda { flunk "No implementation provided for #{name}" }
|
7
|
+
|
8
|
+
defined = instance_method(name) rescue false
|
9
|
+
raise("#{name} is already defined in #{self}") if defined
|
10
|
+
|
11
|
+
define_method(name, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
include Declarative
|
19
|
+
end
|
20
|
+
|
21
|
+
class Module
|
22
|
+
include Declarative
|
23
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# FIXME personal load paths
|
2
|
+
$:.unshift('~/Development/shared/rails/rails-master/activemodel/lib')
|
3
|
+
$:.unshift('~/Development/shared/rails/rails-master/activesupport/lib')
|
4
|
+
$:.unshift('~/Projects/Ruby/rails/activemodel/lib')
|
5
|
+
$:.unshift('~/Projects/Ruby/rails/activesupport/lib')
|
6
|
+
|
7
|
+
|
8
|
+
$:.unshift File.expand_path("../lib", File.dirname(__FILE__))
|
9
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__)))
|
10
|
+
|
11
|
+
require 'rubygems'
|
12
|
+
require 'test/unit'
|
13
|
+
require 'test_case_declarative'
|
14
|
+
|
15
|
+
require 'activemodel_error'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
def teardown
|
19
|
+
I18n.backend = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def store_translations(data)
|
23
|
+
I18n.backend.store_translations(:en, data)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class CascadingBackend < I18n::Backend::Simple
|
28
|
+
include I18n::Backend::Cascade
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activemodel-error
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sven Fuchs
|
8
|
+
- Mateo Murphy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-02-25 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: |-
|
18
|
+
Provides I18n support for validation error messages in ActiveModel.
|
19
|
+
With Rails 3 ActiveModel validation error messages are not backwards
|
20
|
+
compatible with ActiveRecord 2.3.x. This Gem aims to restore this
|
21
|
+
backwards compatiblity and provide a richer feature set and better
|
22
|
+
implementation compared to ActiveRecord 2.3.x.
|
23
|
+
email:
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.textile
|
30
|
+
files:
|
31
|
+
- MIT-LICENSE
|
32
|
+
- README.textile
|
33
|
+
- RakeFile
|
34
|
+
- VERSION
|
35
|
+
- lib/active_model/attribute_errors.rb
|
36
|
+
- lib/active_model/error.rb
|
37
|
+
- lib/active_model/error/base.rb
|
38
|
+
- lib/active_model/error/format.rb
|
39
|
+
- lib/active_model/error/legacy.rb
|
40
|
+
- lib/active_model/errors_ext.rb
|
41
|
+
- lib/activemodel_error.rb
|
42
|
+
- lib/core_ext/error_comparsion.rb
|
43
|
+
- test/active_model/format_test.rb
|
44
|
+
- test/active_model/interpolation_test.rb
|
45
|
+
- test/active_model/lookup_test.rb
|
46
|
+
- test/active_model/variants_test.rb
|
47
|
+
- test/active_model_test.rb
|
48
|
+
- test/all.rb
|
49
|
+
- test/run_active_model_tests.rb
|
50
|
+
- test/test_case_declarative.rb
|
51
|
+
- test/test_helper.rb
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://github.com/svenfuchs/activemodel-error
|
54
|
+
licenses: []
|
55
|
+
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options:
|
58
|
+
- --charset=UTF-8
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.3.5
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: I18n for validation error messages in ActiveModel
|
80
|
+
test_files:
|
81
|
+
- test/active_model/format_test.rb
|
82
|
+
- test/active_model/interpolation_test.rb
|
83
|
+
- test/active_model/lookup_test.rb
|
84
|
+
- test/active_model/variants_test.rb
|
85
|
+
- test/active_model_test.rb
|
86
|
+
- test/all.rb
|
87
|
+
- test/run_active_model_tests.rb
|
88
|
+
- test/test_case_declarative.rb
|
89
|
+
- test/test_helper.rb
|