virtus 1.0.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +19 -15
  3. data/Changelog.md +43 -2
  4. data/Gemfile +5 -5
  5. data/README.md +113 -78
  6. data/Rakefile +13 -3
  7. data/lib/virtus.rb +46 -6
  8. data/lib/virtus/attribute.rb +21 -3
  9. data/lib/virtus/attribute/accessor.rb +11 -0
  10. data/lib/virtus/attribute/builder.rb +8 -13
  11. data/lib/virtus/attribute/collection.rb +12 -3
  12. data/lib/virtus/attribute/default_value.rb +2 -0
  13. data/lib/virtus/attribute/hash.rb +3 -3
  14. data/lib/virtus/attribute/nullify_blank.rb +24 -0
  15. data/lib/virtus/attribute/strict.rb +1 -1
  16. data/lib/virtus/attribute_set.rb +2 -2
  17. data/lib/virtus/builder.rb +2 -6
  18. data/lib/virtus/class_inclusions.rb +0 -1
  19. data/lib/virtus/coercer.rb +1 -0
  20. data/lib/virtus/configuration.rb +17 -36
  21. data/lib/virtus/extensions.rb +13 -21
  22. data/lib/virtus/instance_methods.rb +3 -2
  23. data/lib/virtus/model.rb +1 -3
  24. data/lib/virtus/module_extensions.rb +8 -2
  25. data/lib/virtus/support/equalizer.rb +1 -1
  26. data/lib/virtus/support/options.rb +2 -1
  27. data/lib/virtus/support/type_lookup.rb +1 -1
  28. data/lib/virtus/version.rb +1 -1
  29. data/spec/integration/attributes_attribute_spec.rb +28 -0
  30. data/spec/integration/building_module_spec.rb +22 -0
  31. data/spec/integration/collection_member_coercion_spec.rb +34 -13
  32. data/spec/integration/custom_attributes_spec.rb +2 -2
  33. data/spec/integration/custom_collection_attributes_spec.rb +6 -6
  34. data/spec/integration/default_values_spec.rb +8 -8
  35. data/spec/integration/defining_attributes_spec.rb +25 -18
  36. data/spec/integration/embedded_value_spec.rb +5 -5
  37. data/spec/integration/extending_objects_spec.rb +5 -5
  38. data/spec/integration/hash_attributes_coercion_spec.rb +16 -12
  39. data/spec/integration/mass_assignment_with_accessors_spec.rb +5 -5
  40. data/spec/integration/overriding_virtus_spec.rb +4 -4
  41. data/spec/integration/required_attributes_spec.rb +1 -1
  42. data/spec/integration/struct_as_embedded_value_spec.rb +4 -4
  43. data/spec/integration/using_modules_spec.rb +8 -8
  44. data/spec/integration/value_object_with_custom_constructor_spec.rb +4 -4
  45. data/spec/integration/virtus/instance_level_attributes_spec.rb +1 -1
  46. data/spec/integration/virtus/value_object_spec.rb +14 -14
  47. data/spec/shared/freeze_method_behavior.rb +6 -3
  48. data/spec/shared/idempotent_method_behaviour.rb +1 -1
  49. data/spec/shared/options_class_method.rb +3 -3
  50. data/spec/spec_helper.rb +2 -18
  51. data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +3 -3
  52. data/spec/unit/virtus/attribute/boolean/value_coerced_predicate_spec.rb +3 -3
  53. data/spec/unit/virtus/attribute/class_methods/build_spec.rb +64 -24
  54. data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +2 -2
  55. data/spec/unit/virtus/attribute/coerce_spec.rb +58 -10
  56. data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +2 -2
  57. data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +15 -4
  58. data/spec/unit/virtus/attribute/collection/coerce_spec.rb +25 -4
  59. data/spec/unit/virtus/attribute/collection/value_coerced_predicate_spec.rb +31 -0
  60. data/spec/unit/virtus/attribute/comparison_spec.rb +20 -0
  61. data/spec/unit/virtus/attribute/custom_collection_spec.rb +8 -2
  62. data/spec/unit/virtus/attribute/defined_spec.rb +20 -0
  63. data/spec/unit/virtus/attribute/embedded_value/class_methods/build_spec.rb +30 -15
  64. data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +25 -11
  65. data/spec/unit/virtus/attribute/get_spec.rb +2 -2
  66. data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +21 -9
  67. data/spec/unit/virtus/attribute/hash/coerce_spec.rb +9 -9
  68. data/spec/unit/virtus/attribute/lazy_predicate_spec.rb +2 -2
  69. data/spec/unit/virtus/attribute/rename_spec.rb +6 -3
  70. data/spec/unit/virtus/attribute/required_predicate_spec.rb +2 -2
  71. data/spec/unit/virtus/attribute/set_default_value_spec.rb +43 -10
  72. data/spec/unit/virtus/attribute/set_spec.rb +1 -1
  73. data/spec/unit/virtus/attribute/value_coerced_predicate_spec.rb +2 -2
  74. data/spec/unit/virtus/attribute_set/append_spec.rb +6 -6
  75. data/spec/unit/virtus/attribute_set/define_reader_method_spec.rb +12 -11
  76. data/spec/unit/virtus/attribute_set/define_writer_method_spec.rb +13 -12
  77. data/spec/unit/virtus/attribute_set/each_spec.rb +21 -16
  78. data/spec/unit/virtus/attribute_set/element_reference_spec.rb +2 -2
  79. data/spec/unit/virtus/attribute_set/element_set_spec.rb +17 -9
  80. data/spec/unit/virtus/attribute_set/merge_spec.rb +7 -5
  81. data/spec/unit/virtus/attribute_set/reset_spec.rb +22 -11
  82. data/spec/unit/virtus/attribute_spec.rb +8 -7
  83. data/spec/unit/virtus/attributes_reader_spec.rb +1 -1
  84. data/spec/unit/virtus/attributes_writer_spec.rb +1 -1
  85. data/spec/unit/virtus/element_reader_spec.rb +1 -1
  86. data/spec/unit/virtus/freeze_spec.rb +23 -3
  87. data/spec/unit/virtus/model_spec.rb +38 -7
  88. data/spec/unit/virtus/module_spec.rb +59 -2
  89. data/spec/unit/virtus/set_default_attributes_spec.rb +10 -3
  90. data/spec/unit/virtus/value_object_spec.rb +15 -5
  91. data/virtus.gemspec +7 -5
  92. metadata +46 -44
  93. data/.ruby-version +0 -1
  94. data/Gemfile.devtools +0 -54
  95. data/config/flay.yml +0 -3
  96. data/config/flog.yml +0 -2
  97. data/config/mutant.yml +0 -15
  98. data/config/reek.yml +0 -146
  99. data/config/yardstick.yml +0 -2
@@ -19,7 +19,7 @@ describe Virtus::Attribute, '.coerce' do
19
19
  described_class.coerce(true)
20
20
  end
21
21
 
22
- it { should be(true) }
22
+ it { is_expected.to be(true) }
23
23
  end
24
24
 
25
25
  context 'when it is set to false' do
@@ -27,6 +27,6 @@ describe Virtus::Attribute, '.coerce' do
27
27
  described_class.coerce(false)
28
28
  end
29
29
 
30
- it { should be(false) }
30
+ it { is_expected.to be(false) }
31
31
  end
32
32
  end
@@ -7,10 +7,11 @@ describe Virtus::Attribute, '#coerce' do
7
7
 
8
8
  let(:object) {
9
9
  described_class.build(String,
10
- :coercer => coercer, :strict => strict, :required => required)
10
+ :coercer => coercer, :strict => strict, :required => required, :nullify_blank => nullify_blank)
11
11
  }
12
12
 
13
13
  let(:required) { true }
14
+ let(:nullify_blank) { false }
14
15
  let(:input) { 1 }
15
16
  let(:output) { '1' }
16
17
 
@@ -18,7 +19,7 @@ describe Virtus::Attribute, '#coerce' do
18
19
  let(:strict) { false }
19
20
 
20
21
  it 'uses coercer to coerce the input value' do
21
- stub(coercer).call(input) { output }
22
+ mock(coercer).call(input) { output }
22
23
 
23
24
  expect(subject).to be(output)
24
25
 
@@ -30,8 +31,8 @@ describe Virtus::Attribute, '#coerce' do
30
31
  let(:strict) { true }
31
32
 
32
33
  it 'uses coercer to coerce the input value' do
33
- stub(coercer).call(input) { output }
34
- stub(coercer).success?(String, output) { true }
34
+ mock(coercer).call(input) { output }
35
+ mock(coercer).success?(String, output) { true }
35
36
 
36
37
  expect(subject).to be(output)
37
38
 
@@ -44,8 +45,8 @@ describe Virtus::Attribute, '#coerce' do
44
45
  let(:input) { nil }
45
46
 
46
47
  it 'returns nil' do
47
- stub(coercer).call(input) { input }
48
- stub(coercer).success?(String, input) { false }
48
+ mock(coercer).call(input) { input }
49
+ mock(coercer).success?(String, input) { false }
49
50
 
50
51
  expect(subject).to be(nil)
51
52
 
@@ -58,8 +59,8 @@ describe Virtus::Attribute, '#coerce' do
58
59
  let(:input) { nil }
59
60
 
60
61
  it 'returns raises error' do
61
- stub(coercer).call(input) { input }
62
- stub(coercer).success?(String, input) { false }
62
+ mock(coercer).call(input) { input }
63
+ mock(coercer).success?(String, input) { false }
63
64
 
64
65
  expect { subject }.to raise_error(Virtus::CoercionError)
65
66
 
@@ -69,8 +70,8 @@ describe Virtus::Attribute, '#coerce' do
69
70
  end
70
71
 
71
72
  it 'raises error when input was not coerced' do
72
- stub(coercer).call(input) { input }
73
- stub(coercer).success?(String, input) { false }
73
+ mock(coercer).call(input) { input }
74
+ mock(coercer).success?(String, input) { false }
74
75
 
75
76
  expect { subject }.to raise_error(Virtus::CoercionError)
76
77
 
@@ -78,4 +79,51 @@ describe Virtus::Attribute, '#coerce' do
78
79
  expect(coercer).to have_received.success?(String, input)
79
80
  end
80
81
  end
82
+
83
+ context 'when the input is an empty String' do
84
+ let(:input) { '' }
85
+ let(:output) { '' }
86
+
87
+ context 'when nullify_blank is turned on' do
88
+ let(:nullify_blank) { true }
89
+ let(:strict) { false }
90
+ let(:require) { false }
91
+
92
+ it 'returns nil' do
93
+ mock(coercer).call(input) { input }
94
+ mock(coercer).success?(String, input) { false }
95
+
96
+ expect(subject).to be_nil
97
+
98
+ expect(coercer).to have_received.call(input)
99
+ expect(coercer).to have_received.success?(String, input)
100
+ end
101
+
102
+ it 'returns the ouput if it was coerced' do
103
+ mock(coercer).call(input) { output }
104
+ mock(coercer).success?(String, output) { true }
105
+
106
+ expect(subject).to be(output)
107
+
108
+ expect(coercer).to have_received.call(input)
109
+ expect(coercer).to have_received.success?(String, output)
110
+ end
111
+ end
112
+
113
+ context 'when both nullify_blank and strict are turned on' do
114
+ let(:nullify_blank) { true }
115
+ let(:strict) { true }
116
+
117
+ it 'does not raises an coercion error' do
118
+ mock(coercer).call(input) { input }
119
+ mock(coercer).success?(String, input) { false }
120
+
121
+ expect { subject }.not_to raise_error
122
+ expect(subject).to be_nil
123
+
124
+ expect(coercer).to have_received.call(input)
125
+ expect(coercer).to have_received.success?(String, input)
126
+ end
127
+ end
128
+ end
81
129
  end
@@ -9,12 +9,12 @@ describe Virtus::Attribute, '#coercible?' do
9
9
  context 'when :coerce is set to true' do
10
10
  let(:coerce) { true }
11
11
 
12
- it { should be(true) }
12
+ it { is_expected.to be(true) }
13
13
  end
14
14
 
15
15
  context 'when :coerce is set to false' do
16
16
  let(:coerce) { false }
17
17
 
18
- it { should be(false) }
18
+ it { is_expected.to be(false) }
19
19
  end
20
20
  end
@@ -1,12 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute, '.build' do
4
- subject { described_class.build(type) }
4
+ subject { described_class.build(type, options) }
5
5
 
6
- share_examples_for 'a valid collection attribute instance' do
7
- it { should be_instance_of(Virtus::Attribute::Collection) }
6
+ let(:options) { {} }
8
7
 
9
- it { should be_frozen }
8
+ shared_examples_for 'a valid collection attribute instance' do
9
+ it { is_expected.to be_instance_of(Virtus::Attribute::Collection) }
10
+
11
+ it { is_expected.to be_frozen }
10
12
  end
11
13
 
12
14
  context 'when type is Array' do
@@ -91,4 +93,13 @@ describe Virtus::Attribute, '.build' do
91
93
  expect(subject.type.member_type).to be(Axiom::Types::String)
92
94
  end
93
95
  end
96
+
97
+ context 'when strict mode is used' do
98
+ let(:type) { Array[String] }
99
+ let(:options) { { strict: true } }
100
+
101
+ it 'sets strict mode for member type' do
102
+ expect(subject.member_type).to be_strict
103
+ end
104
+ end
94
105
  end
@@ -16,10 +16,10 @@ describe Virtus::Attribute::Collection, '#coerce' do
16
16
  }
17
17
 
18
18
  it 'uses coercer to coerce members' do
19
- stub(coercer).call(input) { input }
20
- stub(member_type).finalize { member_type }
21
- stub(member_type).coerce('1') { 1 }
22
- stub(member_type).coerce('2') { 2 }
19
+ mock(coercer).call(input) { input }
20
+ mock(member_type).finalize { member_type }
21
+ mock(member_type).coerce('1') { 1 }
22
+ mock(member_type).coerce('2') { 2 }
23
23
 
24
24
  expect(subject).to eq([1, 2])
25
25
 
@@ -50,4 +50,25 @@ describe Virtus::Attribute::Collection, '#coerce' do
50
50
  end
51
51
  end
52
52
  end
53
+
54
+ context 'when input is nil' do
55
+ let(:input) { nil }
56
+
57
+ fake(:coercer) { Virtus::Attribute::Coercer }
58
+ fake(:member_type) { Virtus::Attribute }
59
+
60
+ let(:member_primitive) { Integer }
61
+
62
+ let(:object) {
63
+ described_class.build(
64
+ Array[member_primitive], coercer: coercer, member_type: member_type
65
+ )
66
+ }
67
+
68
+ it 'returns nil' do
69
+ mock(coercer).call(input) { input }
70
+
71
+ expect(subject).to be(input)
72
+ end
73
+ end
53
74
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'set'
3
+
4
+ describe Virtus::Attribute::Collection, '#value_coerced?' do
5
+ subject { object.value_coerced?(input) }
6
+
7
+ let(:object) { described_class.build(Array[Integer]) }
8
+
9
+ context 'when input has correctly typed members' do
10
+ let(:input) { [1, 2, 3] }
11
+
12
+ it { is_expected.to be(true) }
13
+ end
14
+
15
+ context 'when input has incorrectly typed members' do
16
+ let(:input) { [1, 2, '3'] }
17
+
18
+ it { is_expected.to be(false) }
19
+ end
20
+
21
+ context 'when the collection type is incorrect' do
22
+ let(:input) { Set[1, 2, 3] }
23
+
24
+ it { is_expected.to be(false) }
25
+ end
26
+
27
+ context 'when the input is empty' do
28
+ let(:input) { [] }
29
+ it { is_expected.to be(true) }
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute, '#== (defined by including Virtus::Equalizer)' do
4
+ let(:attribute) { described_class.build(String, :name => :name) }
5
+
6
+ it 'returns true when attributes have same type and options' do
7
+ equal_attribute = described_class.build(String, :name => :name)
8
+ expect(attribute == equal_attribute).to be_truthy
9
+ end
10
+
11
+ it 'returns false when attributes have different type' do
12
+ different_attribute = described_class.build(Integer, :name => :name)
13
+ expect(attribute == different_attribute).to be_falsey
14
+ end
15
+
16
+ it 'returns false when attributes have different options' do
17
+ different_attribute = described_class.build(Integer, :name => :name_two)
18
+ expect(attribute == different_attribute).to be_falsey
19
+ end
20
+ end
@@ -12,12 +12,18 @@ describe Virtus::Attribute::Collection, 'custom subclass' do
12
12
  context 'when primitive is set on the attribute subclass' do
13
13
  let(:attribute_class) { Class.new(described_class).primitive(primitive) }
14
14
 
15
- its(:primitive) { should be(primitive) }
15
+ describe '#primitive' do
16
+ subject { super().primitive }
17
+ it { is_expected.to be(primitive) }
18
+ end
16
19
  end
17
20
 
18
21
  context 'when primitive is not set on the attribute subclass' do
19
22
  let(:attribute_class) { Class.new(described_class) }
20
23
 
21
- its(:primitive) { should be(primitive) }
24
+ describe '#primitive' do
25
+ subject { super().primitive }
26
+ it { is_expected.to be(primitive) }
27
+ end
22
28
  end
23
29
  end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute, '#defined?' do
4
+ subject { object.defined?(instance) }
5
+
6
+ let(:object) { described_class.build(String, :name => name) }
7
+
8
+ let(:model) { Class.new { attr_accessor :test } }
9
+ let(:name) { :test }
10
+ let(:instance) { model.new }
11
+
12
+ context 'when the attribute value has not been defined' do
13
+ it { is_expected.to be(false) }
14
+ end
15
+
16
+ context 'when the attribute value has been defined' do
17
+ before { instance.test = nil }
18
+ it { is_expected.to be(true) }
19
+ end
20
+ end
@@ -6,50 +6,65 @@ describe Virtus::Attribute::EmbeddedValue, '.build' do
6
6
  context 'when type is a Virtus.model' do
7
7
  let(:type) { Class.new { include Virtus.model } }
8
8
 
9
- it { should be_frozen }
9
+ it { is_expected.to be_frozen }
10
10
 
11
- it { should be_instance_of(Virtus::Attribute::EmbeddedValue) }
11
+ it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
12
12
 
13
- its(:coercer) { should be_instance_of(described_class::FromOpenStruct) }
13
+ describe '#coercer' do
14
+ subject { super().coercer }
15
+ it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
16
+ end
14
17
  end
15
18
 
16
19
  context 'when type includes Virtus' do
17
20
  let(:type) { Class.new { include Virtus } }
18
21
 
19
- it { should be_frozen }
22
+ it { is_expected.to be_frozen }
20
23
 
21
- it { should be_instance_of(Virtus::Attribute::EmbeddedValue) }
24
+ it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
22
25
 
23
- its(:coercer) { should be_instance_of(described_class::FromOpenStruct) }
26
+ describe '#coercer' do
27
+ subject { super().coercer }
28
+ it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
29
+ end
24
30
  end
25
31
 
26
32
  context 'when type is an OpenStruct subclass' do
27
33
  let(:type) { Class.new(OpenStruct) }
28
34
 
29
- it { should be_frozen }
35
+ it { is_expected.to be_frozen }
30
36
 
31
- it { should be_instance_of(Virtus::Attribute::EmbeddedValue) }
37
+ it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
32
38
 
33
- its(:coercer) { should be_instance_of(described_class::FromOpenStruct) }
39
+ describe '#coercer' do
40
+ subject { super().coercer }
41
+ it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
42
+ end
34
43
  end
35
44
 
36
45
  context 'when type is OpenStruct' do
37
46
  let(:type) { OpenStruct }
38
47
 
39
- it { should be_frozen }
48
+ it { is_expected.to be_frozen }
40
49
 
41
- it { should be_instance_of(Virtus::Attribute::EmbeddedValue) }
50
+ it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
42
51
 
43
- its(:coercer) { should be_instance_of(described_class::FromOpenStruct) }
52
+ describe '#coercer' do
53
+ subject { super().coercer }
54
+ it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
55
+ end
44
56
  end
45
57
 
46
58
  context 'when type is Struct' do
47
59
  let(:type) { Struct.new(:test) }
48
60
 
49
- it { should be_frozen }
61
+ it { is_expected.to be_frozen }
50
62
 
51
- it { should be_instance_of(Virtus::Attribute::EmbeddedValue) }
63
+ it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
52
64
 
53
- its(:coercer) { should be_instance_of(described_class::FromStruct) }
65
+ describe '#coercer' do
66
+ subject { super().coercer }
67
+ it { is_expected.to be_instance_of(described_class::FromStruct) }
68
+ end
54
69
  end
55
70
  end
@@ -12,22 +12,29 @@ describe Virtus::Attribute::EmbeddedValue, '#coerce' do
12
12
  context 'when input is an attribute hash' do
13
13
  let(:input) { Hash[name: 'Piotr', age: 30] }
14
14
 
15
- it { should be_instance_of(model) }
15
+ it { is_expected.to be_instance_of(model) }
16
16
 
17
- its(:name) { should eql('Piotr') }
18
- its(:age) { should eql(30) }
17
+ describe '#name' do
18
+ subject { super().name }
19
+ it { is_expected.to eql('Piotr') }
20
+ end
21
+
22
+ describe '#age' do
23
+ subject { super().age }
24
+ it { is_expected.to eql(30) }
25
+ end
19
26
  end
20
27
 
21
28
  context 'when input is nil' do
22
29
  let(:input) { nil }
23
30
 
24
- it { should be(nil) }
31
+ it { is_expected.to be(nil) }
25
32
  end
26
33
 
27
34
  context 'when input is a model instance' do
28
35
  let(:input) { OpenStruct.new }
29
36
 
30
- it { should be(input) }
37
+ it { is_expected.to be(input) }
31
38
  end
32
39
  end
33
40
 
@@ -37,22 +44,29 @@ describe Virtus::Attribute::EmbeddedValue, '#coerce' do
37
44
  context 'when input is an attribute hash' do
38
45
  let(:input) { ['Piotr', 30] }
39
46
 
40
- it { should be_instance_of(model) }
47
+ it { is_expected.to be_instance_of(model) }
41
48
 
42
- its(:name) { should eql('Piotr') }
43
- its(:age) { should eql(30) }
49
+ describe '#name' do
50
+ subject { super().name }
51
+ it { is_expected.to eql('Piotr') }
52
+ end
53
+
54
+ describe '#age' do
55
+ subject { super().age }
56
+ it { is_expected.to eql(30) }
57
+ end
44
58
  end
45
59
 
46
60
  context 'when input is nil' do
47
61
  let(:input) { nil }
48
62
 
49
- it { should be(nil) }
63
+ it { is_expected.to be(nil) }
50
64
  end
51
65
 
52
66
  context 'when input is a model instance' do
53
67
  let(:input) { model.new('Piotr', 30) }
54
68
 
55
- it { should be(input) }
69
+ it { is_expected.to be(input) }
56
70
  end
57
71
  end
58
72
 
@@ -63,7 +77,7 @@ describe Virtus::Attribute::EmbeddedValue, '#coerce' do
63
77
  context 'when input is coercible' do
64
78
  let(:input) { ['Piotr'] }
65
79
 
66
- it { should eql(model.new('Piotr')) }
80
+ it { is_expected.to eql(model.new('Piotr')) }
67
81
  end
68
82
 
69
83
  context 'when input is not coercible' do