cassandra_object 0.6.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cassandra_object/associations/one_to_many.rb +136 -0
- data/lib/cassandra_object/associations/one_to_one.rb +77 -0
- data/lib/cassandra_object/associations.rb +35 -0
- data/lib/cassandra_object/attributes.rb +93 -0
- data/lib/cassandra_object/base.rb +104 -0
- data/lib/cassandra_object/callbacks.rb +10 -0
- data/lib/cassandra_object/collection.rb +8 -0
- data/lib/cassandra_object/cursor.rb +86 -0
- data/lib/cassandra_object/dirty.rb +27 -0
- data/lib/cassandra_object/identity/abstract_key_factory.rb +36 -0
- data/lib/cassandra_object/identity/key.rb +20 -0
- data/lib/cassandra_object/identity/natural_key_factory.rb +51 -0
- data/lib/cassandra_object/identity/uuid_key_factory.rb +37 -0
- data/lib/cassandra_object/identity.rb +61 -0
- data/lib/cassandra_object/indexes.rb +129 -0
- data/lib/cassandra_object/legacy_callbacks.rb +33 -0
- data/lib/cassandra_object/migrations.rb +72 -0
- data/lib/cassandra_object/mocking.rb +15 -0
- data/lib/cassandra_object/persistence.rb +193 -0
- data/lib/cassandra_object/serialization.rb +6 -0
- data/lib/cassandra_object/type_registration.rb +7 -0
- data/lib/cassandra_object/types.rb +128 -0
- data/lib/cassandra_object/validation.rb +58 -0
- data/lib/cassandra_object.rb +30 -0
- data/vendor/active_support_shims.rb +4 -0
- data/vendor/activemodel/CHANGELOG +13 -0
- data/vendor/activemodel/CHANGES +12 -0
- data/vendor/activemodel/MIT-LICENSE +21 -0
- data/vendor/activemodel/README +21 -0
- data/vendor/activemodel/Rakefile +52 -0
- data/vendor/activemodel/activemodel.gemspec +19 -0
- data/vendor/activemodel/examples/validations.rb +29 -0
- data/vendor/activemodel/lib/active_model/attribute_methods.rb +291 -0
- data/vendor/activemodel/lib/active_model/callbacks.rb +91 -0
- data/vendor/activemodel/lib/active_model/conversion.rb +8 -0
- data/vendor/activemodel/lib/active_model/deprecated_error_methods.rb +33 -0
- data/vendor/activemodel/lib/active_model/dirty.rb +126 -0
- data/vendor/activemodel/lib/active_model/errors.rb +162 -0
- data/vendor/activemodel/lib/active_model/lint.rb +91 -0
- data/vendor/activemodel/lib/active_model/locale/en.yml +27 -0
- data/vendor/activemodel/lib/active_model/naming.rb +45 -0
- data/vendor/activemodel/lib/active_model/observing.rb +191 -0
- data/vendor/activemodel/lib/active_model/railtie.rb +2 -0
- data/vendor/activemodel/lib/active_model/serialization.rb +30 -0
- data/vendor/activemodel/lib/active_model/serializers/json.rb +96 -0
- data/vendor/activemodel/lib/active_model/serializers/xml.rb +204 -0
- data/vendor/activemodel/lib/active_model/state_machine/event.rb +62 -0
- data/vendor/activemodel/lib/active_model/state_machine/machine.rb +75 -0
- data/vendor/activemodel/lib/active_model/state_machine/state.rb +47 -0
- data/vendor/activemodel/lib/active_model/state_machine/state_transition.rb +40 -0
- data/vendor/activemodel/lib/active_model/state_machine.rb +70 -0
- data/vendor/activemodel/lib/active_model/test_case.rb +18 -0
- data/vendor/activemodel/lib/active_model/translation.rb +44 -0
- data/vendor/activemodel/lib/active_model/validations/acceptance.rb +55 -0
- data/vendor/activemodel/lib/active_model/validations/confirmation.rb +47 -0
- data/vendor/activemodel/lib/active_model/validations/exclusion.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/format.rb +64 -0
- data/vendor/activemodel/lib/active_model/validations/inclusion.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/length.rb +117 -0
- data/vendor/activemodel/lib/active_model/validations/numericality.rb +111 -0
- data/vendor/activemodel/lib/active_model/validations/presence.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/with.rb +59 -0
- data/vendor/activemodel/lib/active_model/validations.rb +120 -0
- data/vendor/activemodel/lib/active_model/validator.rb +110 -0
- data/vendor/activemodel/lib/active_model/version.rb +9 -0
- data/vendor/activemodel/lib/active_model.rb +61 -0
- data/vendor/activemodel/test/cases/attribute_methods_test.rb +46 -0
- data/vendor/activemodel/test/cases/callbacks_test.rb +70 -0
- data/vendor/activemodel/test/cases/helper.rb +23 -0
- data/vendor/activemodel/test/cases/lint_test.rb +28 -0
- data/vendor/activemodel/test/cases/naming_test.rb +28 -0
- data/vendor/activemodel/test/cases/observing_test.rb +133 -0
- data/vendor/activemodel/test/cases/serializeration/json_serialization_test.rb +83 -0
- data/vendor/activemodel/test/cases/serializeration/xml_serialization_test.rb +110 -0
- data/vendor/activemodel/test/cases/state_machine/event_test.rb +49 -0
- data/vendor/activemodel/test/cases/state_machine/machine_test.rb +43 -0
- data/vendor/activemodel/test/cases/state_machine/state_test.rb +72 -0
- data/vendor/activemodel/test/cases/state_machine/state_transition_test.rb +84 -0
- data/vendor/activemodel/test/cases/state_machine_test.rb +312 -0
- data/vendor/activemodel/test/cases/tests_database.rb +37 -0
- data/vendor/activemodel/test/cases/translation_test.rb +45 -0
- data/vendor/activemodel/test/cases/validations/acceptance_validation_test.rb +71 -0
- data/vendor/activemodel/test/cases/validations/conditional_validation_test.rb +141 -0
- data/vendor/activemodel/test/cases/validations/confirmation_validation_test.rb +58 -0
- data/vendor/activemodel/test/cases/validations/exclusion_validation_test.rb +47 -0
- data/vendor/activemodel/test/cases/validations/format_validation_test.rb +118 -0
- data/vendor/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +175 -0
- data/vendor/activemodel/test/cases/validations/i18n_validation_test.rb +527 -0
- data/vendor/activemodel/test/cases/validations/inclusion_validation_test.rb +71 -0
- data/vendor/activemodel/test/cases/validations/length_validation_test.rb +437 -0
- data/vendor/activemodel/test/cases/validations/numericality_validation_test.rb +180 -0
- data/vendor/activemodel/test/cases/validations/presence_validation_test.rb +70 -0
- data/vendor/activemodel/test/cases/validations/with_validation_test.rb +166 -0
- data/vendor/activemodel/test/cases/validations_test.rb +215 -0
- data/vendor/activemodel/test/config.rb +3 -0
- data/vendor/activemodel/test/fixtures/topics.yml +41 -0
- data/vendor/activemodel/test/models/contact.rb +7 -0
- data/vendor/activemodel/test/models/custom_reader.rb +17 -0
- data/vendor/activemodel/test/models/developer.rb +6 -0
- data/vendor/activemodel/test/models/person.rb +9 -0
- data/vendor/activemodel/test/models/reply.rb +34 -0
- data/vendor/activemodel/test/models/topic.rb +9 -0
- data/vendor/activemodel/test/models/track_back.rb +4 -0
- data/vendor/activemodel/test/schema.rb +14 -0
- data/vendor/activesupport/lib/active_support/autoload.rb +48 -0
- data/vendor/activesupport/lib/active_support/concern.rb +25 -0
- data/vendor/activesupport/lib/active_support/core_ext/array/wrap.rb +20 -0
- data/vendor/activesupport/lib/active_support/core_ext/object/blank.rb +58 -0
- data/vendor/activesupport/lib/active_support/core_ext/object/tap.rb +6 -0
- data/vendor/activesupport/lib/active_support/dependency_module.rb +17 -0
- data/vendor/activesupport/lib/active_support/i18n.rb +2 -0
- data/vendor/activesupport/lib/active_support/locale/en.yml +33 -0
- metadata +230 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'cases/helper'
|
3
|
+
require 'cases/tests_database'
|
4
|
+
|
5
|
+
require 'models/topic'
|
6
|
+
|
7
|
+
class ValidatesWithTest < ActiveRecord::TestCase
|
8
|
+
include ActiveModel::TestsDatabase
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
Topic.reset_callbacks(:validate)
|
12
|
+
end
|
13
|
+
|
14
|
+
ERROR_MESSAGE = "Validation error from validator"
|
15
|
+
OTHER_ERROR_MESSAGE = "Validation error from other validator"
|
16
|
+
|
17
|
+
class ValidatorThatAddsErrors < ActiveModel::Validator
|
18
|
+
def validate(record)
|
19
|
+
record.errors[:base] << ERROR_MESSAGE
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class OtherValidatorThatAddsErrors < ActiveModel::Validator
|
24
|
+
def validate(record)
|
25
|
+
record.errors[:base] << OTHER_ERROR_MESSAGE
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ValidatorThatDoesNotAddErrors < ActiveModel::Validator
|
30
|
+
def validate(record)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ValidatorThatValidatesOptions < ActiveModel::Validator
|
35
|
+
def validate(record)
|
36
|
+
if options[:field] == :first_name
|
37
|
+
record.errors[:base] << ERROR_MESSAGE
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class ValidatorPerEachAttribute < ActiveModel::EachValidator
|
43
|
+
def validate_each(record, attribute, value)
|
44
|
+
record.errors[attribute] << "Value is #{value}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class ValidatorCheckValidity < ActiveModel::EachValidator
|
49
|
+
def check_validity!
|
50
|
+
raise "boom!"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
test "vaidation with class that adds errors" do
|
55
|
+
Topic.validates_with(ValidatorThatAddsErrors)
|
56
|
+
topic = Topic.new
|
57
|
+
assert !topic.valid?, "A class that adds errors causes the record to be invalid"
|
58
|
+
assert topic.errors[:base].include?(ERROR_MESSAGE)
|
59
|
+
end
|
60
|
+
|
61
|
+
test "with a class that returns valid" do
|
62
|
+
Topic.validates_with(ValidatorThatDoesNotAddErrors)
|
63
|
+
topic = Topic.new
|
64
|
+
assert topic.valid?, "A class that does not add errors does not cause the record to be invalid"
|
65
|
+
end
|
66
|
+
|
67
|
+
test "with a class that adds errors on update and a new record" do
|
68
|
+
Topic.validates_with(ValidatorThatAddsErrors, :on => :update)
|
69
|
+
topic = Topic.new
|
70
|
+
assert topic.valid?, "Validation doesn't run on create if 'on' is set to update"
|
71
|
+
end
|
72
|
+
|
73
|
+
test "with a class that adds errors on create and a new record" do
|
74
|
+
Topic.validates_with(ValidatorThatAddsErrors, :on => :create)
|
75
|
+
topic = Topic.new
|
76
|
+
assert !topic.valid?, "Validation does run on create if 'on' is set to create"
|
77
|
+
assert topic.errors[:base].include?(ERROR_MESSAGE)
|
78
|
+
end
|
79
|
+
|
80
|
+
test "with multiple classes" do
|
81
|
+
Topic.validates_with(ValidatorThatAddsErrors, OtherValidatorThatAddsErrors)
|
82
|
+
topic = Topic.new
|
83
|
+
assert !topic.valid?
|
84
|
+
assert topic.errors[:base].include?(ERROR_MESSAGE)
|
85
|
+
assert topic.errors[:base].include?(OTHER_ERROR_MESSAGE)
|
86
|
+
end
|
87
|
+
|
88
|
+
test "with if statements that return false" do
|
89
|
+
Topic.validates_with(ValidatorThatAddsErrors, :if => "1 == 2")
|
90
|
+
topic = Topic.new
|
91
|
+
assert topic.valid?
|
92
|
+
end
|
93
|
+
|
94
|
+
test "with if statements that return true" do
|
95
|
+
Topic.validates_with(ValidatorThatAddsErrors, :if => "1 == 1")
|
96
|
+
topic = Topic.new
|
97
|
+
assert !topic.valid?
|
98
|
+
assert topic.errors[:base].include?(ERROR_MESSAGE)
|
99
|
+
end
|
100
|
+
|
101
|
+
test "with unless statements that return true" do
|
102
|
+
Topic.validates_with(ValidatorThatAddsErrors, :unless => "1 == 1")
|
103
|
+
topic = Topic.new
|
104
|
+
assert topic.valid?
|
105
|
+
end
|
106
|
+
|
107
|
+
test "with unless statements that returns false" do
|
108
|
+
Topic.validates_with(ValidatorThatAddsErrors, :unless => "1 == 2")
|
109
|
+
topic = Topic.new
|
110
|
+
assert !topic.valid?
|
111
|
+
assert topic.errors[:base].include?(ERROR_MESSAGE)
|
112
|
+
end
|
113
|
+
|
114
|
+
test "passes all configuration options to the validator class" do
|
115
|
+
topic = Topic.new
|
116
|
+
validator = mock()
|
117
|
+
validator.expects(:new).with(:foo => :bar, :if => "1 == 1").returns(validator)
|
118
|
+
validator.expects(:validate).with(topic)
|
119
|
+
|
120
|
+
Topic.validates_with(validator, :if => "1 == 1", :foo => :bar)
|
121
|
+
assert topic.valid?
|
122
|
+
end
|
123
|
+
|
124
|
+
test "validates_with with options" do
|
125
|
+
Topic.validates_with(ValidatorThatValidatesOptions, :field => :first_name)
|
126
|
+
topic = Topic.new
|
127
|
+
assert !topic.valid?
|
128
|
+
assert topic.errors[:base].include?(ERROR_MESSAGE)
|
129
|
+
end
|
130
|
+
|
131
|
+
test "validates_with each validator" do
|
132
|
+
Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content])
|
133
|
+
topic = Topic.new :title => "Title", :content => "Content"
|
134
|
+
assert !topic.valid?
|
135
|
+
assert_equal ["Value is Title"], topic.errors[:title]
|
136
|
+
assert_equal ["Value is Content"], topic.errors[:content]
|
137
|
+
end
|
138
|
+
|
139
|
+
test "each validator checks validity" do
|
140
|
+
assert_raise RuntimeError do
|
141
|
+
Topic.validates_with(ValidatorCheckValidity, :attributes => [:title])
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
test "each validator expects attributes to be given" do
|
146
|
+
assert_raise RuntimeError do
|
147
|
+
Topic.validates_with(ValidatorPerEachAttribute)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
test "each validator skip nil values if :allow_nil is set to true" do
|
152
|
+
Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content], :allow_nil => true)
|
153
|
+
topic = Topic.new :content => ""
|
154
|
+
assert !topic.valid?
|
155
|
+
assert topic.errors[:title].empty?
|
156
|
+
assert_equal ["Value is "], topic.errors[:content]
|
157
|
+
end
|
158
|
+
|
159
|
+
test "each validator skip blank values if :allow_blank is set to true" do
|
160
|
+
Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content], :allow_blank => true)
|
161
|
+
topic = Topic.new :content => ""
|
162
|
+
assert topic.valid?
|
163
|
+
assert topic.errors[:title].empty?
|
164
|
+
assert topic.errors[:content].empty?
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'cases/helper'
|
3
|
+
require 'cases/tests_database'
|
4
|
+
|
5
|
+
require 'models/topic'
|
6
|
+
require 'models/reply'
|
7
|
+
require 'models/developer'
|
8
|
+
require 'models/custom_reader'
|
9
|
+
|
10
|
+
class ValidationsTest < ActiveModel::TestCase
|
11
|
+
include ActiveModel::TestsDatabase
|
12
|
+
|
13
|
+
# Most of the tests mess with the validations of Topic, so lets repair it all the time.
|
14
|
+
# Other classes we mess with will be dealt with in the specific tests
|
15
|
+
def teardown
|
16
|
+
Topic.reset_callbacks(:validate)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_single_field_validation
|
20
|
+
r = Reply.new
|
21
|
+
r.title = "There's no content!"
|
22
|
+
assert !r.valid?, "A reply without content shouldn't be saveable"
|
23
|
+
|
24
|
+
r.content = "Messa content!"
|
25
|
+
assert r.valid?, "A reply with content should be saveable"
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_single_attr_validation_and_error_msg
|
29
|
+
r = Reply.new
|
30
|
+
r.title = "There's no content!"
|
31
|
+
assert !r.valid?
|
32
|
+
assert r.errors[:content].any?, "A reply without content should mark that attribute as invalid"
|
33
|
+
assert_equal ["Empty"], r.errors["content"], "A reply without content should contain an error"
|
34
|
+
assert_equal 1, r.errors.count
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_double_attr_validation_and_error_msg
|
38
|
+
r = Reply.new
|
39
|
+
assert !r.valid?
|
40
|
+
|
41
|
+
assert r.errors[:title].any?, "A reply without title should mark that attribute as invalid"
|
42
|
+
assert_equal ["Empty"], r.errors["title"], "A reply without title should contain an error"
|
43
|
+
|
44
|
+
assert r.errors[:content].any?, "A reply without content should mark that attribute as invalid"
|
45
|
+
assert_equal ["Empty"], r.errors["content"], "A reply without content should contain an error"
|
46
|
+
|
47
|
+
assert_equal 2, r.errors.count
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_single_error_per_attr_iteration
|
51
|
+
r = Reply.new
|
52
|
+
r.save
|
53
|
+
|
54
|
+
errors = []
|
55
|
+
r.errors.each {|attr, messages| errors << [attr.to_s, messages] }
|
56
|
+
|
57
|
+
assert errors.include?(["title", "Empty"])
|
58
|
+
assert errors.include?(["content", "Empty"])
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_multiple_errors_per_attr_iteration_with_full_error_composition
|
62
|
+
r = Reply.new
|
63
|
+
r.title = "Wrong Create"
|
64
|
+
r.content = "Mismatch"
|
65
|
+
r.save
|
66
|
+
|
67
|
+
errors = r.errors.to_a
|
68
|
+
|
69
|
+
assert_equal "Title is Wrong Create", errors[0]
|
70
|
+
assert_equal "Title is Content Mismatch", errors[1]
|
71
|
+
assert_equal 2, r.errors.count
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_errors_on_nested_attributes_expands_name
|
75
|
+
t = Topic.new
|
76
|
+
t.errors["replies.name"] << "can't be blank"
|
77
|
+
assert_equal ["Replies name can't be blank"], t.errors.full_messages
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_errors_on_base
|
81
|
+
r = Reply.new
|
82
|
+
r.content = "Mismatch"
|
83
|
+
r.save
|
84
|
+
r.errors[:base] << "Reply is not dignifying"
|
85
|
+
|
86
|
+
errors = []
|
87
|
+
r.errors.to_a.each { |error| errors << error }
|
88
|
+
|
89
|
+
assert_equal ["Reply is not dignifying"], r.errors[:base]
|
90
|
+
|
91
|
+
assert errors.include?("Title Empty")
|
92
|
+
assert errors.include?("Reply is not dignifying")
|
93
|
+
assert_equal 2, r.errors.count
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_validates_each
|
97
|
+
hits = 0
|
98
|
+
Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
|
99
|
+
record.errors.add attr, 'gotcha'
|
100
|
+
hits += 1
|
101
|
+
end
|
102
|
+
t = Topic.new("title" => "valid", "content" => "whatever")
|
103
|
+
assert !t.save
|
104
|
+
assert_equal 4, hits
|
105
|
+
assert_equal %w(gotcha gotcha), t.errors[:title]
|
106
|
+
assert_equal %w(gotcha gotcha), t.errors[:content]
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_validates_each_custom_reader
|
110
|
+
hits = 0
|
111
|
+
CustomReader.validates_each(:title, :content, [:title, :content]) do |record, attr|
|
112
|
+
record.errors.add attr, 'gotcha'
|
113
|
+
hits += 1
|
114
|
+
end
|
115
|
+
t = CustomReader.new("title" => "valid", "content" => "whatever")
|
116
|
+
assert !t.valid?
|
117
|
+
assert_equal 4, hits
|
118
|
+
assert_equal %w(gotcha gotcha), t.errors[:title]
|
119
|
+
assert_equal %w(gotcha gotcha), t.errors[:content]
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_validate_block
|
123
|
+
Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
|
124
|
+
t = Topic.create("title" => "Title", "content" => "whatever")
|
125
|
+
assert !t.valid?
|
126
|
+
assert t.errors[:title].any?
|
127
|
+
assert_equal ["will never be valid"], t.errors["title"]
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_invalid_validator
|
131
|
+
Topic.validate :i_dont_exist
|
132
|
+
assert_raise(NameError) { t = Topic.create }
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_errors_to_xml
|
136
|
+
r = Reply.new :title => "Wrong Create"
|
137
|
+
assert !r.valid?
|
138
|
+
xml = r.errors.to_xml(:skip_instruct => true)
|
139
|
+
assert_equal "<errors>", xml.first(8)
|
140
|
+
assert xml.include?("<error>Title is Wrong Create</error>")
|
141
|
+
assert xml.include?("<error>Content Empty</error>")
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_validation_order
|
145
|
+
Topic.validates_presence_of :title
|
146
|
+
Topic.validates_length_of :title, :minimum => 2
|
147
|
+
|
148
|
+
t = Topic.new("title" => "")
|
149
|
+
assert !t.valid?
|
150
|
+
assert_equal "can't be blank", t.errors["title"].first
|
151
|
+
Topic.validates_presence_of :title, :author_name
|
152
|
+
Topic.validate {|topic| topic.errors.add('author_email_address', 'will never be valid')}
|
153
|
+
Topic.validates_length_of :title, :content, :minimum => 2
|
154
|
+
|
155
|
+
t = Topic.new :title => ''
|
156
|
+
assert !t.valid?
|
157
|
+
|
158
|
+
assert_equal :title, key = t.errors.keys.first
|
159
|
+
assert_equal "can't be blank", t.errors[key].first
|
160
|
+
assert_equal 'is too short (minimum is 2 characters)', t.errors[key].second
|
161
|
+
assert_equal :author_name, key = t.errors.keys.second
|
162
|
+
assert_equal "can't be blank", t.errors[key].first
|
163
|
+
assert_equal :author_email_address, key = t.errors.keys.third
|
164
|
+
assert_equal 'will never be valid', t.errors[key].first
|
165
|
+
assert_equal :content, key = t.errors.keys.fourth
|
166
|
+
assert_equal 'is too short (minimum is 2 characters)', t.errors[key].first
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_invalid_should_be_the_opposite_of_valid
|
170
|
+
Topic.validates_presence_of :title
|
171
|
+
|
172
|
+
t = Topic.new
|
173
|
+
assert t.invalid?
|
174
|
+
assert t.errors[:title].any?
|
175
|
+
|
176
|
+
t.title = 'Things are going to change'
|
177
|
+
assert !t.invalid?
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_deprecated_error_messages_on
|
181
|
+
Topic.validates_presence_of :title
|
182
|
+
|
183
|
+
t = Topic.new
|
184
|
+
assert t.invalid?
|
185
|
+
|
186
|
+
[:title, "title"].each do |attribute|
|
187
|
+
assert_deprecated { assert_equal "can't be blank", t.errors.on(attribute) }
|
188
|
+
end
|
189
|
+
|
190
|
+
Topic.validates_each(:title) do |record, attribute|
|
191
|
+
record.errors[attribute] << "invalid"
|
192
|
+
end
|
193
|
+
|
194
|
+
assert t.invalid?
|
195
|
+
|
196
|
+
[:title, "title"].each do |attribute|
|
197
|
+
assert_deprecated do
|
198
|
+
assert t.errors.on(attribute).include?("invalid")
|
199
|
+
assert t.errors.on(attribute).include?("can't be blank")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_deprecated_errors_on_base_and_each
|
205
|
+
t = Topic.new
|
206
|
+
assert t.valid?
|
207
|
+
|
208
|
+
assert_deprecated { t.errors.add_to_base "invalid topic" }
|
209
|
+
assert_deprecated { assert_equal "invalid topic", t.errors.on_base }
|
210
|
+
assert_deprecated { assert t.errors.invalid?(:base) }
|
211
|
+
|
212
|
+
all_errors = t.errors.to_a
|
213
|
+
assert_deprecated { assert_equal all_errors, t.errors.each_full{|err| err} }
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
first:
|
2
|
+
id: 1
|
3
|
+
title: The First Topic
|
4
|
+
author_name: David
|
5
|
+
author_email_address: david@loudthinking.com
|
6
|
+
written_on: 2003-07-16t15:28:11.2233+01:00
|
7
|
+
last_read: 2004-04-15
|
8
|
+
bonus_time: 2005-01-30t15:28:00.00+01:00
|
9
|
+
content: Have a nice day
|
10
|
+
approved: false
|
11
|
+
replies_count: 1
|
12
|
+
|
13
|
+
second:
|
14
|
+
id: 2
|
15
|
+
title: The Second Topic of the day
|
16
|
+
author_name: Mary
|
17
|
+
written_on: 2004-07-15t15:28:00.0099+01:00
|
18
|
+
content: Have a nice day
|
19
|
+
approved: true
|
20
|
+
replies_count: 0
|
21
|
+
parent_id: 1
|
22
|
+
type: Reply
|
23
|
+
|
24
|
+
third:
|
25
|
+
id: 3
|
26
|
+
title: The Third Topic of the day
|
27
|
+
author_name: Nick
|
28
|
+
written_on: 2005-07-15t15:28:00.0099+01:00
|
29
|
+
content: I'm a troll
|
30
|
+
approved: true
|
31
|
+
replies_count: 1
|
32
|
+
|
33
|
+
fourth:
|
34
|
+
id: 4
|
35
|
+
title: The Fourth Topic of the day
|
36
|
+
author_name: Carl
|
37
|
+
written_on: 2006-07-15t15:28:00.0099+01:00
|
38
|
+
content: Why not?
|
39
|
+
approved: true
|
40
|
+
type: Reply
|
41
|
+
parent_id: 3
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'models/topic'
|
2
|
+
|
3
|
+
class Reply < Topic
|
4
|
+
validate :errors_on_empty_content
|
5
|
+
validate :title_is_wrong_create, :on => :create
|
6
|
+
|
7
|
+
validate :check_empty_title
|
8
|
+
validate :check_content_mismatch, :on => :create
|
9
|
+
validate :check_wrong_update, :on => :update
|
10
|
+
|
11
|
+
attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read
|
12
|
+
|
13
|
+
def check_empty_title
|
14
|
+
errors[:title] << "Empty" unless attribute_present?("title")
|
15
|
+
end
|
16
|
+
|
17
|
+
def errors_on_empty_content
|
18
|
+
errors[:content] << "Empty" unless attribute_present?("content")
|
19
|
+
end
|
20
|
+
|
21
|
+
def check_content_mismatch
|
22
|
+
if attribute_present?("title") && attribute_present?("content") && content == "Mismatch"
|
23
|
+
errors[:title] << "is Content Mismatch"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def title_is_wrong_create
|
28
|
+
errors[:title] << "is Wrong Create" if attribute_present?("title") && title == "Wrong Create"
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_wrong_update
|
32
|
+
errors[:title] << "is Wrong Update" if attribute_present?("title") && title == "Wrong Update"
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
create_table :topics, :force => true do |t|
|
3
|
+
t.string :title
|
4
|
+
t.string :author_name
|
5
|
+
t.text :content
|
6
|
+
t.boolean :approved, :default => true
|
7
|
+
t.string :type
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :developers, :force => true do |t|
|
11
|
+
t.string :name
|
12
|
+
t.float :salary
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
module ActiveSupport
|
3
|
+
module Autoload
|
4
|
+
@@autoloads = {}
|
5
|
+
@@under_path = nil
|
6
|
+
@@at_path = nil
|
7
|
+
@@eager_autoload = false
|
8
|
+
|
9
|
+
def autoload(const_name, path = @@at_path)
|
10
|
+
full = [self.name, @@under_path, const_name.to_s, path].compact.join("::")
|
11
|
+
location = path || Inflector.underscore(full)
|
12
|
+
|
13
|
+
if @@eager_autoload
|
14
|
+
@@autoloads[const_name] = location
|
15
|
+
end
|
16
|
+
super const_name, location
|
17
|
+
end
|
18
|
+
|
19
|
+
def autoload_under(path)
|
20
|
+
@@under_path, old_path = path, @@under_path
|
21
|
+
yield
|
22
|
+
ensure
|
23
|
+
@@under_path = old_path
|
24
|
+
end
|
25
|
+
|
26
|
+
def autoload_at(path)
|
27
|
+
@@at_path, old_path = path, @@at_path
|
28
|
+
yield
|
29
|
+
ensure
|
30
|
+
@@at_path = old_path
|
31
|
+
end
|
32
|
+
|
33
|
+
def eager_autoload
|
34
|
+
old_eager, @@eager_autoload = @@eager_autoload, true
|
35
|
+
yield
|
36
|
+
ensure
|
37
|
+
@@eager_autoload = old_eager
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.eager_autoload!
|
41
|
+
@@autoloads.values.each { |file| require file }
|
42
|
+
end
|
43
|
+
|
44
|
+
def autoloads
|
45
|
+
@@autoloads
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'active_support/dependency_module'
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Concern
|
5
|
+
include DependencyModule
|
6
|
+
|
7
|
+
def append_features(base)
|
8
|
+
if super
|
9
|
+
base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
|
10
|
+
base.send :include, const_get("InstanceMethods") if const_defined?("InstanceMethods")
|
11
|
+
base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def included(base = nil, &block)
|
16
|
+
if base.nil?
|
17
|
+
@_included_block = block
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :include, :depends_on
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
unless Array.respond_to?(:wrap)
|
2
|
+
class Array
|
3
|
+
# Wraps the object in an Array unless it's an Array. Converts the
|
4
|
+
# object to an Array using #to_ary if it implements that.
|
5
|
+
def self.wrap(object)
|
6
|
+
case object
|
7
|
+
when nil
|
8
|
+
[]
|
9
|
+
when self
|
10
|
+
object
|
11
|
+
else
|
12
|
+
if object.respond_to?(:to_ary)
|
13
|
+
object.to_ary
|
14
|
+
else
|
15
|
+
[object]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class Object
|
2
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
3
|
+
# For example, "", " ", +nil+, [], and {} are blank.
|
4
|
+
#
|
5
|
+
# This simplifies
|
6
|
+
#
|
7
|
+
# if !address.nil? && !address.empty?
|
8
|
+
#
|
9
|
+
# to
|
10
|
+
#
|
11
|
+
# if !address.blank?
|
12
|
+
def blank?
|
13
|
+
respond_to?(:empty?) ? empty? : !self
|
14
|
+
end
|
15
|
+
|
16
|
+
# An object is present if it's not blank.
|
17
|
+
def present?
|
18
|
+
!blank?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class NilClass #:nodoc:
|
23
|
+
def blank?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class FalseClass #:nodoc:
|
29
|
+
def blank?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class TrueClass #:nodoc:
|
35
|
+
def blank?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Array #:nodoc:
|
41
|
+
alias_method :blank?, :empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
class Hash #:nodoc:
|
45
|
+
alias_method :blank?, :empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
class String #:nodoc:
|
49
|
+
def blank?
|
50
|
+
self !~ /\S/
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Numeric #:nodoc:
|
55
|
+
def blank?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|