gourami 0.4.0 → 1.3.0
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 +5 -5
- data/README.md +5 -1
- data/Rakefile +14 -0
- data/gourami.gemspec +3 -2
- data/lib/gourami.rb +1 -0
- data/lib/gourami/attribute_name_conflict_error.rb +4 -0
- data/lib/gourami/attributes.rb +6 -0
- data/lib/gourami/coercer.rb +69 -54
- data/lib/gourami/extensions/resources.rb +22 -0
- data/lib/gourami/validation_error.rb +32 -2
- data/lib/gourami/validations.rb +17 -4
- data/lib/gourami/version.rb +1 -1
- metadata +30 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9aeeb89759c11dd7f9559824ccfd42bc6ab7755aa2d60f11b8a38e5b0db08902
|
4
|
+
data.tar.gz: 80c1968c495c2cff9277b4bd51c0340bd8381874dc864d53dab711091f61443a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97af9a59317e79d499c95b7b05f31a5089e9f56c7b7970818c22b36482de075f646f212b12e41ad4b53d9be1e967c34b08b34e55c46a90e033151f46416208dc
|
7
|
+
data.tar.gz: 48979f3194878e519431c3a46deb3da5eea9dc624731483f89e8006370d84c30027445b4ac6b31f0ca91b1d669539ad79edf988c51a2d8b2f56f7877b1659cdd
|
data/README.md
CHANGED
@@ -252,7 +252,11 @@ end
|
|
252
252
|
|
253
253
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
254
254
|
|
255
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
255
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
256
|
+
|
257
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
258
|
+
|
259
|
+
To add another gem owner to gourami gem `gem owner --add john.smith@example.com gourami`
|
256
260
|
|
257
261
|
## Contributing
|
258
262
|
|
data/Rakefile
CHANGED
@@ -8,4 +8,18 @@ Rake::TestTask.new(:test) do |t|
|
|
8
8
|
end
|
9
9
|
|
10
10
|
task :spec => :test
|
11
|
+
namespace :test do
|
12
|
+
task :watch do |t, args|
|
13
|
+
require "filewatcher"
|
14
|
+
|
15
|
+
watcher = Filewatcher.new(["spec/", "lib/"], :every => true, :spinner => true, :immediate => true)
|
16
|
+
watcher.watch do |filename, event|
|
17
|
+
begin
|
18
|
+
Rake::Task[:test].execute(args)
|
19
|
+
rescue StandardError => error
|
20
|
+
puts "Error: #{error.message}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
11
25
|
task :default => :test
|
data/gourami.gemspec
CHANGED
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
+
spec.add_development_dependency "activesupport", ">= 5.1.7"
|
25
|
+
spec.add_development_dependency "filewatcher", "~> 1.1.0"
|
26
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
24
27
|
spec.add_development_dependency "pry", "~>0.10"
|
25
|
-
spec.add_development_dependency "bundler", "~> 1.13"
|
26
28
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
28
29
|
end
|
data/lib/gourami.rb
CHANGED
data/lib/gourami/attributes.rb
CHANGED
@@ -2,6 +2,7 @@ module Gourami
|
|
2
2
|
module Attributes
|
3
3
|
|
4
4
|
module ClassMethods
|
5
|
+
|
5
6
|
# Copy parent attributes to inheriting class.
|
6
7
|
#
|
7
8
|
# @param klass [Class]
|
@@ -20,11 +21,16 @@ module Gourami
|
|
20
21
|
# @block default_block
|
21
22
|
# If provided, the block will be applied to options as the :default
|
22
23
|
def attribute(name, options = {}, &default_block)
|
24
|
+
base = self
|
23
25
|
options = options.dup
|
24
26
|
options[:default] = default_block if block_given?
|
25
27
|
|
26
28
|
mixin = Module.new do |mixin|
|
27
29
|
unless options[:skip_reader]
|
30
|
+
if !base.attributes.key?(name) && base.instance_methods.include?(name) && !options[:override_reader]
|
31
|
+
raise AttributeNameConflictError, "#{name} is already a method. To use the existing method, use `:skip_reader => true` option. To override the existing method, use `:override_reader => true` option."
|
32
|
+
end
|
33
|
+
|
28
34
|
mixin.send(:define_method, :"#{name}") do
|
29
35
|
value = instance_variable_get(:"@#{name}")
|
30
36
|
default = options[:default]
|
data/lib/gourami/coercer.rb
CHANGED
@@ -11,10 +11,7 @@ module Gourami
|
|
11
11
|
# @return [*]
|
12
12
|
def setter_filter(attribute_name, value, options)
|
13
13
|
type = options[:type]
|
14
|
-
|
15
|
-
if type
|
16
|
-
value = send(coercer_method_name, value, options)
|
17
|
-
end
|
14
|
+
value = send(:"coerce_#{type}", value, options) if type
|
18
15
|
|
19
16
|
super(attribute_name, value, options)
|
20
17
|
end
|
@@ -23,12 +20,17 @@ module Gourami
|
|
23
20
|
#
|
24
21
|
# @param value [Object]
|
25
22
|
# @option allow_nil [Boolean] (true)
|
23
|
+
# @option nil_when_empty [Boolean] (true)
|
26
24
|
# @option upcase [Boolean] (false)
|
27
25
|
# @option strip [Boolean] (true)
|
28
26
|
#
|
29
27
|
# @return [String, nil]
|
30
28
|
def coerce_string(value, options = {})
|
31
|
-
|
29
|
+
if options.fetch(:allow_nil, true)
|
30
|
+
return if value.nil?
|
31
|
+
value = value.to_s
|
32
|
+
return if value.empty? && options.fetch(:nil_when_empty, false)
|
33
|
+
end
|
32
34
|
|
33
35
|
value = value.to_s.dup.force_encoding(Encoding::UTF_8)
|
34
36
|
value.strip! if options.fetch(:strip, true)
|
@@ -44,9 +46,9 @@ module Gourami
|
|
44
46
|
#
|
45
47
|
# @return [Boolean, nil]
|
46
48
|
def coerce_boolean(value, options = {})
|
47
|
-
return
|
49
|
+
return if options[:allow_nil] && (value.nil? || value == "")
|
48
50
|
return false if value.to_s.strip == "false"
|
49
|
-
!!value && !coerce_string(value).strip.empty?
|
51
|
+
!!value && !coerce_string(value, :allow_nil => false).strip.empty?
|
50
52
|
end
|
51
53
|
|
52
54
|
# Coerce the value into an Array.
|
@@ -63,31 +65,29 @@ module Gourami
|
|
63
65
|
# @return [Array]
|
64
66
|
# The coerced Array.
|
65
67
|
def coerce_array(value, options = {})
|
68
|
+
return if options[:allow_nil] && value.nil?
|
69
|
+
|
66
70
|
element_type = options[:element_type]
|
67
|
-
value = value.values if value.
|
71
|
+
value = value.values if value.is_a?(Hash)
|
68
72
|
|
69
|
-
if options[:split_by] && value.
|
73
|
+
if options[:split_by] && value.is_a?(String)
|
70
74
|
value = value.split(options[:split_by]).map(&:strip)
|
71
75
|
end
|
72
76
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
element_type_options = {}
|
80
|
-
end
|
81
|
-
|
82
|
-
coercer_method_name = :"coerce_#{element_type}"
|
83
|
-
value.map do |array_element|
|
84
|
-
send(coercer_method_name, array_element, element_type_options)
|
85
|
-
end
|
86
|
-
else
|
87
|
-
value
|
88
|
-
end
|
77
|
+
return [] unless value.is_a?(Array)
|
78
|
+
return value unless element_type
|
79
|
+
|
80
|
+
if element_type.is_a?(Hash)
|
81
|
+
element_type_options = element_type
|
82
|
+
element_type = element_type[:type]
|
89
83
|
else
|
90
|
-
|
84
|
+
element_type_options = {}
|
85
|
+
end
|
86
|
+
|
87
|
+
coercer_method_name = :"coerce_#{element_type}"
|
88
|
+
|
89
|
+
value.map do |array_element|
|
90
|
+
send(coercer_method_name, array_element, element_type_options)
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -96,7 +96,7 @@ module Gourami
|
|
96
96
|
# @param value [Object]
|
97
97
|
#
|
98
98
|
# @return [Float, nil]
|
99
|
-
def coerce_float(value,
|
99
|
+
def coerce_float(value, _options = {})
|
100
100
|
Float(value) rescue nil
|
101
101
|
end
|
102
102
|
|
@@ -107,7 +107,8 @@ module Gourami
|
|
107
107
|
#
|
108
108
|
# @return [String, nil]
|
109
109
|
def coerce_phone(value, options = {})
|
110
|
-
value
|
110
|
+
value = coerce_string(value, options)
|
111
|
+
value ? value.upcase.gsub(/[^+0-9A-Z]/, "") : nil
|
111
112
|
end
|
112
113
|
|
113
114
|
# Coerce the value into a Hash.
|
@@ -118,23 +119,39 @@ module Gourami
|
|
118
119
|
# The type of the hash keys to coerce, no coersion if value is nil.
|
119
120
|
# @option options :value_type [Symbol, Callable] (nil)
|
120
121
|
# The type of the hash values to coerce, no coersion if value is nil.
|
122
|
+
# @option options :indifferent_access [Boolean] (false)
|
123
|
+
# When true, the resulting Hash will be an ActiveSupport::HashWithIndifferentAccess
|
121
124
|
#
|
122
|
-
# @return [Hash]
|
125
|
+
# @return [Hash, ActiveSupport::HashWithIndifferentAccess]
|
123
126
|
# The coerced Hash.
|
124
127
|
def coerce_hash(value, options = {})
|
128
|
+
return if options[:allow_nil] && value.nil?
|
129
|
+
|
125
130
|
hash_key_type = options[:key_type]
|
126
131
|
hash_value_type = options[:value_type]
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
132
|
+
|
133
|
+
hash_class = options[:indifferent_access] ? ActiveSupport::HashWithIndifferentAccess : Hash
|
134
|
+
hash = hash_class.new
|
135
|
+
|
136
|
+
return hash unless value.is_a?(Hash) || (defined?(Sequel::Postgres::JSONHash) && value.is_a?(Sequel::Postgres::JSONHash))
|
137
|
+
|
138
|
+
value.each_with_object(hash) do |(key, value), coerced_hash|
|
139
|
+
key_type = hash_key_type.respond_to?(:call) ? hash_key_type.call(key, value) : hash_key_type
|
140
|
+
key = send(:"coerce_#{key_type}", key) if key_type
|
141
|
+
|
142
|
+
value_type = hash_value_type.respond_to?(:call) ? hash_value_type.call(key, value) : hash_value_type
|
143
|
+
|
144
|
+
# TODO: Refactor shared logic here and coerce_array to a method like `type, options = resolve_coercer_type_and_options`
|
145
|
+
if value_type.is_a?(Hash)
|
146
|
+
value_type_options = value_type
|
147
|
+
value_type = value_type[:type]
|
148
|
+
else
|
149
|
+
value_type_options = {}
|
135
150
|
end
|
136
|
-
|
137
|
-
{}
|
151
|
+
|
152
|
+
value = send(:"coerce_#{value_type}", value, value_type_options) if value_type
|
153
|
+
|
154
|
+
coerced_hash[key] = value
|
138
155
|
end
|
139
156
|
end
|
140
157
|
|
@@ -145,13 +162,11 @@ module Gourami
|
|
145
162
|
#
|
146
163
|
# @return [Integer, nil]
|
147
164
|
# An Integer if the value can be coerced or nil otherwise.
|
148
|
-
def coerce_integer(value,
|
165
|
+
def coerce_integer(value, _options = {})
|
149
166
|
value = value.to_s
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
nil
|
154
|
-
end
|
167
|
+
return unless value =~ /\A0|[1-9]\d*\z/
|
168
|
+
|
169
|
+
value.to_i
|
155
170
|
end
|
156
171
|
|
157
172
|
# Coerce the value into a Date.
|
@@ -163,7 +178,7 @@ module Gourami
|
|
163
178
|
# A Date if the value can be coerced or nil otherwise.
|
164
179
|
def coerce_date(value, options = {})
|
165
180
|
value = coerce_string(value, options)
|
166
|
-
return
|
181
|
+
return if value.nil?
|
167
182
|
begin
|
168
183
|
Date.strptime(value, "%Y-%m-%d")
|
169
184
|
rescue ArgumentError
|
@@ -180,7 +195,7 @@ module Gourami
|
|
180
195
|
# A Time if the value can be coerced or nil otherwise.
|
181
196
|
def coerce_time(value, options = {})
|
182
197
|
value = coerce_string(value, options)
|
183
|
-
return
|
198
|
+
return if !value || value.empty?
|
184
199
|
|
185
200
|
begin
|
186
201
|
Time.parse(value).utc
|
@@ -198,13 +213,13 @@ module Gourami
|
|
198
213
|
# @return [Hash, nil]
|
199
214
|
# The hash will contain the file String :filename and the File :tempfile,
|
200
215
|
# or nil otherwise.
|
201
|
-
def coerce_file(value,
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
216
|
+
def coerce_file(value, _options = {})
|
217
|
+
return unless value.is_a?(Hash) && !value[:filename].to_s.empty?
|
218
|
+
|
219
|
+
tempfile = value[:tempfile]
|
220
|
+
return unless tempfile.is_a?(File) || tempfile.is_a?(Tempfile)
|
221
|
+
|
222
|
+
value
|
208
223
|
end
|
209
224
|
|
210
225
|
end
|
@@ -91,6 +91,28 @@ module Gourami
|
|
91
91
|
resource_errors.values.flat_map(&:values).map(&:values).flatten.any?
|
92
92
|
end
|
93
93
|
|
94
|
+
# Replace the existing resource errors with the provided errors Hash.
|
95
|
+
#
|
96
|
+
# @param new_resource_errors [Hash<Symbol, Hash<Symbol, Hash<Symbol, Array>>>]
|
97
|
+
#
|
98
|
+
# @return [Hash<Symbol, Hash<Symbol, Hash<Symbol, Array>>>]
|
99
|
+
def clear_and_set_resource_errors(new_resource_errors)
|
100
|
+
new_resource_errors = new_resource_errors.dup
|
101
|
+
resource_errors.clear
|
102
|
+
resource_errors.merge!(new_resource_errors)
|
103
|
+
|
104
|
+
resource_errors
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_validation_error(error)
|
108
|
+
super(error)
|
109
|
+
clear_and_set_resource_errors(error.resource_errors) unless error.resource_errors.nil?
|
110
|
+
end
|
111
|
+
|
112
|
+
def raise_validate_errors
|
113
|
+
raise ValidationError.new(errors, resource_errors)
|
114
|
+
end
|
115
|
+
|
94
116
|
end
|
95
117
|
end
|
96
118
|
end
|
@@ -9,20 +9,39 @@ module Gourami
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
def self.stringify_resource_errors(resource_errors)
|
13
|
+
[].tap do |array|
|
14
|
+
resource_errors.each do |resource_namespace, resource_namespace_errors|
|
15
|
+
resource_namespace_errors.each do |resource_uid, resource_uid_errors|
|
16
|
+
resource_uid_errors.each do |attribute_name, error|
|
17
|
+
array.push("#{resource_namespace}:#{resource_uid}:#{attribute_name}: #{error}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
12
24
|
# !@attribute [r] errors
|
13
25
|
# @return [Hash<Symbol, Array>]
|
14
26
|
attr_reader :errors
|
15
27
|
|
28
|
+
# !@attribute [r] resource_errors
|
29
|
+
# @return [Hash<Symbol, Hash<Symbol, Hash<Symbol, Array>>>]
|
30
|
+
attr_reader :resource_errors
|
31
|
+
|
16
32
|
# Initialize the Gourami::ValidationError.
|
17
33
|
#
|
18
34
|
# @param errors [Hash<Symbol, Array>]
|
19
|
-
|
35
|
+
# @param resource_errors [Hash<Symbol, Hash<Symbol, Hash<Symbol, Array>>>]
|
36
|
+
def initialize(errors, resource_errors = {})
|
37
|
+
@resource_errors = resource_errors
|
20
38
|
@errors = errors
|
39
|
+
|
21
40
|
super(message)
|
22
41
|
end
|
23
42
|
|
24
43
|
def message
|
25
|
-
@message ||=
|
44
|
+
@message ||= stringify_all_errors
|
26
45
|
end
|
27
46
|
|
28
47
|
private
|
@@ -31,5 +50,16 @@ module Gourami
|
|
31
50
|
ValidationError.stringify_errors(errors)
|
32
51
|
end
|
33
52
|
|
53
|
+
def stringify_resource_errors
|
54
|
+
ValidationError.stringify_resource_errors(resource_errors)
|
55
|
+
end
|
56
|
+
|
57
|
+
def stringify_all_errors
|
58
|
+
messages = []
|
59
|
+
messages << "Validation failed with errors: #{stringify_errors.join("\n")}" unless errors.nil? || errors.empty?
|
60
|
+
messages << "Validation failed with resource errors: #{stringify_resource_errors.join("\n")}" unless resource_errors.nil? || resource_errors.empty?
|
61
|
+
messages.join("\n")
|
62
|
+
end
|
63
|
+
|
34
64
|
end
|
35
65
|
end
|
data/lib/gourami/validations.rb
CHANGED
@@ -15,11 +15,16 @@ module Gourami
|
|
15
15
|
# @raise [Gourami::ValidationError]
|
16
16
|
def perform!
|
17
17
|
if valid?
|
18
|
-
|
18
|
+
begin
|
19
|
+
returned = perform
|
20
|
+
rescue Gourami::ValidationError => error
|
21
|
+
handle_validation_error(error)
|
22
|
+
raise
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
if any_errors?
|
22
|
-
|
27
|
+
raise_validate_errors
|
23
28
|
end
|
24
29
|
|
25
30
|
returned
|
@@ -46,9 +51,9 @@ module Gourami
|
|
46
51
|
|
47
52
|
# Replace the existing errors with the provided errors Hash.
|
48
53
|
#
|
49
|
-
# @param new_errors
|
54
|
+
# @param new_errors Hash<Symbol, Array>
|
50
55
|
#
|
51
|
-
# @return
|
56
|
+
# @return Hash<Symbol, Array>
|
52
57
|
def clear_and_set_errors(new_errors)
|
53
58
|
new_errors = new_errors.dup
|
54
59
|
errors.clear
|
@@ -57,6 +62,14 @@ module Gourami
|
|
57
62
|
errors
|
58
63
|
end
|
59
64
|
|
65
|
+
def raise_validate_errors
|
66
|
+
raise ValidationError.new(errors)
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_validation_error(error)
|
70
|
+
clear_and_set_errors(error.errors) unless error.errors.nil?
|
71
|
+
end
|
72
|
+
|
60
73
|
# Return true if there given attribute has any errors.
|
61
74
|
def attribute_has_errors?(attribute_name)
|
62
75
|
errors[attribute_name.to_sym].any?
|
data/lib/gourami/version.rb
CHANGED
metadata
CHANGED
@@ -1,71 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gourami
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TSMMark
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.1.7
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.1.7
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: filewatcher
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - "~>"
|
18
32
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
33
|
+
version: 1.1.0
|
20
34
|
type: :development
|
21
35
|
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
40
|
+
version: 1.1.0
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
42
|
+
name: minitest
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
47
|
+
version: '5.0'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
54
|
+
version: '5.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: pry
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '10
|
61
|
+
version: '0.10'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '10
|
68
|
+
version: '0.10'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
70
|
+
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
75
|
+
version: '10.0'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
82
|
+
version: '10.0'
|
69
83
|
description: Create Plain Old Ruby Objects that take attributes, validate them, and
|
70
84
|
perform an action.
|
71
85
|
email:
|
@@ -85,6 +99,7 @@ files:
|
|
85
99
|
- bin/setup
|
86
100
|
- gourami.gemspec
|
87
101
|
- lib/gourami.rb
|
102
|
+
- lib/gourami/attribute_name_conflict_error.rb
|
88
103
|
- lib/gourami/attributes.rb
|
89
104
|
- lib/gourami/coercer.rb
|
90
105
|
- lib/gourami/configuration_error.rb
|
@@ -118,8 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
133
|
- !ruby/object:Gem::Version
|
119
134
|
version: '0'
|
120
135
|
requirements: []
|
121
|
-
|
122
|
-
rubygems_version: 2.4.6
|
136
|
+
rubygems_version: 3.0.4
|
123
137
|
signing_key:
|
124
138
|
specification_version: 4
|
125
139
|
summary: Keep your Routes, Controllers and Models thin.
|