toolchain 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +34 -0
- data/LICENSE +22 -0
- data/README.md +254 -0
- data/Rakefile +1 -0
- data/lib/toolchain.rb +2 -0
- data/lib/toolchain/attributes.rb +154 -0
- data/lib/toolchain/attributes/configuration.rb +41 -0
- data/lib/toolchain/attributes/errors.rb +5 -0
- data/lib/toolchain/attributes/errors/invalid_hash_transformation.rb +4 -0
- data/lib/toolchain/attributes/errors/invalid_mass_assignment.rb +4 -0
- data/lib/toolchain/attributes/errors/type_mismatch.rb +4 -0
- data/lib/toolchain/attributes/ext/boolean.rb +4 -0
- data/lib/toolchain/attributes/helpers.rb +72 -0
- data/lib/toolchain/validations.rb +103 -0
- data/lib/toolchain/validations/delegation.rb +31 -0
- data/lib/toolchain/validations/delegator.rb +51 -0
- data/lib/toolchain/validations/helpers.rb +58 -0
- data/lib/toolchain/validations/validation_errors.rb +82 -0
- data/lib/toolchain/validations/validators.rb +12 -0
- data/lib/toolchain/validations/validators/acceptance.rb +25 -0
- data/lib/toolchain/validations/validators/base.rb +54 -0
- data/lib/toolchain/validations/validators/confirmation.rb +39 -0
- data/lib/toolchain/validations/validators/email.rb +26 -0
- data/lib/toolchain/validations/validators/exclusion.rb +29 -0
- data/lib/toolchain/validations/validators/format.rb +25 -0
- data/lib/toolchain/validations/validators/inclusion.rb +29 -0
- data/lib/toolchain/validations/validators/length.rb +60 -0
- data/lib/toolchain/validations/validators/presence.rb +25 -0
- data/lib/toolchain/version.rb +3 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/toolchain/attributes/attribute_spec.rb +47 -0
- data/spec/toolchain/attributes/attributes_spec.rb +193 -0
- data/spec/toolchain/attributes/base_helper.rb +37 -0
- data/spec/toolchain/attributes/boolean_spec.rb +38 -0
- data/spec/toolchain/attributes/configuration_spec.rb +33 -0
- data/spec/toolchain/attributes/date_time_spec.rb +21 -0
- data/spec/toolchain/attributes/hash_spec.rb +61 -0
- data/spec/toolchain/attributes/include_attributes_spec.rb +19 -0
- data/spec/toolchain/attributes/initializer_spec.rb +32 -0
- data/spec/toolchain/validations/base_helper.rb +2 -0
- data/spec/toolchain/validations/custom_validations_spec.rb +26 -0
- data/spec/toolchain/validations/delegation_spec.rb +70 -0
- data/spec/toolchain/validations/include_validations_spec.rb +20 -0
- data/spec/toolchain/validations/inheritence_spec.rb +26 -0
- data/spec/toolchain/validations/multiple_validations_spec.rb +19 -0
- data/spec/toolchain/validations/nested_validations_spec.rb +68 -0
- data/spec/toolchain/validations/validation_errors_spec.rb +9 -0
- data/spec/toolchain/validations/validators/acceptance_spec.rb +48 -0
- data/spec/toolchain/validations/validators/confirmation_spec.rb +86 -0
- data/spec/toolchain/validations/validators/email_spec.rb +41 -0
- data/spec/toolchain/validations/validators/exclusion_spec.rb +53 -0
- data/spec/toolchain/validations/validators/format_spec.rb +44 -0
- data/spec/toolchain/validations/validators/inclusion_spec.rb +50 -0
- data/spec/toolchain/validations/validators/length_spec.rb +134 -0
- data/spec/toolchain/validations/validators/presence_spec.rb +34 -0
- data/toolchain.gemspec +21 -0
- metadata +161 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
require_relative "validators/base"
|
3
|
+
|
4
|
+
require_relative "validators/acceptance"
|
5
|
+
require_relative "validators/confirmation"
|
6
|
+
require_relative "validators/email"
|
7
|
+
require_relative "validators/exclusion"
|
8
|
+
require_relative "validators/format"
|
9
|
+
require_relative "validators/inclusion"
|
10
|
+
require_relative "validators/length"
|
11
|
+
require_relative "validators/presence"
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the acceptance of an attribute.
|
4
|
+
# Accepted values are as follows: `true`, `1` and `"1"`.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class User::Creator
|
8
|
+
# validates :terms, acceptance: {
|
9
|
+
# message: "the terms of service must be accepted"
|
10
|
+
# }
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class Acceptance < Base
|
14
|
+
|
15
|
+
def validate
|
16
|
+
errors.add(key_path, message || "must be accepted") if not_accepted?
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def not_accepted?
|
22
|
+
![1, "1", true].include?(value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Toolchain::Validations::Validators::Base
|
2
|
+
|
3
|
+
# @return [Object] the object that contains the attribute
|
4
|
+
# that'll be validated.
|
5
|
+
#
|
6
|
+
attr_reader :object
|
7
|
+
|
8
|
+
# @return [Toolchain::Validations::ValidationErrors] the errors object
|
9
|
+
# of the object that's being validated.
|
10
|
+
#
|
11
|
+
attr_reader :errors
|
12
|
+
|
13
|
+
# @return [Symbol] The key_path of the attribute that's being validated.
|
14
|
+
#
|
15
|
+
attr_reader :key_path
|
16
|
+
|
17
|
+
# @return [Hash] The value that was passed in to the validator
|
18
|
+
# at definition time. i.e. a Hash containing the regular expression
|
19
|
+
# for Toolchain::Validations::Validators::Formatter along with a message.
|
20
|
+
#
|
21
|
+
attr_reader :data
|
22
|
+
|
23
|
+
# @return [String] A custom message to override the
|
24
|
+
# default message with in case the attribute is invalid.
|
25
|
+
#
|
26
|
+
attr_reader :message
|
27
|
+
|
28
|
+
# Instantiates a new Toolchain::Validations::Validators object
|
29
|
+
# which'll be used to validate the target object.
|
30
|
+
#
|
31
|
+
# @param object [Object]
|
32
|
+
# @param key_path [Object]
|
33
|
+
# @param data [Object]
|
34
|
+
#
|
35
|
+
def initialize(object, key_path, data)
|
36
|
+
@object = object
|
37
|
+
@errors = object.errors
|
38
|
+
@key_path = key_path
|
39
|
+
@data = data
|
40
|
+
@message = data[:message] if data.is_a?(Hash)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Object] The value that's stored in the attribute of
|
44
|
+
# the object that's being validated.
|
45
|
+
#
|
46
|
+
def value
|
47
|
+
@value ||= (
|
48
|
+
keys = key_path.dup
|
49
|
+
keys.inject(object.send(keys.shift)) do |memo, key|
|
50
|
+
memo[key] if memo.kind_of?(Hash)
|
51
|
+
end
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the confirmation of an attribute.
|
4
|
+
# In the example both `password` and `password_confirmation`
|
5
|
+
# attributes must match. One or more `nil` values will result in the
|
6
|
+
# validation error being triggered as well.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class User::Creator
|
10
|
+
# validates :password, confirmation: {
|
11
|
+
# message: "doesn't match confirmation"
|
12
|
+
# }
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
class Confirmation < Base
|
16
|
+
|
17
|
+
def validate
|
18
|
+
if no_match?
|
19
|
+
errors.add(key_path, message || "doesn't match confirmation")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def no_match?
|
26
|
+
value.nil? || confirmation.nil? || value != confirmation
|
27
|
+
end
|
28
|
+
|
29
|
+
def confirmation
|
30
|
+
@confirmation ||= (
|
31
|
+
keys = key_path.dup
|
32
|
+
keys << :"#{keys.pop}_confirmation"
|
33
|
+
keys.inject(object.send(keys.shift)) do |memo, key|
|
34
|
+
memo[key] if memo.kind_of?(Hash)
|
35
|
+
end
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the format of an email address.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# class User::Creator
|
7
|
+
# validates :email, email: {
|
8
|
+
# message: "isn't valid"
|
9
|
+
# }
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
class Email < Base
|
13
|
+
|
14
|
+
PATTERN = /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
|
15
|
+
|
16
|
+
def validate
|
17
|
+
errors.add(key_path, message || "is invalid") if no_email?
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def no_email?
|
23
|
+
value.nil? || !value.match(PATTERN)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the exclusion of values in an attribute.
|
4
|
+
# In the example only games without a pegi rating
|
5
|
+
# of 12, 16, 18 are valid.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class Game::Creator
|
9
|
+
# validates :pegi, exclusion: {
|
10
|
+
# in: [12, 16, 18],
|
11
|
+
# message: "invalid pegi rating"
|
12
|
+
# }
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
class Exclusion < Base
|
16
|
+
|
17
|
+
def validate
|
18
|
+
if included?
|
19
|
+
errors.add(key_path, message || "is invalid")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def included?
|
26
|
+
data[:in].include?(value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the format of an attribute using a regular expression.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# class Company::Creator
|
7
|
+
# validates :credit_card, format: {
|
8
|
+
# with: /^\d+{4}-$\d+{4}-\d+{4}-\d+{4}/,
|
9
|
+
# message: "invalid credit card format"
|
10
|
+
# }
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class Format < Base
|
14
|
+
|
15
|
+
def validate
|
16
|
+
errors.add(key_path, message || "is invalid") if no_match?
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def no_match?
|
22
|
+
value.nil? || !value.match(data[:with])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the inclusion of values in an attribute.
|
4
|
+
# In the example, only `pending` and `dispatched` are
|
5
|
+
# allowed to be set.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class Shipment::Creator
|
9
|
+
# validates :status, inclusion: {
|
10
|
+
# in: ["pending", "dispatched"],
|
11
|
+
# message: "available options are: pending, dispatched"
|
12
|
+
# }
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
class Inclusion < Base
|
16
|
+
|
17
|
+
def validate
|
18
|
+
if not_included?
|
19
|
+
errors.add(key_path, message || "is invalid")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def not_included?
|
26
|
+
!data.include?(value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the lengt of an attribute.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# class User::Creator
|
7
|
+
# validates :password, length: {
|
8
|
+
# between: 5..100,
|
9
|
+
# message: "must be between 5 and 100 characters long"
|
10
|
+
# }
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# class User::Creator
|
14
|
+
# validates :password, length: {
|
15
|
+
# greater_than: 5,
|
16
|
+
# less_than 100,
|
17
|
+
# message: "must be between 5 and 100 characters long"
|
18
|
+
# }
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
class Length < Base
|
22
|
+
|
23
|
+
def validate
|
24
|
+
errors.add(key_path, message || "is invalid") unless valid?
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def valid?
|
30
|
+
val =
|
31
|
+
if value.kind_of?(String) && value =~ /^\d+$/
|
32
|
+
value.to_i
|
33
|
+
elsif value.kind_of?(String) && value =~ /^\d+\.\d+$/
|
34
|
+
value.to_f
|
35
|
+
elsif value.kind_of?(String)
|
36
|
+
value.length
|
37
|
+
else
|
38
|
+
value
|
39
|
+
end
|
40
|
+
|
41
|
+
if data[:between]
|
42
|
+
return data[:between].include?(val)
|
43
|
+
end
|
44
|
+
|
45
|
+
if data[:greater_than] && data[:less_than]
|
46
|
+
return val > data[:greater_than] && val < data[:less_than]
|
47
|
+
end
|
48
|
+
|
49
|
+
if data[:greater_than]
|
50
|
+
return val > data[:greater_than]
|
51
|
+
end
|
52
|
+
|
53
|
+
if data[:less_than]
|
54
|
+
return val < data[:less_than]
|
55
|
+
end
|
56
|
+
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Toolchain::Validations::Validators
|
2
|
+
|
3
|
+
# Validates the presence of an attribute. If the attribute
|
4
|
+
# is either `nil` or `""` (empty String) it is considered invalid.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class User::Creator
|
8
|
+
# validates :name, presence: {
|
9
|
+
# message: "is required"
|
10
|
+
# }
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class Presence < Base
|
14
|
+
|
15
|
+
def validate
|
16
|
+
errors.add(key_path, message || "can't be blank") if blank?
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def blank?
|
22
|
+
[nil, ""].include?(value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative "base_helper"
|
2
|
+
|
3
|
+
describe Toolchain::Attributes, "Attribute" do
|
4
|
+
|
5
|
+
let(:model) { ModelData.new }
|
6
|
+
|
7
|
+
it "should be nil by default" do
|
8
|
+
model.string.should == nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be empty by default" do
|
12
|
+
model.string_default.should == ""
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should set a new String" do
|
16
|
+
expect { model.string = "Example" }.
|
17
|
+
to change { model.string }.from(nil).to("Example")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should set to nil, resulting in default" do
|
21
|
+
model.string_default = "Example"
|
22
|
+
expect { model.string_default = nil }.
|
23
|
+
to change { model.string_default }.from("Example").to("")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should instance-variable cache the result" do
|
27
|
+
model.time_default.should == model.time_default
|
28
|
+
end
|
29
|
+
|
30
|
+
it "requires the type to match the configured type" do
|
31
|
+
expect { model.string = 0 }.to raise_error(
|
32
|
+
Toolchain::Attributes::Errors::TypeMismatch,
|
33
|
+
"ModelData#string expected String type, but received Fixnum (0).")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not allow defaults of other data-type" do
|
37
|
+
expect {
|
38
|
+
class InvalidModelData
|
39
|
+
include Toolchain::Attributes
|
40
|
+
attribute :string, String, 0
|
41
|
+
end
|
42
|
+
}.to raise_error(
|
43
|
+
Toolchain::Attributes::Errors::TypeMismatch,
|
44
|
+
"expected InvalidModelData#string to have default value "+
|
45
|
+
"of String type, but received Fixnum (0).")
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require_relative "base_helper"
|
2
|
+
|
3
|
+
describe Toolchain::Attributes, "Attributes (Method)" do
|
4
|
+
|
5
|
+
let(:model) { ModelData.new }
|
6
|
+
|
7
|
+
def expect_date_time
|
8
|
+
[
|
9
|
+
Date.today.tap { |d| Date.stubs(:today).returns(d) },
|
10
|
+
Time.now.tap { |t| Time.stubs(:now).returns(t) },
|
11
|
+
DateTime.now.tap { |dt| DateTime.stubs(:now).returns(dt) }
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return attributes with Symbol keys" do
|
16
|
+
date, time, date_time = expect_date_time
|
17
|
+
|
18
|
+
model.attributes.should == {
|
19
|
+
array_default: [],
|
20
|
+
boolean_default: false,
|
21
|
+
float_default: 0.0,
|
22
|
+
hash_default: {},
|
23
|
+
integer_default: 0,
|
24
|
+
string_default: "",
|
25
|
+
date_default: date,
|
26
|
+
time_default: time,
|
27
|
+
date_time_default: date_time
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return attributes with String keys" do
|
32
|
+
Toolchain::Attributes::Configuration.
|
33
|
+
hash_transformation = :stringify_keys
|
34
|
+
|
35
|
+
date, time, date_time = expect_date_time
|
36
|
+
|
37
|
+
model.attributes.should == {
|
38
|
+
"array_default" => [],
|
39
|
+
"boolean_default" => false,
|
40
|
+
"float_default" => 0.0,
|
41
|
+
"hash_default" => {},
|
42
|
+
"integer_default" => 0,
|
43
|
+
"string_default" => "",
|
44
|
+
"date_default" => date,
|
45
|
+
"time_default" => time,
|
46
|
+
"date_time_default" => date_time
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should symbolize hash, hash_default" do
|
51
|
+
model.hash = { "key" => { "value" => true } }
|
52
|
+
model.hash_default = { "key" => { "value" => true } }
|
53
|
+
model.attributes.tap do |attrs|
|
54
|
+
attrs[:hash].should == { key: { value: true } }
|
55
|
+
attrs[:hash_default].should == { key: { value: true } }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should stringify hash, hash_default" do
|
60
|
+
Toolchain::Attributes::Configuration.
|
61
|
+
hash_transformation = :stringify_keys
|
62
|
+
|
63
|
+
model.hash = { key: { value: true } }
|
64
|
+
model.hash_default = { key: { value: true } }
|
65
|
+
model.attributes.tap do |attrs|
|
66
|
+
attrs["hash"].should == { "key" => { "value" => true } }
|
67
|
+
attrs["hash_default"].should == { "key" => { "value" => true } }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should include nil attributes" do
|
72
|
+
Toolchain::Attributes::Configuration.
|
73
|
+
include_nil_in_attributes = true
|
74
|
+
|
75
|
+
date, time, date_time = expect_date_time
|
76
|
+
|
77
|
+
model.attributes.should == {
|
78
|
+
array: nil,
|
79
|
+
array_default: [],
|
80
|
+
boolean: nil,
|
81
|
+
boolean_default: false,
|
82
|
+
float: nil,
|
83
|
+
float_default: 0.0,
|
84
|
+
hash: nil,
|
85
|
+
hash_default: {},
|
86
|
+
integer: nil,
|
87
|
+
integer_default: 0,
|
88
|
+
string: nil,
|
89
|
+
string_default: "",
|
90
|
+
date: nil,
|
91
|
+
date_default: date,
|
92
|
+
time: nil,
|
93
|
+
time_default: time,
|
94
|
+
date_time: nil,
|
95
|
+
date_time_default: date_time
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should mass-assign attributes" do
|
100
|
+
date, time, date_time = expect_date_time
|
101
|
+
|
102
|
+
model.attributes = {
|
103
|
+
string: "Example",
|
104
|
+
integer: 123,
|
105
|
+
float: 1.23,
|
106
|
+
hash: { foo: "bar" },
|
107
|
+
array: [1, 2, 3],
|
108
|
+
boolean: true,
|
109
|
+
date: date,
|
110
|
+
date_default: date,
|
111
|
+
time: time,
|
112
|
+
time_default: time,
|
113
|
+
date_time: date_time,
|
114
|
+
date_time_default: date_time,
|
115
|
+
}
|
116
|
+
|
117
|
+
model.attributes.should == {
|
118
|
+
array: [1, 2, 3],
|
119
|
+
array_default: [],
|
120
|
+
boolean: true,
|
121
|
+
boolean_default: false,
|
122
|
+
float: 1.23,
|
123
|
+
float_default: 0.0,
|
124
|
+
hash: { foo: "bar" },
|
125
|
+
hash_default: {},
|
126
|
+
integer: 123,
|
127
|
+
integer_default: 0,
|
128
|
+
string: "Example",
|
129
|
+
string_default: "",
|
130
|
+
date: date,
|
131
|
+
date_default: date,
|
132
|
+
time: time,
|
133
|
+
time_default: time,
|
134
|
+
date_time: date_time,
|
135
|
+
date_time_default: date_time
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should not assign undefined attributes" do
|
140
|
+
date, time, date_time = expect_date_time
|
141
|
+
model.attributes = { unknown_attribute: true }
|
142
|
+
model.attributes.should == {
|
143
|
+
array_default: [],
|
144
|
+
boolean_default: false,
|
145
|
+
float_default: 0.0,
|
146
|
+
hash_default: {},
|
147
|
+
integer_default: 0,
|
148
|
+
string_default: "",
|
149
|
+
date_default: date,
|
150
|
+
time_default: time,
|
151
|
+
date_time_default: date_time,
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should raise an exception non-Hash type is passed" do
|
156
|
+
expect { model.attributes = 0 }.
|
157
|
+
to raise_error(
|
158
|
+
Toolchain::Attributes::Errors::InvalidMassAssignment,
|
159
|
+
"Can't mass-assign Fixnum (0) type to ModelData#attributes.")
|
160
|
+
end
|
161
|
+
|
162
|
+
class InheritedModelData < ModelData
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should inherit all attribute definitions" do
|
166
|
+
date, time, date_time = expect_date_time
|
167
|
+
InheritedModelData.new.attributes.should == {
|
168
|
+
array_default: [],
|
169
|
+
boolean_default: false,
|
170
|
+
float_default: 0.0,
|
171
|
+
hash_default: {},
|
172
|
+
integer_default: 0,
|
173
|
+
string_default: "",
|
174
|
+
date_default: date,
|
175
|
+
time_default: time,
|
176
|
+
date_time_default: date_time
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should mass-assign superclass keys" do
|
181
|
+
date, time, date_time = expect_date_time
|
182
|
+
model = InheritedModelData.new
|
183
|
+
model.attributes = { string: "Michael" }
|
184
|
+
model.string.should == "Michael"
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should mass-assing superclass string keys" do
|
188
|
+
date, time, date_time = expect_date_time
|
189
|
+
model = InheritedModelData.new
|
190
|
+
model.attributes = { "string" => "Michael" }
|
191
|
+
model.string.should == "Michael"
|
192
|
+
end
|
193
|
+
end
|