attributor 7.1 → 8.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 +4 -4
- data/.travis.yml +1 -3
- data/CHANGELOG.md +6 -2
- data/attributor.gemspec +3 -2
- data/lib/attributor/attribute.rb +13 -12
- data/lib/attributor/extras/field_selector.rb +1 -1
- data/lib/attributor/types/bigdecimal.rb +1 -1
- data/lib/attributor/types/date.rb +2 -2
- data/lib/attributor/types/date_time.rb +3 -2
- data/lib/attributor/types/polymorphic.rb +1 -1
- data/lib/attributor/types/string.rb +1 -10
- data/lib/attributor/types/tempfile.rb +1 -1
- data/lib/attributor/types/time.rb +3 -3
- data/lib/attributor/types/uri.rb +1 -1
- data/lib/attributor/version.rb +1 -1
- data/lib/attributor.rb +4 -5
- data/spec/attribute_spec.rb +1 -25
- data/spec/support/hashes.rb +1 -1
- data/spec/support/models.rb +16 -16
- data/spec/types/csv_spec.rb +1 -1
- data/spec/types/date_spec.rb +6 -6
- data/spec/types/model_spec.rb +1 -1
- data/spec/types/string_spec.rb +0 -8
- metadata +9 -10
- data/lib/attributor/extensions/randexp.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bec1eaa11a8711121f24b64eb86dcedc3779012f3ccc2239882bfa38527a0db
|
4
|
+
data.tar.gz: 15e6274f319f78d5c7801015ed5a97fd3858727ce98956a2e3b0229c89bdf25c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1055363cc837a07b3c319f0cfec62293797361a713354c146e3c1bead0b2fa0cbb2313dfcf092400abc57f5101a6fc76b782ba51bb9876c09720c2a382bb09de
|
7
|
+
data.tar.gz: 0aea79491d61b6ab866aec643c93d18bd372b8afc63428ba69d4a9723d0fd55a24589ea182a4ed2a0029e30a55f522981010f5637a54ea98af68ec0f41b48ec7
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# Attributor Changelog
|
2
2
|
|
3
|
-
##
|
3
|
+
## 8.0
|
4
|
+
|
5
|
+
- Add support for Ruby 3.2.
|
6
|
+
- Remove usage of Randexp for examples and replace with Faker.
|
7
|
+
- The above means this also removes support for generating examples using regular expressions.
|
4
8
|
|
5
9
|
## 7.1 (6/9/2023)
|
6
10
|
- Enhance custom_option handling. The values provided for custom options are now loaded (and definition will fail if they aren't compatible). This was specially
|
@@ -37,7 +41,7 @@
|
|
37
41
|
- added support for enum's out of values in json_schema generation
|
38
42
|
|
39
43
|
## 6.0 (22/11/2021)
|
40
|
-
- removed `required_if` support and all of the necessary code.
|
44
|
+
- removed `required_if` support and all of the necessary code.
|
41
45
|
- changed the semantics of the `required:` option in attributes, to really mean if the "key" is required to be passed in or not (i.e., check if the key is null, not if its value is null)
|
42
46
|
- Introduced a new option`null: true|false` to allow for the value of an attribute to be nullable or not when the attribute is passed in.
|
43
47
|
* The default behavior for an attribute nullability currently `null: false` (but it can be easily changed by overriding the `Attributor::Attribute.default_for_null` function to return `true`)
|
data/attributor.gemspec
CHANGED
@@ -13,14 +13,14 @@ Gem::Specification.new do |spec|
|
|
13
13
|
|
14
14
|
spec.homepage = 'https://github.com/rightscale/attributor'
|
15
15
|
spec.license = 'MIT'
|
16
|
-
spec.required_ruby_version = '>=2.
|
16
|
+
spec.required_ruby_version = '>=2.7'
|
17
17
|
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
spec.files = `git ls-files -z`.split("\x0")
|
20
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
21
|
|
22
22
|
spec.add_runtime_dependency('hashie', ['~> 3'])
|
23
|
-
spec.add_runtime_dependency('
|
23
|
+
spec.add_runtime_dependency('faker', [' >= 3.2'])
|
24
24
|
spec.add_runtime_dependency('activesupport', ['>= 3'])
|
25
25
|
|
26
26
|
spec.add_development_dependency 'rspec', '~> 3'
|
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_development_dependency('guard', ['~> 2'])
|
35
35
|
spec.add_development_dependency('guard-rspec', ['~> 4'])
|
36
36
|
spec.add_development_dependency('pry')
|
37
|
+
|
37
38
|
if RUBY_PLATFORM !~ /java/
|
38
39
|
spec.add_development_dependency('pry-byebug')
|
39
40
|
spec.add_development_dependency('pry-stack_explorer')
|
data/lib/attributor/attribute.rb
CHANGED
@@ -27,7 +27,7 @@ module Attributor
|
|
27
27
|
|
28
28
|
class << self
|
29
29
|
attr_accessor :custom_options
|
30
|
-
end
|
30
|
+
end
|
31
31
|
|
32
32
|
def self.custom_option(name, attr_type, options = {}, &block)
|
33
33
|
if TOP_LEVEL_OPTIONS.include?(name) || INTERNAL_OPTIONS.include?(name)
|
@@ -47,7 +47,7 @@ module Attributor
|
|
47
47
|
current_option_name = nil # Use this to avoid having to wrap each loop with a begin/rescue block
|
48
48
|
(self.class.custom_options.keys & @options.keys).each do |custom_key|
|
49
49
|
current_option_name = custom_key
|
50
|
-
@options[custom_key] = self.class.custom_options[custom_key].load(@options[custom_key])
|
50
|
+
@options[custom_key] = self.class.custom_options[custom_key].load(@options[custom_key])
|
51
51
|
end
|
52
52
|
rescue => e
|
53
53
|
raise AttributorException, "Error while loading value #{@options[current_option_name]} for custom option '#{current_option_name}': #{e.message}"
|
@@ -156,8 +156,6 @@ module Attributor
|
|
156
156
|
def example_from_options(parent, context)
|
157
157
|
val = options[:example]
|
158
158
|
generated = case val
|
159
|
-
when ::Regexp
|
160
|
-
val.gen
|
161
159
|
when ::Proc
|
162
160
|
if val.arity == 2
|
163
161
|
val.call(parent, context)
|
@@ -211,8 +209,10 @@ module Attributor
|
|
211
209
|
description
|
212
210
|
end
|
213
211
|
|
214
|
-
def example(context=nil, parent: nil, values:{})
|
215
|
-
|
212
|
+
def example(context = nil, parent: nil, values: {})
|
213
|
+
require 'faker'
|
214
|
+
raise ArgumentError, 'attribute example cannot take a context of type String' if context.is_a? ::String
|
215
|
+
|
216
216
|
if context
|
217
217
|
ctx = Attributor.humanize_context(context)
|
218
218
|
seed, = Digest::SHA1.digest(ctx).unpack('QQ')
|
@@ -226,10 +226,11 @@ module Attributor
|
|
226
226
|
# Only validate the type, if the proc-generated example is "complex" (has attributes)
|
227
227
|
errors = loaded.class.respond_to?(:attributes) ? validate_type(loaded, context) : validate(loaded, context)
|
228
228
|
raise AttributorException, "Error generating example for #{Attributor.humanize_context(context)}. Errors: #{errors.inspect}" if errors.any?
|
229
|
+
|
229
230
|
return loaded
|
230
231
|
end
|
231
232
|
|
232
|
-
return options[:values].
|
233
|
+
return options[:values].sample if options.key? :values
|
233
234
|
|
234
235
|
if type.respond_to?(:attributes)
|
235
236
|
type.example(context, **values)
|
@@ -242,7 +243,7 @@ module Attributor
|
|
242
243
|
type.attributes if @type_has_attributes ||= type.respond_to?(:attributes)
|
243
244
|
end
|
244
245
|
|
245
|
-
# Default value for a non-specified null: option
|
246
|
+
# Default value for a non-specified null: option
|
246
247
|
def self.default_for_null
|
247
248
|
false
|
248
249
|
end
|
@@ -272,7 +273,7 @@ module Attributor
|
|
272
273
|
end
|
273
274
|
|
274
275
|
return errors if errors.any?
|
275
|
-
|
276
|
+
|
276
277
|
object.nil? ? errors : errors + type.validate(object, context, self)
|
277
278
|
end
|
278
279
|
|
@@ -303,7 +304,7 @@ module Attributor
|
|
303
304
|
raise AttributorException, 'Required must be a boolean' unless definition == true || definition == false
|
304
305
|
raise AttributorException, 'Required cannot be enabled in combination with :default' if definition == true && options.key?(:default)
|
305
306
|
when :null
|
306
|
-
raise AttributorException, 'Null must be a boolean' unless definition == true || definition == false
|
307
|
+
raise AttributorException, 'Null must be a boolean' unless definition == true || definition == false
|
307
308
|
when :example
|
308
309
|
unless definition.is_a?(::Regexp) || definition.is_a?(::String) || definition.is_a?(::Array) || definition.is_a?(::Proc) || definition.nil? || type.valid_type?(definition)
|
309
310
|
raise AttributorException, "Invalid example type (got: #{definition.class.name}). It must always match the type of the attribute (except if passing Regex that is allowed for some types)"
|
@@ -317,8 +318,8 @@ module Attributor
|
|
317
318
|
:ok # passes
|
318
319
|
end
|
319
320
|
|
320
|
-
def check_custom_option(name, definition)
|
321
|
-
attribute = self.class.custom_options.fetch(name)
|
321
|
+
def check_custom_option(name, definition)
|
322
|
+
attribute = self.class.custom_options.fetch(name)
|
322
323
|
|
323
324
|
errors = attribute.validate(definition)
|
324
325
|
raise AttributorException, "Custom option #{name.inspect} is invalid: #{errors.inspect}" if errors.any?
|
@@ -9,7 +9,7 @@ module Attributor
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.example(_context = nil, options: {})
|
12
|
-
BigDecimal("#{
|
12
|
+
BigDecimal("#{Faker::Number.decimal(l_digits: 3, r_digits: 3)}")
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.load(value, _context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
|
@@ -9,7 +9,7 @@ module Attributor
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.example(context = nil, options: {})
|
12
|
-
load(
|
12
|
+
load(Faker::Date.in_date_period, context)
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
|
@@ -21,7 +21,7 @@ module Attributor
|
|
21
21
|
case value
|
22
22
|
when ::String
|
23
23
|
begin
|
24
|
-
|
24
|
+
::Date.parse(value)
|
25
25
|
rescue ArgumentError
|
26
26
|
raise Attributor::DeserializationError.new(context: context, from: value.class, encoding: 'Date', value: value)
|
27
27
|
end
|
@@ -13,7 +13,7 @@ module Attributor
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.example(context = nil, options: {})
|
16
|
-
load(
|
16
|
+
load(Faker::Date.in_date_period, context)
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
|
@@ -21,10 +21,11 @@ module Attributor
|
|
21
21
|
return value if value.is_a?(native_type)
|
22
22
|
return value.to_datetime if value.respond_to?(:to_datetime)
|
23
23
|
return nil unless value.is_a?(::String)
|
24
|
+
|
24
25
|
# TODO: we should be able to convert not only from String but Time...etc
|
25
26
|
# Else, we'll decode it from String.
|
26
27
|
begin
|
27
|
-
|
28
|
+
::DateTime.parse(value)
|
28
29
|
rescue ArgumentError
|
29
30
|
raise Attributor::DeserializationError.new(context: context, from: value.class, encoding: 'DateTime', value: value)
|
30
31
|
end
|
@@ -17,16 +17,7 @@ module Attributor
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.example(_context = nil, options: {})
|
20
|
-
|
21
|
-
begin
|
22
|
-
# It may fail to generate an example, see bug #72.
|
23
|
-
options[:regexp].gen
|
24
|
-
rescue => e
|
25
|
-
format('Failed to generate example for %s : %s', options[:regexp].inspect, e.message)
|
26
|
-
end
|
27
|
-
else
|
28
|
-
/\w+/.gen
|
29
|
-
end
|
20
|
+
Faker::Lorem.word
|
30
21
|
end
|
31
22
|
|
32
23
|
def self.family
|
@@ -10,7 +10,7 @@ module Attributor
|
|
10
10
|
|
11
11
|
def self.example(context = Attributor::DEFAULT_ROOT_CONTEXT, options: {})
|
12
12
|
file = ::Tempfile.new(Attributor.humanize_context(context))
|
13
|
-
file.write
|
13
|
+
file.write Faker::Lorem.paragraph
|
14
14
|
file.write '.'
|
15
15
|
file.rewind
|
16
16
|
file
|
@@ -9,7 +9,7 @@ module Attributor
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.example(context = nil, options: {})
|
12
|
-
load(
|
12
|
+
load(Faker::Time.between(from: ::DateTime.now - 1, to: ::DateTime.now), context)
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
|
@@ -24,10 +24,10 @@ module Attributor
|
|
24
24
|
def self.parse(value, context)
|
25
25
|
case value
|
26
26
|
when ::Integer
|
27
|
-
|
27
|
+
::Time.at(value)
|
28
28
|
when ::String
|
29
29
|
begin
|
30
|
-
|
30
|
+
::Time.parse(value)
|
31
31
|
rescue ArgumentError
|
32
32
|
raise Attributor::DeserializationError.new(context: context, from: value.class, encoding: 'Time', value: value)
|
33
33
|
end
|
data/lib/attributor/types/uri.rb
CHANGED
data/lib/attributor/version.rb
CHANGED
data/lib/attributor.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'json'
|
2
|
-
require 'randexp'
|
3
2
|
|
4
3
|
require 'hashie'
|
5
4
|
require 'active_support/concern'
|
@@ -17,8 +16,6 @@ module Attributor
|
|
17
16
|
|
18
17
|
require_relative 'attributor/example_mixin'
|
19
18
|
|
20
|
-
require_relative 'attributor/extensions/randexp'
|
21
|
-
|
22
19
|
# hierarchical separator string for composing human readable attributes
|
23
20
|
SEPARATOR = '.'.freeze
|
24
21
|
ROOT_PREFIX = '$'.freeze
|
@@ -37,11 +34,13 @@ module Attributor
|
|
37
34
|
|
38
35
|
def self.find_type(attr_type)
|
39
36
|
return attr_type if attr_type < Attributor::Type
|
37
|
+
|
40
38
|
name = attr_type.name.split('::').last # TOO EXPENSIVE?
|
41
39
|
|
42
40
|
klass = const_get(name) if const_defined?(name)
|
43
41
|
raise AttributorException, "Could not find class with name #{name}" unless klass
|
44
42
|
raise AttributorException, "Could not find attribute type for: #{name} [klass: #{klass.name}]" unless klass < Attributor::Type
|
43
|
+
|
45
44
|
klass
|
46
45
|
end
|
47
46
|
|
@@ -57,7 +56,7 @@ module Attributor
|
|
57
56
|
context = Array(context) if context.is_a? ::String
|
58
57
|
|
59
58
|
begin
|
60
|
-
|
59
|
+
context.join('.')
|
61
60
|
rescue e
|
62
61
|
raise "Error creating context string: #{e.message}"
|
63
62
|
end
|
@@ -81,7 +80,7 @@ module Attributor
|
|
81
80
|
else
|
82
81
|
val
|
83
82
|
end
|
84
|
-
end
|
83
|
+
end
|
85
84
|
|
86
85
|
MODULE_PREFIX = 'Attributor::'.freeze
|
87
86
|
MODULE_PREFIX_REGEX = ::Regexp.new(MODULE_PREFIX)
|
data/spec/attribute_spec.rb
CHANGED
@@ -273,7 +273,7 @@ describe Attributor::Attribute do
|
|
273
273
|
end
|
274
274
|
|
275
275
|
context 'deterministic examples' do
|
276
|
-
let(:example) {
|
276
|
+
let(:example) { proc { Faker::Lorem.word } }
|
277
277
|
let(:attribute_options) { { example: example } }
|
278
278
|
|
279
279
|
it 'can take a context to pre-seed the random number generator' do
|
@@ -332,30 +332,6 @@ describe Attributor::Attribute do
|
|
332
332
|
it { should be example }
|
333
333
|
end
|
334
334
|
|
335
|
-
context 'with a regexp' do
|
336
|
-
let(:example) { Regexp.new(/\w+/) }
|
337
|
-
let(:generated_example) { /\w+/.gen }
|
338
|
-
|
339
|
-
it 'calls #gen on the regexp' do
|
340
|
-
expect(example).to receive(:gen).and_return(generated_example)
|
341
|
-
|
342
|
-
expect(example_result).to match example
|
343
|
-
end
|
344
|
-
|
345
|
-
context 'for a type with a non-String native_type' do
|
346
|
-
let(:type) { Attributor::Integer }
|
347
|
-
let(:example) { Regexp.new(/\d{5}/) }
|
348
|
-
let(:generated_example) { /\d{5}/.gen }
|
349
|
-
|
350
|
-
it 'coerces the example value properly' do
|
351
|
-
expect(example).to receive(:gen).and_return(generated_example)
|
352
|
-
expect(type).to receive(:load).and_call_original
|
353
|
-
|
354
|
-
expect(example_result).to be_kind_of(type.native_type)
|
355
|
-
end
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
335
|
context 'with a proc' do
|
360
336
|
let(:parent) { Object.new }
|
361
337
|
|
data/spec/support/hashes.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class HashWithModel < Attributor::Hash
|
2
2
|
keys do
|
3
|
-
key :name, String, default: 'Turkey McDucken', description: 'Turducken name', example:
|
3
|
+
key :name, String, default: 'Turkey McDucken', description: 'Turducken name', example: proc { Faker::Name.first_name }
|
4
4
|
key :chicken, Chicken
|
5
5
|
end
|
6
6
|
end
|
data/spec/support/models.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
class Chicken < Attributor::Model
|
2
2
|
attributes(identity: :email) do
|
3
|
-
attribute :name, Attributor::String, example:
|
3
|
+
attribute :name, Attributor::String, example: proc { Faker::Name.first_name }
|
4
4
|
attribute :age, Attributor::Integer, default: 1, min: 0, max: 120, description: 'The age of the chicken'
|
5
|
-
attribute :email, Attributor::String, example:
|
5
|
+
attribute :email, Attributor::String, example: proc { "#{Faker::Name.first_name.downcase}@#{Faker::Lorem.word.downcase}.example.org" }, regexp: /@/, description: 'The email address of the chicken'
|
6
6
|
attribute :angry, Attributor::Boolean, example: 'true', description: 'Angry bird?'
|
7
|
-
attribute :weight, Attributor::Float, example:
|
7
|
+
attribute :weight, Attributor::Float, example: proc { Faker::Number.number(digits: 3) }, description: 'The weight of the chicken'
|
8
8
|
attribute :type, Attributor::Symbol, values: [:chicken]
|
9
9
|
end
|
10
10
|
end
|
@@ -14,8 +14,8 @@ class Duck < Attributor::Model
|
|
14
14
|
attribute :age, Attributor::Integer
|
15
15
|
attribute :name, Attributor::String
|
16
16
|
attribute :email, Attributor::String
|
17
|
-
attribute :angry, Attributor::Boolean, default: true, example:
|
18
|
-
attribute :weight, Attributor::Float, example:
|
17
|
+
attribute :angry, Attributor::Boolean, default: true, example: proc { [true, false].sample }, description: 'Angry bird?'
|
18
|
+
attribute :weight, Attributor::Float, example: proc { Faker::Number.number(digits: 3).to_f }, description: 'The weight of the duck'
|
19
19
|
attribute :type, Attributor::Symbol, values: [:duck]
|
20
20
|
end
|
21
21
|
end
|
@@ -23,16 +23,16 @@ end
|
|
23
23
|
class Turkey < Attributor::Model
|
24
24
|
attributes do
|
25
25
|
attribute :age, Integer, default: 1, min: 0, max: 120, description: 'The age of the turkey'
|
26
|
-
attribute :name, String, description: 'name of the turkey', example:
|
27
|
-
attribute :email, String, example:
|
28
|
-
attribute :weight, Attributor::Float, example:
|
26
|
+
attribute :name, String, description: 'name of the turkey', example: proc { Faker::Name.name } # , :default => "Providencia Zboncak"
|
27
|
+
attribute :email, String, example: proc { "#{Faker::Name.first_name.downcase}@example.org" }, regexp: /@/, description: 'The email address of the turkey'
|
28
|
+
attribute :weight, Attributor::Float, example: proc { Faker::Number.number(digits: 2).to_f }, max: 100.0, description: 'The weight of the turkey'
|
29
29
|
attribute :type, Attributor::Symbol, values: [:turkey]
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
class Turducken < Attributor::Model
|
34
34
|
attributes do
|
35
|
-
attribute :name, String, default: 'Turkey McDucken', description: 'Turducken name', example:
|
35
|
+
attribute :name, String, default: 'Turkey McDucken', description: 'Turducken name', example: proc { Faker::Name.first_name }
|
36
36
|
attribute :chicken, Chicken
|
37
37
|
attribute :duck, Duck
|
38
38
|
attribute :turkey, Turkey, description: 'The turkey'
|
@@ -43,7 +43,7 @@ end
|
|
43
43
|
|
44
44
|
class Cormorant < Attributor::Model
|
45
45
|
attributes do
|
46
|
-
attribute :name, String, description: 'Name of the Cormorant', example:
|
46
|
+
attribute :name, String, description: 'Name of the Cormorant', example: proc { Faker::Name.name }
|
47
47
|
attribute :timestamps do
|
48
48
|
attribute :born_at, DateTime
|
49
49
|
attribute :died_at, DateTime, example: proc { |timestamps| timestamps.born_at + 10 }
|
@@ -53,22 +53,22 @@ class Cormorant < Attributor::Model
|
|
53
53
|
attribute :all_the_fish, Attributor::Collection, description: 'All kinds of fish for feeding the babies'
|
54
54
|
|
55
55
|
# This will be a collection of Cormorants (note, this relationship is circular)
|
56
|
-
attribute :neighbors, Attributor::Collection.of(Cormorant), member_options: {null: false}, description: 'Neighbor cormorants', null: false
|
56
|
+
attribute :neighbors, Attributor::Collection.of(Cormorant), member_options: { null: false }, description: 'Neighbor cormorants', null: false
|
57
57
|
|
58
58
|
# This will be a collection of instances of an anonymous Struct class, each having two well-defined attributes
|
59
59
|
|
60
60
|
attribute :babies, Attributor::Collection.of(Attributor::Struct), description: 'All the babies', member_options: { identity: :name } do
|
61
|
-
attribute :name, Attributor::String, example:
|
61
|
+
attribute :name, Attributor::String, example: proc { Faker::Name.name }, description: 'The name of the baby cormorant', required: true
|
62
62
|
attribute :months, Attributor::Integer, default: 0, min: 0, description: 'The age in months of the baby cormorant'
|
63
|
-
attribute :weight, Attributor::Float, example:
|
63
|
+
attribute :weight, Attributor::Float, example: proc { Faker::Number.number(digits: 2) }, description: 'The weight in kg of the baby cormorant'
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
68
|
class Person < Attributor::Model
|
69
69
|
attributes do
|
70
|
-
attribute :name, String, example:
|
71
|
-
attribute :title, String, values: %w
|
70
|
+
attribute :name, String, example: proc { Faker::Name.first_name }
|
71
|
+
attribute :title, String, values: %w[Mr Mrs Ms Dr]
|
72
72
|
attribute :okay, Attributor::Boolean, values: [true]
|
73
73
|
attribute :address, Address, example: proc { |person, context| Address.example(context, person: person) }
|
74
74
|
end
|
@@ -77,7 +77,7 @@ end
|
|
77
77
|
class Address < Attributor::Model
|
78
78
|
attributes do
|
79
79
|
attribute :name, String, example: /\w+/, null: true
|
80
|
-
attribute :state, String, values: %w
|
80
|
+
attribute :state, String, values: %w[OR CA], null: false
|
81
81
|
attribute :person, Person, example: proc { |address, context| Person.example(context, address: address) }
|
82
82
|
attribute :substruct, reference: Address, null: false do
|
83
83
|
attribute :state, Struct do # redefine state as a Struct
|
data/spec/types/csv_spec.rb
CHANGED
@@ -29,7 +29,7 @@ describe Attributor::CSV do
|
|
29
29
|
|
30
30
|
context '.dump' do
|
31
31
|
let!(:int_vals) { [1, 2, 3] }
|
32
|
-
let!(:str_vals) { (0..2).collect {
|
32
|
+
let!(:str_vals) { (0..2).collect { Faker::Lorem.word } }
|
33
33
|
|
34
34
|
it 'dumps a String value' do
|
35
35
|
expect(csv.dump(int_vals)).to be_a(String)
|
data/spec/types/date_spec.rb
CHANGED
@@ -19,7 +19,7 @@ describe Attributor::Date do
|
|
19
19
|
let(:example) { type.example }
|
20
20
|
subject(:value) { type.dump(example) }
|
21
21
|
it 'is formatted correctly' do
|
22
|
-
expect(value).to match(/\d{4}-\d{2}-\d{2}
|
22
|
+
expect(value).to match(/\d{4}-\d{2}-\d{2}/)
|
23
23
|
end
|
24
24
|
context 'nil values' do
|
25
25
|
it 'should be nil' do
|
@@ -59,7 +59,7 @@ describe Attributor::Date do
|
|
59
59
|
'Sat, 3 Feb 2001 04:05:06 +0700',
|
60
60
|
'2013/08/23 00:39:55 +0000',
|
61
61
|
'2007-10-19T04:11:33Z',
|
62
|
-
'2001-02-03T04:05:06+07:00.123456'
|
62
|
+
'2001-02-03T04:05:06+07:00.123456' # custom format with microseconds
|
63
63
|
].each do |value|
|
64
64
|
it "returns correct Date for #{value.inspect}" do
|
65
65
|
expect(type.load(value)).to eq Date.parse(value)
|
@@ -70,7 +70,7 @@ describe Attributor::Date do
|
|
70
70
|
'Sat, 30 Feb 2001 04:05:06 GMT', # No such date exists
|
71
71
|
'2013/08/33 00:39:55 +0000',
|
72
72
|
'2007-10-33T04:11:33Z',
|
73
|
-
'2001-02-33T04:05:06+07:00.123456'
|
73
|
+
'2001-02-33T04:05:06+07:00.123456' # custom format with microseconds
|
74
74
|
].each do |value|
|
75
75
|
it "raises Attributor::AttributorException for #{value.inspect}" do
|
76
76
|
expect do
|
@@ -82,7 +82,7 @@ describe Attributor::Date do
|
|
82
82
|
[
|
83
83
|
'',
|
84
84
|
'foobar',
|
85
|
-
'Sat, 30 Feb 2001 04:05:06 FOOBAR'
|
85
|
+
'Sat, 30 Feb 2001 04:05:06 FOOBAR' # No such date format exists
|
86
86
|
].each do |value|
|
87
87
|
it "raises Attributor::AttributorException for #{value.inspect}" do
|
88
88
|
expect do
|
@@ -93,11 +93,11 @@ describe Attributor::Date do
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
context '.as_json_schema' do
|
96
|
-
subject(:js){ type.as_json_schema }
|
96
|
+
subject(:js) { type.as_json_schema }
|
97
97
|
it 'adds the right attributes' do
|
98
98
|
expect(js.keys).to include(:type, :'x-type_name')
|
99
99
|
expect(js[:type]).to eq(:string)
|
100
|
-
expect(js[:format]).to eq(:
|
100
|
+
expect(js[:format]).to eq(:date)
|
101
101
|
expect(js[:'x-type_name']).to eq('Date')
|
102
102
|
end
|
103
103
|
end
|
data/spec/types/model_spec.rb
CHANGED
@@ -80,7 +80,7 @@ describe Attributor::Model do
|
|
80
80
|
subject(:chicken) { Chicken.example }
|
81
81
|
|
82
82
|
let(:age_opts) { { options: Chicken.attributes[:age].options } }
|
83
|
-
let(:age) {
|
83
|
+
let(:age) { Faker::Number.number(digits: 2) }
|
84
84
|
|
85
85
|
context 'for a simple model' do
|
86
86
|
it { should be_kind_of(Chicken) }
|
data/spec/types/string_spec.rb
CHANGED
@@ -22,14 +22,6 @@ describe Attributor::String do
|
|
22
22
|
expect(type.example).to be_a(::String)
|
23
23
|
end
|
24
24
|
|
25
|
-
it 'handles regexps that Randexp can not (#72)' do
|
26
|
-
regex = /\w+(,\w+)*/
|
27
|
-
expect do
|
28
|
-
val = Attributor::String.example(options: { regexp: regex })
|
29
|
-
expect(val).to be_a(::String)
|
30
|
-
expect(val).to match(/Failed to generate.+is too vague/)
|
31
|
-
end.to_not raise_error
|
32
|
-
end
|
33
25
|
end
|
34
26
|
|
35
27
|
context '.load' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attributor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '
|
4
|
+
version: '8.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josep M. Blanquer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-08-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: hashie
|
@@ -26,19 +26,19 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '3'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: faker
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
34
|
+
version: '3.2'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - "
|
39
|
+
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
41
|
+
version: '3.2'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: activesupport
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -316,7 +316,6 @@ files:
|
|
316
316
|
- lib/attributor/dumpable.rb
|
317
317
|
- lib/attributor/example_mixin.rb
|
318
318
|
- lib/attributor/exceptions.rb
|
319
|
-
- lib/attributor/extensions/randexp.rb
|
320
319
|
- lib/attributor/extras/field_selector.rb
|
321
320
|
- lib/attributor/extras/field_selector/parser.rb
|
322
321
|
- lib/attributor/extras/field_selector/transformer.rb
|
@@ -400,14 +399,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
400
399
|
requirements:
|
401
400
|
- - ">="
|
402
401
|
- !ruby/object:Gem::Version
|
403
|
-
version: '2.
|
402
|
+
version: '2.7'
|
404
403
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
405
404
|
requirements:
|
406
405
|
- - ">="
|
407
406
|
- !ruby/object:Gem::Version
|
408
407
|
version: '0'
|
409
408
|
requirements: []
|
410
|
-
rubygems_version: 3.
|
409
|
+
rubygems_version: 3.4.10
|
411
410
|
signing_key:
|
412
411
|
specification_version: 4
|
413
412
|
summary: A powerful attribute and type management library for Ruby
|