modelish 0.3.0 → 1.0.0.pre.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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rspec +3 -1
- data/.ruby-version +1 -1
- data/.travis.yml +14 -0
- data/Appraisals +11 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -1
- data/README.md +5 -0
- data/gemfiles/hashie_1.gemfile +7 -0
- data/gemfiles/hashie_2.gemfile +7 -0
- data/gemfiles/hashie_3.gemfile +7 -0
- data/lib/modelish/base.rb +108 -72
- data/lib/modelish/configuration.rb +9 -8
- data/lib/modelish/property_translations.rb +23 -11
- data/lib/modelish/property_types.rb +67 -50
- data/lib/modelish/validations.rb +70 -51
- data/lib/modelish/version.rb +3 -1
- data/lib/modelish.rb +3 -1
- data/modelish.gemspec +20 -15
- data/spec/modelish/base_spec.rb +203 -182
- data/spec/modelish/configuration_spec.rb +26 -19
- data/spec/modelish/property_translations_spec.rb +47 -39
- data/spec/modelish/property_types_spec.rb +53 -45
- data/spec/modelish/validations_spec.rb +296 -256
- data/spec/modelish_spec.rb +5 -3
- data/spec/spec_helper.rb +97 -2
- data/spec/support/property_examples.rb +15 -12
- data/spec/support/typed_property_examples.rb +39 -35
- data/spec/support/unknown_property_examples.rb +6 -4
- data/spec/support/validation_examples.rb +29 -23
- metadata +136 -103
- data/.ruby-gemset +0 -1
data/lib/modelish/validations.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
|
3
5
|
module Modelish
|
6
|
+
# Mixin for validated properties
|
4
7
|
module Validations
|
5
8
|
def self.included(base)
|
6
9
|
base.extend(ClassMethods)
|
@@ -13,8 +16,8 @@ module Modelish
|
|
13
16
|
# @see ClassMethods#add_validator
|
14
17
|
def validate
|
15
18
|
errors = {}
|
16
|
-
|
17
|
-
call_validators do |name,message|
|
19
|
+
|
20
|
+
call_validators do |name, message|
|
18
21
|
errors[name] ||= []
|
19
22
|
errors[name] << to_error(message)
|
20
23
|
end
|
@@ -27,7 +30,7 @@ module Modelish
|
|
27
30
|
# @raise ArgumentError when any property fails validation
|
28
31
|
def validate!
|
29
32
|
errors = validate
|
30
|
-
raise
|
33
|
+
raise errors.first[1].first unless errors.empty?
|
31
34
|
end
|
32
35
|
|
33
36
|
def valid?
|
@@ -35,12 +38,12 @@ module Modelish
|
|
35
38
|
end
|
36
39
|
|
37
40
|
private
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
|
42
|
+
def call_validators
|
43
|
+
self.class.validators.each_pair do |property_name, validators|
|
44
|
+
validators.each do |validator|
|
45
|
+
message = validator.call(send(property_name))
|
46
|
+
yield property_name, message if message
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
@@ -49,27 +52,31 @@ module Modelish
|
|
49
52
|
msg.is_a?(StandardError) ? msg : ArgumentError.new(msg.to_s)
|
50
53
|
end
|
51
54
|
|
55
|
+
# Class methods for managing validated properties
|
52
56
|
module ClassMethods
|
53
57
|
# Sets up a block containing validation logic for a given property.
|
54
58
|
# Each property may have 0 or more validators.
|
55
59
|
#
|
56
|
-
# @param [String,Symbol] property_name the name of the property to
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
60
|
+
# @param [String,Symbol] property_name the name of the property to
|
61
|
+
# validate
|
62
|
+
# @param [#call] validator the block containing the validation logic; must
|
63
|
+
# return either an error object or a string
|
64
|
+
# containing the error message if validation
|
65
|
+
# fails.
|
66
|
+
#
|
61
67
|
# @example adding a validator that only allows non-nil values
|
62
68
|
# class MyModel
|
63
69
|
# include Modelish::Validations
|
64
70
|
# attr_accessor :foo
|
65
|
-
# add_validator(:foo) { |val| val.nil? ? 'foo must
|
71
|
+
# add_validator(:foo) { |val| val.nil? ? 'foo must exist': nil }
|
66
72
|
# end
|
67
73
|
def add_validator(property_name, &validator)
|
68
|
-
|
69
|
-
validators[
|
74
|
+
property = property_name.to_sym
|
75
|
+
validators[property] ||= []
|
76
|
+
validators[property] << validator
|
70
77
|
|
71
78
|
class_eval do
|
72
|
-
attr_accessor
|
79
|
+
attr_accessor property unless method_defined?(property_name)
|
73
80
|
end
|
74
81
|
end
|
75
82
|
|
@@ -78,38 +85,41 @@ module Modelish
|
|
78
85
|
@validators ||= {}
|
79
86
|
end
|
80
87
|
|
81
|
-
# Validates the required values, returning a list of errors when
|
82
|
-
# fails.
|
88
|
+
# Validates the required values, returning a list of errors when
|
89
|
+
# validation fails.
|
83
90
|
#
|
84
91
|
# @param [Hash] args the map of name => value pairs to validate
|
85
|
-
# @return [Array<ArgumentError>] a list of
|
92
|
+
# @return [Array<ArgumentError>] a list of validation failures
|
86
93
|
def validate_required(args)
|
87
|
-
|
88
|
-
|
89
|
-
|
94
|
+
blanks = args.select { |_k, v| v.nil? || v.to_s.strip.empty? }
|
95
|
+
blanks.keys.map do |name|
|
96
|
+
ArgumentError.new("#{name} must not be nil or blank")
|
90
97
|
end
|
91
|
-
errors
|
92
98
|
end
|
93
99
|
|
94
100
|
# Validates the required values, raising an error when validation fails.
|
95
101
|
#
|
96
102
|
# @param [Hash] args the map of name => value pairs to validate
|
97
|
-
# @raise [ArgumentError] when any value in args hash is nil or empty.
|
98
|
-
# key will be used to construct an
|
103
|
+
# @raise [ArgumentError] when any value in args hash is nil or empty.
|
104
|
+
# The name key will be used to construct an
|
105
|
+
# informative error message.
|
99
106
|
def validate_required!(args)
|
100
107
|
errors = validate_required(args)
|
101
108
|
raise errors.first unless errors.empty?
|
102
109
|
end
|
103
110
|
|
104
|
-
# Validates the required values, returning a boolean indicating validation
|
111
|
+
# Validates the required values, returning a boolean indicating validation
|
112
|
+
# success.
|
105
113
|
#
|
106
114
|
# @param [Hash] args the map of name => value pairs to validate
|
107
|
-
# @return [true,false] true when validation passes; false when validation
|
115
|
+
# @return [true,false] true when validation passes; false when validation
|
116
|
+
# fails
|
108
117
|
def validate_required?(args)
|
109
118
|
validate_required(args).empty?
|
110
119
|
end
|
111
120
|
|
112
|
-
# Validates the length of a value, raising an error to indicate validation
|
121
|
+
# Validates the length of a value, raising an error to indicate validation
|
122
|
+
# failure.
|
113
123
|
#
|
114
124
|
# @param (see .validate_length)
|
115
125
|
# @raise [ArgumentError] when the value is longer than max_length
|
@@ -118,33 +128,37 @@ module Modelish
|
|
118
128
|
raise error if error
|
119
129
|
end
|
120
130
|
|
121
|
-
# Validates the length of a value, returning a boolean to indicate
|
122
|
-
# success.
|
131
|
+
# Validates the length of a value, returning a boolean to indicate
|
132
|
+
# validation success.
|
123
133
|
#
|
124
134
|
# @param (see .validate_length)
|
125
|
-
# @return [true,false] true if value does not exceed max_length; false
|
135
|
+
# @return [true,false] true if value does not exceed max_length; false
|
136
|
+
# otherwise
|
126
137
|
def validate_length?(name, value, max_length)
|
127
138
|
validate_length(name, value, max_length).nil?
|
128
139
|
end
|
129
140
|
|
130
|
-
# Validates the length of a value, returning an error when validation
|
141
|
+
# Validates the length of a value, returning an error when validation
|
142
|
+
# fails.
|
131
143
|
#
|
132
|
-
# @param [Symbol,String] name the
|
144
|
+
# @param [Symbol,String] name the property/argument to validate
|
133
145
|
# @param [#length] value the value to be validated
|
134
146
|
# @param [#to_i] max_length the maximum allowable length
|
135
147
|
# @raise [ArgumentError] when the value is longer than max_length
|
136
148
|
def validate_length(name, value, max_length)
|
137
149
|
if max_length.to_i > 0 && value.to_s.length > max_length.to_i
|
138
|
-
|
150
|
+
message = "#{name} must be less than #{max_length} characters"
|
151
|
+
ArgumentError.new(message)
|
139
152
|
end
|
140
153
|
end
|
141
154
|
|
142
|
-
# Validates the type of the value, returning a boolean indicating
|
143
|
-
# outcome.
|
155
|
+
# Validates the type of the value, returning a boolean indicating
|
156
|
+
# validation outcome.
|
144
157
|
#
|
145
158
|
# @see #validate_type
|
146
159
|
# @param {see #validate_type}
|
147
|
-
# @return [true,false] true when the value is the correct type; false
|
160
|
+
# @return [true,false] true when the value is the correct type; false
|
161
|
+
# otherwise
|
148
162
|
def validate_type?(name, value, type)
|
149
163
|
validate_type(name, value, type).nil?
|
150
164
|
end
|
@@ -160,18 +174,19 @@ module Modelish
|
|
160
174
|
raise error if error
|
161
175
|
end
|
162
176
|
|
163
|
-
# Validates the type of the value, returning an error when the value
|
164
|
-
# be converted to the appropriate type.
|
177
|
+
# Validates the type of the value, returning an error when the value
|
178
|
+
# cannot be converted to the appropriate type.
|
165
179
|
#
|
166
|
-
# @param [Symbol,String] name the
|
180
|
+
# @param [Symbol,String] name the property/argument to validate
|
167
181
|
# @param [Object] value the value to be validated
|
168
|
-
# @param [Class,Proc] type the type of the class to
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
182
|
+
# @param [Class,Proc] type the type of the class to validate.
|
183
|
+
# Supported types include:
|
184
|
+
# * +Integer+
|
185
|
+
# * +Float+
|
186
|
+
# * +Date+
|
187
|
+
# * +DateTime+
|
188
|
+
# * +Symbol+
|
189
|
+
# * any arbitrary +Class+ -- validates based on the results of is_a?
|
175
190
|
# @return [ArgumentError] when validation fails
|
176
191
|
def validate_type(name, value, type)
|
177
192
|
error = nil
|
@@ -192,11 +207,15 @@ module Modelish
|
|
192
207
|
end
|
193
208
|
|
194
209
|
unless is_valid
|
195
|
-
|
210
|
+
message = "#{name} must be of type #{type}, " \
|
211
|
+
"but got #{value.inspect}"
|
212
|
+
error = ArgumentError.new(message)
|
196
213
|
end
|
197
214
|
end
|
198
215
|
rescue StandardError => e
|
199
|
-
|
216
|
+
message = "An error occurred validating #{name} with " \
|
217
|
+
"value #{value.inspect}: #{e.message}"
|
218
|
+
error = ArgumentError.new(message)
|
200
219
|
end
|
201
220
|
|
202
221
|
error
|
data/lib/modelish/version.rb
CHANGED
data/lib/modelish.rb
CHANGED
data/modelish.gemspec
CHANGED
@@ -1,29 +1,34 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
5
|
+
require 'modelish/version'
|
4
6
|
|
5
7
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
8
|
+
s.name = 'modelish'
|
7
9
|
s.version = Modelish::VERSION
|
8
10
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = [
|
10
|
-
s.email = [
|
11
|
-
s.homepage =
|
12
|
-
s.summary =
|
13
|
-
s.description =
|
14
|
-
|
15
|
-
s.rubyforge_project = s.name
|
11
|
+
s.authors = ['Maeve Revels']
|
12
|
+
s.email = ['maeve.revels@g5platform.com']
|
13
|
+
s.homepage = 'http://github.com/G5/modelish'
|
14
|
+
s.summary = 'A lightweight pseudo-modeling not-quite-framework'
|
15
|
+
s.description = 'Sometimes you need something just a little modelish.'
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
-
s.executables = `git ls-files -- bin/*`.split("\n")
|
20
|
-
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n")
|
20
|
+
.map { |f| File.basename(f) }
|
21
|
+
s.require_paths = ['lib']
|
21
22
|
|
22
|
-
s.add_dependency('hashie','
|
23
|
+
s.add_dependency('hashie', '>= 1.0.0')
|
23
24
|
|
24
|
-
s.add_development_dependency('
|
25
|
+
s.add_development_dependency('appraisal')
|
26
|
+
s.add_development_dependency('fuubar')
|
27
|
+
s.add_development_dependency('rspec', '~> 3.6')
|
28
|
+
s.add_development_dependency('rspec-its')
|
29
|
+
s.add_development_dependency('simplecov')
|
25
30
|
s.add_development_dependency('yard', '~> 0.6')
|
26
|
-
s.add_development_dependency('bluecloth','~> 2.0
|
31
|
+
s.add_development_dependency('bluecloth', '~> 2.0')
|
27
32
|
|
28
33
|
s.has_rdoc = true
|
29
34
|
end
|