attributor 5.4 → 6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/attributor/attribute.rb +101 -84
- data/lib/attributor/extras/field_selector.rb +4 -0
- data/lib/attributor/families/numeric.rb +19 -6
- data/lib/attributor/families/temporal.rb +16 -9
- data/lib/attributor/hash_dsl_compiler.rb +6 -5
- data/lib/attributor/type.rb +26 -3
- data/lib/attributor/types/bigdecimal.rb +6 -1
- data/lib/attributor/types/boolean.rb +5 -0
- data/lib/attributor/types/collection.rb +19 -0
- data/lib/attributor/types/csv.rb +4 -0
- data/lib/attributor/types/date.rb +7 -1
- data/lib/attributor/types/date_time.rb +7 -1
- data/lib/attributor/types/float.rb +4 -3
- data/lib/attributor/types/hash.rb +86 -23
- data/lib/attributor/types/integer.rb +7 -1
- data/lib/attributor/types/model.rb +9 -21
- data/lib/attributor/types/object.rb +5 -0
- data/lib/attributor/types/polymorphic.rb +0 -1
- data/lib/attributor/types/string.rb +19 -0
- data/lib/attributor/types/symbol.rb +5 -0
- data/lib/attributor/types/tempfile.rb +4 -0
- data/lib/attributor/types/time.rb +6 -2
- data/lib/attributor/types/uri.rb +8 -0
- data/lib/attributor/version.rb +1 -1
- data/lib/attributor.rb +3 -7
- data/spec/attribute_spec.rb +148 -124
- data/spec/extras/field_selector/field_selector_spec.rb +9 -0
- data/spec/hash_dsl_compiler_spec.rb +5 -5
- data/spec/spec_helper.rb +0 -2
- data/spec/support/integers.rb +7 -0
- data/spec/support/models.rb +7 -7
- data/spec/types/bigdecimal_spec.rb +8 -0
- data/spec/types/boolean_spec.rb +10 -0
- data/spec/types/collection_spec.rb +16 -0
- data/spec/types/date_spec.rb +9 -0
- data/spec/types/date_time_spec.rb +9 -0
- data/spec/types/float_spec.rb +8 -0
- data/spec/types/hash_spec.rb +181 -22
- data/spec/types/integer_spec.rb +9 -0
- data/spec/types/model_spec.rb +7 -1
- data/spec/types/string_spec.rb +10 -0
- data/spec/types/temporal_spec.rb +5 -1
- data/spec/types/time_spec.rb +9 -0
- data/spec/types/uri_spec.rb +9 -0
- metadata +5 -6
- data/lib/attributor/attribute_resolver.rb +0 -111
- data/spec/attribute_resolver_spec.rb +0 -237
data/spec/attribute_spec.rb
CHANGED
@@ -11,7 +11,7 @@ describe Attributor::Attribute do
|
|
11
11
|
|
12
12
|
context 'initialize' do
|
13
13
|
its(:type) { should be type }
|
14
|
-
its(:options) { should
|
14
|
+
its(:options) { should eq attribute_options }
|
15
15
|
|
16
16
|
it 'calls check_options!' do
|
17
17
|
expect_any_instance_of(Attributor::Attribute).to receive(:check_options!)
|
@@ -36,17 +36,49 @@ describe Attributor::Attribute do
|
|
36
36
|
it { should eq other_attribute }
|
37
37
|
end
|
38
38
|
|
39
|
+
context 'describe_json_schema' do
|
40
|
+
let(:type) { PositiveIntegerType }
|
41
|
+
|
42
|
+
let(:attribute_options) do
|
43
|
+
{
|
44
|
+
values: [1,20],
|
45
|
+
description: "something",
|
46
|
+
example: 20,
|
47
|
+
max: 1000,
|
48
|
+
default: 1
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'reports all of the possible attributes' do
|
53
|
+
let(:js){ subject.as_json_schema(example: 20) }
|
54
|
+
|
55
|
+
it 'including the attribute-specific ones' do
|
56
|
+
expect(js[:enum]).to eq( [1,20])
|
57
|
+
expect(js[:description]).to eq( "something")
|
58
|
+
expect(js[:default]).to eq(1)
|
59
|
+
expect(js[:example]).to eq(20)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'as well as the type-specific ones' do
|
63
|
+
expect(js[:type]).to eq(:integer)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
39
70
|
context 'describe' do
|
40
|
-
let(:attribute_options) { {
|
71
|
+
let(:attribute_options) { {required: true, values: ['one'], description: "something", min: 0} }
|
41
72
|
let(:expected) do
|
42
|
-
h = {
|
43
|
-
common = attribute_options.select
|
73
|
+
h = {type: {name: 'String', id: type.id, family: type.family}}
|
74
|
+
common = attribute_options.select{|k,v| Attributor::Attribute::TOP_LEVEL_OPTIONS.include? k }
|
44
75
|
h.merge!(common)
|
45
|
-
h[:options] = {
|
76
|
+
h[:options] = {min: 0}
|
46
77
|
h
|
47
78
|
end
|
48
79
|
|
49
|
-
|
80
|
+
# It has both the type-included options (min) as well as the attribute options (max)
|
81
|
+
its(:describe) { should == expected }
|
50
82
|
|
51
83
|
context 'with example options' do
|
52
84
|
let(:attribute_options) { { description: 'something', example: 'ex_def' } }
|
@@ -163,6 +195,49 @@ describe Attributor::Attribute do
|
|
163
195
|
end.not_to raise_error
|
164
196
|
end
|
165
197
|
end
|
198
|
+
|
199
|
+
context 'custom_options' do
|
200
|
+
let(:option_name) { :foo }
|
201
|
+
let(:custom_option_args) { [option_name, String] }
|
202
|
+
|
203
|
+
around do |example|
|
204
|
+
Attributor::Attribute.custom_option *custom_option_args
|
205
|
+
example.run
|
206
|
+
Attributor::Attribute.custom_options.delete option_name
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'raises ArgumentError if given an existing option' do
|
210
|
+
expect {
|
211
|
+
Attributor::Attribute.custom_option :default, Object
|
212
|
+
}.to raise_error(ArgumentError)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'accepts custom options' do
|
216
|
+
expect do
|
217
|
+
Attributor::Attribute.new(Integer, foo: 'unvalidated')
|
218
|
+
end.not_to raise_error
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'can validate the custom option value' do
|
222
|
+
let(:custom_option_args) { [option_name, String, values: ['valid']] }
|
223
|
+
it 'does not raise with a valid option value' do
|
224
|
+
expect do
|
225
|
+
Attributor::Attribute.new(Integer, foo: 'valid')
|
226
|
+
end.not_to raise_error
|
227
|
+
end
|
228
|
+
it 'raises with an invalid option value' do
|
229
|
+
expect do
|
230
|
+
Attributor::Attribute.new(Integer, foo: 'invalid')
|
231
|
+
end.to raise_error(Attributor::AttributorException)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'appear in as_json_schema' do
|
236
|
+
attribute = Attributor::Attribute.new(Integer, foo: 'valid')
|
237
|
+
json_schema = attribute.as_json_schema
|
238
|
+
expect(json_schema[:'x-foo']).to eq 'valid'
|
239
|
+
end
|
240
|
+
end
|
166
241
|
end
|
167
242
|
|
168
243
|
context 'example' do
|
@@ -383,10 +458,49 @@ describe Attributor::Attribute do
|
|
383
458
|
context 'applying attribute options' do
|
384
459
|
context ':required' do
|
385
460
|
let(:attribute_options) { { required: true } }
|
461
|
+
context 'has no effect on a bare attribute' do
|
462
|
+
let(:value) { 'val' }
|
463
|
+
it 'it does not error, as we do not know if the parent attribute key was passed in (done at the Hash level)' do
|
464
|
+
expect(attribute.validate(value, context)).to be_empty
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
context ':null false (non-nullable)' do
|
469
|
+
let(:attribute_options) { { null: false } }
|
386
470
|
context 'with a nil value' do
|
387
471
|
let(:value) { nil }
|
388
472
|
it 'returns an error' do
|
389
|
-
expect(attribute.validate(value, context).first).to eq 'Attribute context is
|
473
|
+
expect(attribute.validate(value, context).first).to eq 'Attribute context is not nullable'
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
context ':null true (nullable)' do
|
478
|
+
let(:attribute_options) { { null: true } }
|
479
|
+
context 'with a nil value' do
|
480
|
+
let(:value) { nil }
|
481
|
+
it 'does not error' do
|
482
|
+
expect(attribute.validate(value, context)).to be_empty
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
context 'defaults to non-nullable if null not defined' do
|
487
|
+
let(:attribute_options) { { } }
|
488
|
+
context 'with a nil value' do
|
489
|
+
let(:value) { nil }
|
490
|
+
it 'returns an error' do
|
491
|
+
expect(Attributor::Attribute.default_for_null).to be(false)
|
492
|
+
expect(attribute.validate(value, context).first).to eq 'Attribute context is not nullable'
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
context 'default can be overrideable with true' do
|
498
|
+
let(:attribute_options) { { } }
|
499
|
+
context 'with a nil value' do
|
500
|
+
let(:value) { nil }
|
501
|
+
it 'suceeds' do
|
502
|
+
expect(Attributor::Attribute).to receive(:default_for_null).and_return(true)
|
503
|
+
expect(attribute.validate(value, context)).to be_empty
|
390
504
|
end
|
391
505
|
end
|
392
506
|
end
|
@@ -432,6 +546,13 @@ describe Attributor::Attribute do
|
|
432
546
|
end
|
433
547
|
end
|
434
548
|
|
549
|
+
context 'with a nil value' do
|
550
|
+
let(:value) { nil }
|
551
|
+
it 'returns no errors' do
|
552
|
+
expect(errors).to be_empty
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
435
556
|
context 'with a value of a value different than the native_type' do
|
436
557
|
let(:value) { 1 }
|
437
558
|
|
@@ -441,58 +562,6 @@ describe Attributor::Attribute do
|
|
441
562
|
end
|
442
563
|
end
|
443
564
|
end
|
444
|
-
|
445
|
-
context '#validate_missing_value' do
|
446
|
-
let(:key) { '$.instance.ssh_key.name' }
|
447
|
-
let(:value) { /\w+/.gen }
|
448
|
-
|
449
|
-
let(:attribute_options) { { required_if: key } }
|
450
|
-
|
451
|
-
let(:ssh_key) { double('ssh_key', name: value) }
|
452
|
-
let(:instance) { double('instance', ssh_key: ssh_key) }
|
453
|
-
|
454
|
-
before { Attributor::AttributeResolver.current.register('instance', instance) }
|
455
|
-
|
456
|
-
let(:attribute_context) { ['$', 'params', 'key_material'] }
|
457
|
-
subject(:errors) { attribute.validate_missing_value(attribute_context) }
|
458
|
-
|
459
|
-
context 'for a simple dependency without a predicate' do
|
460
|
-
context 'that is satisfied' do
|
461
|
-
it { should_not be_empty }
|
462
|
-
end
|
463
|
-
|
464
|
-
context 'that is missing' do
|
465
|
-
let(:value) { nil }
|
466
|
-
it { should be_empty }
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
|
-
context 'with a dependency that has a predicate' do
|
471
|
-
let(:value) { 'default_ssh_key_name' }
|
472
|
-
# subject(:errors) { attribute.validate_missing_value('') }
|
473
|
-
|
474
|
-
context 'where the target attribute exists, and matches the predicate' do
|
475
|
-
let(:attribute_options) { { required_if: { key => /default/ } } }
|
476
|
-
|
477
|
-
it { should_not be_empty }
|
478
|
-
|
479
|
-
its(:first) { should match(/Attribute #{Regexp.quote(Attributor.humanize_context(attribute_context))} is required when #{Regexp.quote(key)} matches/) }
|
480
|
-
end
|
481
|
-
|
482
|
-
context 'where the target attribute exists, but does not match the predicate' do
|
483
|
-
let(:attribute_options) { { required_if: { key => /other/ } } }
|
484
|
-
|
485
|
-
it { should be_empty }
|
486
|
-
end
|
487
|
-
|
488
|
-
context 'where the target attribute does not exist' do
|
489
|
-
let(:attribute_options) { { required_if: { key => /default/ } } }
|
490
|
-
let(:ssh_key) { double('ssh_key', name: nil) }
|
491
|
-
|
492
|
-
it { should be_empty }
|
493
|
-
end
|
494
|
-
end
|
495
|
-
end
|
496
565
|
end
|
497
566
|
|
498
567
|
context 'for an attribute for a subclass of Model' do
|
@@ -561,71 +630,6 @@ describe Attributor::Attribute do
|
|
561
630
|
end
|
562
631
|
end
|
563
632
|
end
|
564
|
-
|
565
|
-
context '#validate_missing_value' do
|
566
|
-
let(:type) { Duck }
|
567
|
-
let(:attribute_name) { nil }
|
568
|
-
let(:attribute) { Duck.attributes[attribute_name] }
|
569
|
-
|
570
|
-
let(:attribute_context) { ['$', 'duck', attribute_name.to_s] }
|
571
|
-
subject(:errors) { attribute.validate_missing_value(attribute_context) }
|
572
|
-
|
573
|
-
before do
|
574
|
-
Attributor::AttributeResolver.current.register('duck', duck)
|
575
|
-
end
|
576
|
-
|
577
|
-
context 'for a dependency with no predicate' do
|
578
|
-
let(:attribute_name) { :email }
|
579
|
-
|
580
|
-
let(:duck) do
|
581
|
-
d = Duck.new
|
582
|
-
d.age = 1
|
583
|
-
d.name = 'Donald'
|
584
|
-
d
|
585
|
-
end
|
586
|
-
|
587
|
-
context 'where the target attribute exists, and matches the predicate' do
|
588
|
-
it { should_not be_empty }
|
589
|
-
its(:first) { should eq 'Attribute $.duck.email is required when name (for $.duck) is present.' }
|
590
|
-
end
|
591
|
-
context 'where the target attribute does not exist' do
|
592
|
-
before do
|
593
|
-
duck.name = nil
|
594
|
-
end
|
595
|
-
it { should be_empty }
|
596
|
-
end
|
597
|
-
end
|
598
|
-
|
599
|
-
context 'for a dependency with a predicate' do
|
600
|
-
let(:attribute_name) { :age }
|
601
|
-
|
602
|
-
let(:duck) do
|
603
|
-
d = Duck.new
|
604
|
-
d.name = 'Daffy'
|
605
|
-
d.email = 'daffy@darkwing.uoregon.edu' # he's a duck,get it?
|
606
|
-
d
|
607
|
-
end
|
608
|
-
|
609
|
-
context 'where the target attribute exists, and matches the predicate' do
|
610
|
-
it { should_not be_empty }
|
611
|
-
its(:first) { should match(/Attribute #{Regexp.quote('$.duck.age')} is required when name #{Regexp.quote('(for $.duck)')} matches/) }
|
612
|
-
end
|
613
|
-
|
614
|
-
context 'where the target attribute exists, and does not match the predicate' do
|
615
|
-
before do
|
616
|
-
duck.name = 'Donald'
|
617
|
-
end
|
618
|
-
it { should be_empty }
|
619
|
-
end
|
620
|
-
|
621
|
-
context 'where the target attribute does not exist' do
|
622
|
-
before do
|
623
|
-
duck.name = nil
|
624
|
-
end
|
625
|
-
it { should be_empty }
|
626
|
-
end
|
627
|
-
end
|
628
|
-
end
|
629
633
|
end
|
630
634
|
end
|
631
635
|
|
@@ -682,4 +686,24 @@ describe Attributor::Attribute do
|
|
682
686
|
end
|
683
687
|
end
|
684
688
|
end
|
689
|
+
|
690
|
+
context '.nullable_attribute?' do
|
691
|
+
subject { described_class.nullable_attribute?(options) }
|
692
|
+
context 'with null: true option' do
|
693
|
+
let(:options) { { null: true } }
|
694
|
+
it { should be_truthy }
|
695
|
+
end
|
696
|
+
context 'with null: false option' do
|
697
|
+
let(:options) { { null: false } }
|
698
|
+
it { should be_falsey }
|
699
|
+
end
|
700
|
+
context 'defaults to false without any null option' do
|
701
|
+
let(:options) { { } }
|
702
|
+
it { should be_falsey }
|
703
|
+
end
|
704
|
+
context 'defaults to false if null: nil' do
|
705
|
+
let(:options) { { null: nil } }
|
706
|
+
it { should be_falsey }
|
707
|
+
end
|
708
|
+
end
|
685
709
|
end
|
@@ -33,4 +33,13 @@ describe Attributor::FieldSelector do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
context '.as_json_schema' do
|
38
|
+
subject(:js){ type.as_json_schema }
|
39
|
+
it 'adds the right attributes' do
|
40
|
+
expect(js.keys).to include(:type, :'x-type_name')
|
41
|
+
expect(js[:type]).to eq(:string)
|
42
|
+
expect(js[:'x-type_name']).to eq('FieldSelector')
|
43
|
+
end
|
44
|
+
end
|
36
45
|
end
|
@@ -109,31 +109,31 @@ describe Attributor::HashDSLCompiler do
|
|
109
109
|
context 'for :all' do
|
110
110
|
let(:arguments) { { all: [:one, :two, :three] } }
|
111
111
|
let(:value) { [:one] }
|
112
|
-
let(:validation_error) { [
|
112
|
+
let(:validation_error) { ["Attribute $.key(:two) is required.", "Attribute $.key(:three) is required."] }
|
113
113
|
it { expect(subject).to include(*validation_error) }
|
114
114
|
end
|
115
115
|
context 'for :exactly' do
|
116
116
|
let(:requirement) { req_class.new(exactly: 1).of(:one, :two) }
|
117
117
|
let(:value) { [:one, :two] }
|
118
|
-
let(:validation_error) { 'Exactly 1 of the following
|
118
|
+
let(:validation_error) { 'Exactly 1 of the following attributes [:one, :two] are required for $. Found 2 instead: [:one, :two]' }
|
119
119
|
it { expect(subject).to include(validation_error) }
|
120
120
|
end
|
121
121
|
context 'for :at_least' do
|
122
122
|
let(:requirement) { req_class.new(at_least: 2).of(:one, :two, :three) }
|
123
123
|
let(:value) { [:one] }
|
124
|
-
let(:validation_error) { 'At least 2
|
124
|
+
let(:validation_error) { 'At least 2 attributes out of [:one, :two, :three] are required to be passed in for $. Found [:one]' }
|
125
125
|
it { expect(subject).to include(validation_error) }
|
126
126
|
end
|
127
127
|
context 'for :at_most' do
|
128
128
|
let(:requirement) { req_class.new(at_most: 1).of(:one, :two, :three) }
|
129
129
|
let(:value) { [:one, :two] }
|
130
|
-
let(:validation_error) { 'At most 1
|
130
|
+
let(:validation_error) { 'At most 1 attributes out of [:one, :two, :three] can be passed in for $. Found [:one, :two]' }
|
131
131
|
it { expect(subject).to include(validation_error) }
|
132
132
|
end
|
133
133
|
context 'for :exclusive' do
|
134
134
|
let(:arguments) { { exclusive: [:one, :two] } }
|
135
135
|
let(:value) { [:one, :two] }
|
136
|
-
let(:validation_error) { '
|
136
|
+
let(:validation_error) { 'Attributes [:one, :two] are mutually exclusive for $.' }
|
137
137
|
it { expect(subject).to include(validation_error) }
|
138
138
|
end
|
139
139
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -23,9 +23,7 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
23
23
|
|
24
24
|
RSpec.configure do |config|
|
25
25
|
config.around(:each) do |example|
|
26
|
-
Attributor::AttributeResolver.current = Attributor::AttributeResolver.new
|
27
26
|
example.run
|
28
|
-
Attributor::AttributeResolver.current = nil
|
29
27
|
end
|
30
28
|
end
|
31
29
|
|
data/spec/support/models.rb
CHANGED
@@ -11,9 +11,9 @@ end
|
|
11
11
|
|
12
12
|
class Duck < Attributor::Model
|
13
13
|
attributes do
|
14
|
-
attribute :age, Attributor::Integer
|
14
|
+
attribute :age, Attributor::Integer
|
15
15
|
attribute :name, Attributor::String
|
16
|
-
attribute :email, Attributor::String
|
16
|
+
attribute :email, Attributor::String
|
17
17
|
attribute :angry, Attributor::Boolean, default: true, example: /true|false/, description: 'Angry bird?'
|
18
18
|
attribute :weight, Attributor::Float, example: /\d{1,2}\.\d/, description: 'The weight of the duck'
|
19
19
|
attribute :type, Attributor::Symbol, values: [:duck]
|
@@ -50,15 +50,15 @@ class Cormorant < Attributor::Model
|
|
50
50
|
end
|
51
51
|
|
52
52
|
# This will be a collection of arbitrary Ruby Objects
|
53
|
-
attribute :
|
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), description: 'Neighbor cormorants'
|
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: /[:name]/, description: 'The name of the baby cormorant'
|
61
|
+
attribute :name, Attributor::String, example: /[: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
63
|
attribute :weight, Attributor::Float, example: /\d{1,2}\.\d{3}/, description: 'The weight in kg of the baby cormorant'
|
64
64
|
end
|
@@ -76,8 +76,8 @@ end
|
|
76
76
|
|
77
77
|
class Address < Attributor::Model
|
78
78
|
attributes do
|
79
|
-
attribute :name, String, example: /\w
|
80
|
-
attribute :state, String, values: %w(OR CA)
|
79
|
+
attribute :name, String, example: /\w+/, null: true
|
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
|
requires :name
|
83
83
|
end
|
@@ -45,4 +45,12 @@ describe Attributor::BigDecimal do
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
|
+
context '.as_json_schema' do
|
49
|
+
subject(:js){ type.as_json_schema }
|
50
|
+
it 'adds the right attributes' do
|
51
|
+
expect(js.keys).to include(:type, :'x-type_name')
|
52
|
+
expect(js[:type]).to eq(:number)
|
53
|
+
expect(js[:'x-type_name']).to eq('BigDecimal')
|
54
|
+
end
|
55
|
+
end
|
48
56
|
end
|
data/spec/types/boolean_spec.rb
CHANGED
@@ -7,6 +7,8 @@ describe Attributor::Boolean do
|
|
7
7
|
expect(type.new.is_a?(Attributor::Dumpable)).not_to be(true)
|
8
8
|
end
|
9
9
|
|
10
|
+
its(:json_schema_type){ should eq(:boolean)}
|
11
|
+
|
10
12
|
context '.valid_type?' do
|
11
13
|
context 'for incoming Boolean values' do
|
12
14
|
[false, true].each do |value|
|
@@ -63,4 +65,12 @@ describe Attributor::Boolean do
|
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
68
|
+
context '.as_json_schema' do
|
69
|
+
subject(:js){ type.as_json_schema }
|
70
|
+
it 'adds the right attributes' do
|
71
|
+
expect(js.keys).to include(:type, :'x-type_name')
|
72
|
+
expect(js[:type]).to eq(:boolean)
|
73
|
+
expect(js[:'x-type_name']).to eq('Boolean')
|
74
|
+
end
|
75
|
+
end
|
66
76
|
end
|
@@ -344,4 +344,20 @@ describe Attributor::Collection do
|
|
344
344
|
end.to_not raise_error
|
345
345
|
end
|
346
346
|
end
|
347
|
+
|
348
|
+
context '.as_json_schema' do
|
349
|
+
let(:member_type) { Attributor::String }
|
350
|
+
let(:type) { Attributor::Collection.of(member_type) }
|
351
|
+
let(:attribute_options) do
|
352
|
+
{}
|
353
|
+
end
|
354
|
+
subject(:js){ type.as_json_schema(attribute_options: attribute_options) }
|
355
|
+
|
356
|
+
it 'adds the right attributes' do
|
357
|
+
expect(js.keys).to include(:type, :'x-type_name', :items)
|
358
|
+
expect(js[:type]).to eq(:array)
|
359
|
+
expect(js[:'x-type_name']).to eq('Collection')
|
360
|
+
expect(js[:items]).to eq(member_type.as_json_schema)
|
361
|
+
end
|
362
|
+
end
|
347
363
|
end
|
data/spec/types/date_spec.rb
CHANGED
@@ -92,4 +92,13 @@ describe Attributor::Date do
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
95
|
+
context '.as_json_schema' do
|
96
|
+
subject(:js){ type.as_json_schema }
|
97
|
+
it 'adds the right attributes' do
|
98
|
+
expect(js.keys).to include(:type, :'x-type_name')
|
99
|
+
expect(js[:type]).to eq(:string)
|
100
|
+
expect(js[:format]).to eq(:'date')
|
101
|
+
expect(js[:'x-type_name']).to eq('Date')
|
102
|
+
end
|
103
|
+
end
|
95
104
|
end
|
@@ -92,4 +92,13 @@ describe Attributor::DateTime do
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
95
|
+
context '.as_json_schema' do
|
96
|
+
subject(:js){ type.as_json_schema }
|
97
|
+
it 'adds the right attributes' do
|
98
|
+
expect(js.keys).to include(:type, :'x-type_name', :format)
|
99
|
+
expect(js[:type]).to eq(:string)
|
100
|
+
expect(js[:format]).to eq(:'date-time')
|
101
|
+
expect(js[:'x-type_name']).to eq('DateTime')
|
102
|
+
end
|
103
|
+
end
|
95
104
|
end
|
data/spec/types/float_spec.rb
CHANGED
@@ -76,4 +76,12 @@ describe Attributor::Float do
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
79
|
+
context '.as_json_schema' do
|
80
|
+
subject(:js){ type.as_json_schema }
|
81
|
+
it 'adds the right attributes' do
|
82
|
+
expect(js.keys).to include(:type, :'x-type_name')
|
83
|
+
expect(js[:type]).to eq(:number)
|
84
|
+
expect(js[:'x-type_name']).to eq('Float')
|
85
|
+
end
|
86
|
+
end
|
79
87
|
end
|