cassandra_object 0.6.0.pre
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/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
|