attributor 5.0.2 → 5.1.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +30 -0
  3. data/.travis.yml +6 -4
  4. data/CHANGELOG.md +6 -1
  5. data/Gemfile +1 -1
  6. data/Guardfile +14 -8
  7. data/Rakefile +4 -5
  8. data/attributor.gemspec +34 -29
  9. data/lib/attributor.rb +23 -29
  10. data/lib/attributor/attribute.rb +108 -127
  11. data/lib/attributor/attribute_resolver.rb +12 -26
  12. data/lib/attributor/dsl_compiler.rb +17 -21
  13. data/lib/attributor/dumpable.rb +1 -2
  14. data/lib/attributor/example_mixin.rb +5 -8
  15. data/lib/attributor/exceptions.rb +5 -6
  16. data/lib/attributor/extensions/randexp.rb +3 -5
  17. data/lib/attributor/extras/field_selector.rb +4 -4
  18. data/lib/attributor/extras/field_selector/transformer.rb +6 -7
  19. data/lib/attributor/families/numeric.rb +0 -2
  20. data/lib/attributor/families/temporal.rb +1 -4
  21. data/lib/attributor/hash_dsl_compiler.rb +22 -25
  22. data/lib/attributor/type.rb +24 -32
  23. data/lib/attributor/types/bigdecimal.rb +7 -14
  24. data/lib/attributor/types/boolean.rb +5 -8
  25. data/lib/attributor/types/class.rb +9 -10
  26. data/lib/attributor/types/collection.rb +34 -44
  27. data/lib/attributor/types/container.rb +9 -15
  28. data/lib/attributor/types/csv.rb +7 -10
  29. data/lib/attributor/types/date.rb +20 -25
  30. data/lib/attributor/types/date_time.rb +7 -14
  31. data/lib/attributor/types/float.rb +4 -6
  32. data/lib/attributor/types/hash.rb +171 -196
  33. data/lib/attributor/types/ids.rb +2 -6
  34. data/lib/attributor/types/integer.rb +12 -17
  35. data/lib/attributor/types/model.rb +39 -48
  36. data/lib/attributor/types/object.rb +2 -4
  37. data/lib/attributor/types/polymorphic.rb +118 -0
  38. data/lib/attributor/types/regexp.rb +4 -5
  39. data/lib/attributor/types/string.rb +6 -7
  40. data/lib/attributor/types/struct.rb +8 -15
  41. data/lib/attributor/types/symbol.rb +3 -6
  42. data/lib/attributor/types/tempfile.rb +5 -6
  43. data/lib/attributor/types/time.rb +11 -11
  44. data/lib/attributor/types/uri.rb +9 -10
  45. data/lib/attributor/version.rb +1 -1
  46. data/spec/attribute_resolver_spec.rb +57 -78
  47. data/spec/attribute_spec.rb +174 -216
  48. data/spec/attributor_spec.rb +11 -15
  49. data/spec/dsl_compiler_spec.rb +19 -33
  50. data/spec/dumpable_spec.rb +6 -7
  51. data/spec/extras/field_selector/field_selector_spec.rb +1 -1
  52. data/spec/families_spec.rb +1 -3
  53. data/spec/hash_dsl_compiler_spec.rb +65 -74
  54. data/spec/spec_helper.rb +9 -3
  55. data/spec/support/hashes.rb +2 -3
  56. data/spec/support/models.rb +30 -36
  57. data/spec/support/polymorphics.rb +10 -0
  58. data/spec/type_spec.rb +38 -61
  59. data/spec/types/bigdecimal_spec.rb +11 -15
  60. data/spec/types/boolean_spec.rb +12 -39
  61. data/spec/types/class_spec.rb +10 -11
  62. data/spec/types/collection_spec.rb +72 -81
  63. data/spec/types/container_spec.rb +22 -26
  64. data/spec/types/csv_spec.rb +15 -16
  65. data/spec/types/date_spec.rb +16 -33
  66. data/spec/types/date_time_spec.rb +16 -33
  67. data/spec/types/file_upload_spec.rb +1 -2
  68. data/spec/types/float_spec.rb +7 -14
  69. data/spec/types/hash_spec.rb +285 -289
  70. data/spec/types/ids_spec.rb +5 -7
  71. data/spec/types/integer_spec.rb +37 -46
  72. data/spec/types/model_spec.rb +111 -128
  73. data/spec/types/polymorphic_spec.rb +134 -0
  74. data/spec/types/regexp_spec.rb +4 -7
  75. data/spec/types/string_spec.rb +17 -21
  76. data/spec/types/struct_spec.rb +40 -47
  77. data/spec/types/tempfile_spec.rb +1 -2
  78. data/spec/types/temporal_spec.rb +9 -0
  79. data/spec/types/time_spec.rb +16 -32
  80. data/spec/types/type_spec.rb +15 -0
  81. data/spec/types/uri_spec.rb +6 -7
  82. metadata +77 -25
@@ -11,8 +11,10 @@ Coveralls.wear! do
11
11
  end
12
12
 
13
13
  require 'rspec'
14
- require 'attributor'
14
+ require 'rspec/its'
15
+ require 'rspec/collection_matchers'
15
16
 
17
+ require 'attributor'
16
18
  require 'pry'
17
19
 
18
20
  # Requires supporting files with custom matchers and macros, etc,
@@ -20,13 +22,11 @@ require 'pry'
20
22
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
21
23
 
22
24
  RSpec.configure do |config|
23
-
24
25
  config.around(:each) do |example|
25
26
  Attributor::AttributeResolver.current = Attributor::AttributeResolver.new
26
27
  example.run
27
28
  Attributor::AttributeResolver.current = nil
28
29
  end
29
-
30
30
  end
31
31
 
32
32
  RSpec::Matchers.define :be_in_family do |expected|
@@ -34,3 +34,9 @@ RSpec::Matchers.define :be_in_family do |expected|
34
34
  actual.family == expected
35
35
  end
36
36
  end
37
+
38
+ RSpec::Matchers.define :be_subclass_of do |expected|
39
+ match do |actual|
40
+ actual < expected
41
+ end
42
+ end
@@ -1,14 +1,13 @@
1
1
  class HashWithModel < Attributor::Hash
2
2
  keys do
3
- key :name, String, :default => "Turkey McDucken", :description => "Turducken name", :example => /[:name:]/
3
+ key :name, String, default: 'Turkey McDucken', description: 'Turducken name', example: Randgen.name
4
4
  key :chicken, Chicken
5
5
  end
6
6
  end
7
7
 
8
-
9
8
  class HashWithStrings < Attributor::Hash
10
9
  keys do
11
10
  key :name, String
12
11
  key :something, String
13
12
  end
14
- end
13
+ end
@@ -1,42 +1,41 @@
1
1
  class Chicken < Attributor::Model
2
- attributes(:identity => :email) do
3
- attribute :name, Attributor::String, example: /[:first_name:]/
4
- attribute :age, Attributor::Integer, :default => 1, :min => 0, :max => 120, :description => "The age of the chicken"
5
- attribute :email, Attributor::String, :example => /[:email:]/, :regexp => /@/, :description => "The email address of the chicken"
6
- attribute :angry, Attributor::Boolean, :example => "true", :description => "Angry bird?"
7
- attribute :weight, Attributor::Float, :example => /\d{1,2}\.\d/, :description => "The weight of the chicken"
2
+ attributes(identity: :email) do
3
+ attribute :name, Attributor::String, example: Randgen.first_name
4
+ attribute :age, Attributor::Integer, default: 1, min: 0, max: 120, description: 'The age of the chicken'
5
+ attribute :email, Attributor::String, example: Randgen.email, regexp: /@/, description: 'The email address of the chicken'
6
+ attribute :angry, Attributor::Boolean, example: 'true', description: 'Angry bird?'
7
+ attribute :weight, Attributor::Float, example: /\d{1,2}\.\d/, description: 'The weight of the chicken'
8
+ attribute :type, Attributor::Symbol, values: [:chicken]
8
9
  end
9
10
  end
10
11
 
11
-
12
12
  class Duck < Attributor::Model
13
13
  attributes do
14
- attribute :age, Attributor::Integer, :required_if => {"name" => "Daffy" }
14
+ attribute :age, Attributor::Integer, required_if: { 'name' => 'Daffy' }
15
15
  attribute :name, Attributor::String
16
- attribute :email, Attributor::String, :required_if => "name"
17
- attribute :angry, Attributor::Boolean, :default => true, :example => /true|false/, :description => "Angry bird?"
18
- attribute :weight, Attributor::Float, :example => /\d{1,2}\.\d/, :description => "The weight of the duck"
16
+ attribute :email, Attributor::String, required_if: 'name'
17
+ attribute :angry, Attributor::Boolean, default: true, example: /true|false/, description: 'Angry bird?'
18
+ attribute :weight, Attributor::Float, example: /\d{1,2}\.\d/, description: 'The weight of the duck'
19
+ attribute :type, Attributor::Symbol, values: [:duck]
19
20
  end
20
21
  end
21
22
 
22
-
23
23
  class Turkey < Attributor::Model
24
24
  attributes do
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 => /[:name:]/ #, :default => "Providencia Zboncak"
27
- attribute :email, String, :example => /[:email:]/, :regexp => /@/, :description => "The email address of the turkey"
28
- attribute :weight, Attributor::Float, :example => /\d{1,2}\.\d/, :max => 86.7, :description => "The weight of the turkey"
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: Randgen.name # , :default => "Providencia Zboncak"
27
+ attribute :email, String, example: Randgen.email, regexp: /@/, description: 'The email address of the turkey'
28
+ attribute :weight, Attributor::Float, example: /\d{1,2}\.\d/, max: 100.0, description: 'The weight of the turkey'
29
+ attribute :type, Attributor::Symbol, values: [:turkey]
29
30
  end
30
31
  end
31
32
 
32
-
33
-
34
33
  class Turducken < Attributor::Model
35
34
  attributes do
36
- attribute :name, String, :default => "Turkey McDucken", :description => "Turducken name", :example => /[:name:]/
35
+ attribute :name, String, default: 'Turkey McDucken', description: 'Turducken name', example: Randgen.name
37
36
  attribute :chicken, Chicken
38
37
  attribute :duck, Duck
39
- attribute :turkey, Turkey, :description => "The turkey"
38
+ attribute :turkey, Turkey, description: 'The turkey'
40
39
  end
41
40
  end
42
41
 
@@ -44,54 +43,49 @@ end
44
43
 
45
44
  class Cormorant < Attributor::Model
46
45
  attributes do
47
- attribute :name, String, :description => "Name of the Cormorant", :example => /[:name:]/
46
+ attribute :name, String, description: 'Name of the Cormorant', example: Randgen.name
48
47
  attribute :timestamps do
49
48
  attribute :born_at, DateTime
50
- attribute :died_at, DateTime, example: Proc.new {|timestamps| timestamps.born_at + 10}
49
+ attribute :died_at, DateTime, example: proc { |timestamps| timestamps.born_at + 10 }
51
50
  end
52
51
 
53
52
  # This will be a collection of arbitrary Ruby Objects
54
- attribute :fish, Attributor::Collection, :description => "All kinds of fish for feeding the babies"
53
+ attribute :fish, Attributor::Collection, description: 'All kinds of fish for feeding the babies'
55
54
 
56
55
  # This will be a collection of Cormorants (note, this relationship is circular)
57
- attribute :neighbors, Attributor::Collection.of(Cormorant), :description => "Neighbor cormorants"
56
+ attribute :neighbors, Attributor::Collection.of(Cormorant), description: 'Neighbor cormorants'
58
57
 
59
58
  # This will be a collection of instances of an anonymous Struct class, each having two well-defined attributes
60
59
 
61
- attribute :babies, Attributor::Collection.of(Attributor::Struct), :description => "All the babies", :member_options => {:identity => :name} do
62
- attribute :name, Attributor::String, :example => /[:name]/, :description => "The name of the baby cormorant"
63
- attribute :months, Attributor::Integer, :default => 0, :min => 0, :description => "The age in months of the baby cormorant"
64
- attribute :weight, Attributor::Float, :example => /\d{1,2}\.\d{3}/, :description => "The weight in kg of the baby cormorant"
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'
62
+ attribute :months, Attributor::Integer, default: 0, min: 0, description: 'The age in months of the baby cormorant'
63
+ attribute :weight, Attributor::Float, example: /\d{1,2}\.\d{3}/, description: 'The weight in kg of the baby cormorant'
65
64
  end
66
-
67
65
  end
68
66
  end
69
67
 
70
-
71
68
  class Person < Attributor::Model
72
69
  attributes do
73
- attribute :name, String, example: /[:first_name:]/
74
- attribute :title, String, values: %w{Mr Mrs Ms Dr}
70
+ attribute :name, String, example: Randgen.first_name
71
+ attribute :title, String, values: %w(Mr Mrs Ms Dr)
75
72
  attribute :okay, Attributor::Boolean, values: [true]
76
73
  attribute :address, Address, example: proc { |person, context| Address.example(context, person: person) }
77
74
  end
78
75
  end
79
76
 
80
-
81
77
  class Address < Attributor::Model
82
78
  attributes do
83
79
  attribute :name, String, example: /\w+/
84
- attribute :state, String, values: %w{OR CA}
80
+ attribute :state, String, values: %w(OR CA)
85
81
  attribute :person, Person, example: proc { |address, context| Person.example(context, address: address) }
86
82
  requires :name
87
83
  end
88
84
  end
89
85
 
90
-
91
86
  class Post < Attributor::Model
92
87
  attributes do
93
88
  attribute :title, String
94
89
  attribute :tags, Attributor::Collection.of(String)
95
90
  end
96
91
  end
97
-
@@ -0,0 +1,10 @@
1
+ class Sandwich < Attributor::Model
2
+ attributes do
3
+ attribute :name, String
4
+ attribute :meat, Attributor::Polymorphic.on(:type) do
5
+ given :chicken, Chicken
6
+ given :turkey, Turkey
7
+ given :duck, Duck
8
+ end
9
+ end
10
+ end
@@ -1,8 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
2
 
3
-
4
3
  describe Attributor::Type do
5
-
6
4
  subject(:test_type) do
7
5
  Class.new do
8
6
  include Attributor::Type
@@ -24,14 +22,13 @@ describe Attributor::Type do
24
22
  let(:attribute_attributes) { Hash.new }
25
23
 
26
24
  let(:attribute) do
27
- double "attribute",
28
- :options => attribute_options,
29
- :attributes => attribute_attributes
25
+ double 'attribute',
26
+ options: attribute_options,
27
+ attributes: attribute_attributes
30
28
  end
31
29
 
32
-
33
30
  its(:native_type) { should be(::String) }
34
- its(:id) { should eq('Testing')}
31
+ its(:id) { should eq('Testing') }
35
32
 
36
33
  context 'anonymous' do
37
34
  its(:anonymous?) { should be(false) }
@@ -39,13 +36,13 @@ describe Attributor::Type do
39
36
  klass = Class.new do
40
37
  include Attributor::Type
41
38
  end
42
- expect( klass.anonymous? ).to be(true)
39
+ expect(klass.anonymous?).to be(true)
43
40
  end
44
41
  it 'can be set to true explicitly' do
45
42
  klass = Class.new(test_type) do
46
43
  anonymous_type
47
44
  end
48
- expect( klass.anonymous? ).to be(true)
45
+ expect(klass.anonymous?).to be(true)
49
46
  end
50
47
  end
51
48
 
@@ -53,80 +50,69 @@ describe Attributor::Type do
53
50
  let(:value) { nil }
54
51
  let(:context) { nil }
55
52
 
56
- context "when given a nil value" do
53
+ context 'when given a nil value' do
57
54
  it 'always successfully returns it (i.e., you can always load nil)' do
58
- test_type.load(value).should be(value)
55
+ expect(test_type.load(value)).to be(value)
59
56
  end
60
57
  end
61
58
 
62
- context "when given a value that is of native_type" do
63
- let(:value) { "one" }
59
+ context 'when given a value that is of native_type' do
60
+ let(:value) { 'one' }
64
61
  it 'returns the value' do
65
- test_type.load(value).should be(value)
62
+ expect(test_type.load(value)).to be(value)
66
63
  end
67
64
  end
68
65
 
69
- context "when given a value that is not of native_type" do
66
+ context 'when given a value that is not of native_type' do
70
67
  let(:value) { 1 }
71
- let(:context) { ['top','sub'] }
68
+ let(:context) { %w(top sub) }
72
69
 
73
70
  it 'raises an exception' do
74
- expect { test_type.load(value,context) }.to raise_error( Attributor::IncompatibleTypeError, /cannot load values of type Fixnum.*while loading top.sub/)
71
+ expect { test_type.load(value, context) }.to raise_error(Attributor::IncompatibleTypeError, /cannot load values of type Fixnum.*while loading top.sub/)
75
72
  end
76
-
77
-
78
73
  end
79
-
80
74
  end
81
75
 
82
-
83
76
  context 'validate' do
84
77
  let(:context) { ['some_attribute'] }
85
78
 
86
79
  let(:attribute_options) { {} }
87
80
 
88
- let(:attribute) { double("some_attribute", :options => attribute_options)}
89
- subject(:errors) { test_type.validate(value, context, attribute) }
81
+ let(:attribute) { double('some_attribute', options: attribute_options) }
82
+ subject(:errors) { test_type.validate(value, context, attribute) }
90
83
 
91
84
  context 'min and max' do
92
85
  let(:min) { 10 }
93
- let(:max) { 100}
86
+ let(:max) { 100 }
94
87
 
95
- let(:attribute_options) { {:min => min, :max => max} }
88
+ let(:attribute_options) { { min: min, max: max } }
96
89
 
97
-
98
-
99
- context "with a value <= min" do
90
+ context 'with a value <= min' do
100
91
  let(:value) { 1 }
101
92
 
102
93
  it { should_not be_empty }
103
94
  it 'returns the correct error message' do
104
- errors.first.should =~ /value \(#{value}\) is smaller than the allowed min/
95
+ expect(errors.first).to match(/value \(#{value}\) is smaller than the allowed min/)
105
96
  end
106
97
  end
107
98
 
108
- context "with a value >= max" do
99
+ context 'with a value >= max' do
109
100
  let(:value) { 1000 }
110
101
  it { should_not be_empty }
111
102
  it 'returns the correct error message' do
112
- errors.first.should =~ /value \(#{value}\) is larger than the allowed max/
103
+ expect(errors.first).to match(/value \(#{value}\) is larger than the allowed max/)
113
104
  end
114
-
115
105
  end
116
106
 
117
107
  context 'with a value within the range' do
118
108
  let(:value) { 50 }
119
109
  it { should be_empty }
120
110
  end
121
-
122
-
123
111
  end
124
112
 
125
-
126
-
127
- context 'regexp' do
113
+ context 'regexp' do
128
114
  let(:regexp) { /dog/ }
129
- let(:attribute_options) { {:regexp => regexp} }
115
+ let(:attribute_options) { { regexp: regexp } }
130
116
 
131
117
  context 'with a value that matches' do
132
118
  let(:value) { 'bulldog' }
@@ -134,68 +120,59 @@ describe Attributor::Type do
134
120
  it { should be_empty }
135
121
  end
136
122
 
137
-
138
123
  context 'with a value that does not match' do
139
124
  let(:value) { 'chicken' }
140
- it { should_not be_empty}
125
+ it { should_not be_empty }
141
126
  it 'returns the correct error message' do
142
- errors.first.should =~ /value \(#{value}\) does not match regexp/
127
+ expect(errors.first).to match(/value \(#{value}\) does not match regexp/)
143
128
  end
144
129
  end
145
-
146
- end
147
-
148
-
130
+ end
149
131
  end
150
132
 
151
-
152
133
  context 'example' do
153
-
154
134
  end
155
135
 
156
136
  context 'id' do
157
137
  it 'works for built-in types' do
158
- Attributor::String.id.should eq('Attributor-String')
138
+ expect(Attributor::String.id).to eq('Attributor-String')
159
139
  end
160
140
 
161
141
  it 'returns nil for anonymous types' do
162
142
  type = Class.new(Attributor::Model)
163
- type.id.should eq(nil)
143
+ expect(type.id).to eq(nil)
164
144
  end
165
145
  end
166
146
 
167
147
  context 'describe' do
168
- let(:example){ "Foo" }
148
+ let(:example) { 'Foo' }
169
149
  subject(:description) { test_type.describe }
170
150
  it 'outputs the type name' do
171
- description[:name].should eq(test_type.name)
151
+ expect(description[:name]).to eq(test_type.name)
172
152
  end
173
153
  it 'outputs the type id' do
174
- description[:id].should eq(test_type.name)
154
+ expect(description[:id]).to eq(test_type.name)
175
155
  end
176
156
 
177
157
  context 'with an example' do
178
158
  subject(:description) { test_type.describe(example: example) }
179
159
  it 'includes it in the :example key' do
180
- description.should have_key(:example)
181
- description[:example].should be(example)
160
+ expect(description).to have_key(:example)
161
+ expect(description[:example]).to be(example)
182
162
  end
183
163
  end
184
164
 
185
165
  context 'when anonymous' do
186
-
187
166
  it 'reports true in the output when set (to true default)' do
188
167
  anon_type = Class.new(test_type) { anonymous_type }
189
- anon_type.describe.should have_key(:anonymous)
190
- anon_type.describe[:anonymous].should be(true)
168
+ expect(anon_type.describe).to have_key(:anonymous)
169
+ expect(anon_type.describe[:anonymous]).to be(true)
191
170
  end
192
171
  it 'reports false in the output when set false explicitly' do
193
172
  anon_type = Class.new(test_type) { anonymous_type false }
194
- anon_type.describe.should have_key(:anonymous)
195
- anon_type.describe[:anonymous].should be(false)
173
+ expect(anon_type.describe).to have_key(:anonymous)
174
+ expect(anon_type.describe[:anonymous]).to be(false)
196
175
  end
197
-
198
176
  end
199
177
  end
200
-
201
178
  end
@@ -4,7 +4,7 @@ describe Attributor::BigDecimal do
4
4
  subject(:type) { Attributor::BigDecimal }
5
5
 
6
6
  it 'it is not Dumpable' do
7
- type.new.is_a?(Attributor::Dumpable).should_not be(true)
7
+ expect(type.new.is_a?(Attributor::Dumpable)).not_to be(true)
8
8
  end
9
9
 
10
10
  context '.native_type' do
@@ -13,40 +13,36 @@ describe Attributor::BigDecimal do
13
13
 
14
14
  context '.example' do
15
15
  its(:example) { should be_a(::BigDecimal) }
16
- it do
17
- ex = type.example
18
- end
19
16
  end
20
17
 
21
18
  context '.load' do
22
19
  let(:value) { nil }
23
20
  it 'returns nil for nil' do
24
- type.load(nil).should be(nil)
21
+ expect(type.load(nil)).to be(nil)
25
22
  end
26
23
 
27
24
  context 'for incoming Float values' do
28
- it 'returns the incoming value' do
29
- [0.0, -1.0, 1.0, 1e-10, 0.25135].each do |value|
30
- type.load(value).should eq(value)
31
- end
32
- end
25
+ it 'returns the incoming value' do
26
+ [0.0, -1.0, 1.0, 1e-10, 0.25135].each do |value|
27
+ expect(type.load(value)).to eq(value)
28
+ end
29
+ end
33
30
  end
34
31
 
35
32
  context 'for incoming Integer values' do
36
33
  it 'should equal the incoming value' do
37
34
  [0, -1, 1].each do |value|
38
- type.load(value).should eq(value)
35
+ expect(type.load(value)).to eq(value)
39
36
  end
40
37
  end
41
38
  end
42
39
 
43
40
  context 'for incoming String values' do
44
41
  it 'should equal the value' do
45
- type.load('0').should eq(0)
46
- type.load('100').should eq(100)
47
- type.load('0.1').should eq(0.1)
42
+ expect(type.load('0')).to eq(0)
43
+ expect(type.load('100')).to eq(100)
44
+ expect(type.load('0.1')).to eq(0.1)
48
45
  end
49
46
  end
50
-
51
47
  end
52
48
  end