virtus 0.5.5 → 1.0.0.beta3

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 (268) hide show
  1. data/.rspec +1 -1
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +6 -8
  5. data/Gemfile +8 -2
  6. data/Gemfile.devtools +24 -30
  7. data/Guardfile +17 -6
  8. data/README.md +215 -77
  9. data/TODO.md +6 -0
  10. data/config/flay.yml +2 -2
  11. data/config/flog.yml +1 -1
  12. data/config/mutant.yml +12 -1
  13. data/config/reek.yml +57 -66
  14. data/lib/virtus.rb +126 -42
  15. data/lib/virtus/attribute.rb +52 -240
  16. data/lib/virtus/attribute/accessor.rb +91 -0
  17. data/lib/virtus/attribute/boolean.rb +11 -8
  18. data/lib/virtus/attribute/builder.rb +120 -0
  19. data/lib/virtus/attribute/coercer.rb +51 -0
  20. data/lib/virtus/attribute/coercible.rb +14 -0
  21. data/lib/virtus/attribute/collection.rb +44 -90
  22. data/lib/virtus/attribute/default_value/from_callable.rb +1 -1
  23. data/lib/virtus/attribute/default_value/from_clonable.rb +1 -6
  24. data/lib/virtus/attribute/default_value/from_symbol.rb +3 -3
  25. data/lib/virtus/attribute/embedded_value.rb +37 -28
  26. data/lib/virtus/attribute/hash.rb +69 -71
  27. data/lib/virtus/attribute/lazy_default.rb +18 -0
  28. data/lib/virtus/attribute/strict.rb +16 -0
  29. data/lib/virtus/attribute_set.rb +81 -9
  30. data/lib/virtus/class_inclusions.rb +24 -17
  31. data/lib/virtus/class_methods.rb +13 -31
  32. data/lib/virtus/configuration.rb +77 -0
  33. data/lib/virtus/const_missing_extensions.rb +16 -0
  34. data/lib/virtus/extensions.rb +86 -61
  35. data/lib/virtus/instance_methods.rb +107 -128
  36. data/lib/virtus/model.rb +68 -0
  37. data/lib/virtus/module_builder.rb +184 -0
  38. data/lib/virtus/module_extensions.rb +27 -15
  39. data/lib/virtus/support/equalizer.rb +2 -3
  40. data/lib/virtus/support/type_lookup.rb +1 -1
  41. data/lib/virtus/value_object.rb +24 -31
  42. data/lib/virtus/version.rb +1 -1
  43. data/spec/integration/building_module_spec.rb +68 -0
  44. data/spec/integration/custom_attributes_spec.rb +8 -15
  45. data/spec/integration/custom_collection_attributes_spec.rb +101 -0
  46. data/spec/integration/default_values_spec.rb +9 -2
  47. data/spec/integration/defining_attributes_spec.rb +2 -2
  48. data/spec/integration/using_modules_spec.rb +5 -3
  49. data/spec/shared/freeze_method_behavior.rb +2 -2
  50. data/spec/shared/options_class_method.rb +1 -1
  51. data/spec/spec_helper.rb +25 -5
  52. data/spec/unit/virtus/attribute/boolean/value_coerced_predicate_spec.rb +25 -0
  53. data/spec/unit/virtus/attribute/class_methods/build_spec.rb +115 -22
  54. data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +32 -0
  55. data/spec/unit/virtus/attribute/coerce_spec.rb +38 -21
  56. data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +20 -0
  57. data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +84 -0
  58. data/spec/unit/virtus/attribute/collection/coerce_spec.rb +37 -24
  59. data/spec/unit/virtus/attribute/custom_collection_spec.rb +23 -0
  60. data/spec/unit/virtus/attribute/embedded_value/class_methods/build_spec.rb +37 -0
  61. data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +46 -10
  62. data/spec/unit/virtus/attribute/get_spec.rb +15 -63
  63. data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +80 -0
  64. data/spec/unit/virtus/attribute/hash/coerce_spec.rb +75 -13
  65. data/spec/unit/virtus/attribute/lazy_predicate_spec.rb +20 -0
  66. data/spec/unit/virtus/attribute/set_default_value_spec.rb +74 -0
  67. data/spec/unit/virtus/attribute/set_spec.rb +16 -36
  68. data/spec/unit/virtus/attribute/value_coerced_predicate_spec.rb +19 -0
  69. data/spec/unit/virtus/attribute_set/append_spec.rb +3 -5
  70. data/spec/unit/virtus/attribute_set/define_reader_method_spec.rb +1 -1
  71. data/spec/unit/virtus/attribute_set/define_writer_method_spec.rb +1 -1
  72. data/spec/unit/virtus/attribute_set/each_spec.rb +3 -3
  73. data/spec/unit/virtus/attribute_set/element_reference_spec.rb +1 -1
  74. data/spec/unit/virtus/attribute_set/element_set_spec.rb +4 -4
  75. data/spec/unit/virtus/attribute_set/merge_spec.rb +10 -16
  76. data/spec/unit/virtus/attribute_set/reset_spec.rb +6 -10
  77. data/spec/unit/virtus/attribute_spec.rb +222 -0
  78. data/spec/unit/virtus/attributes_reader_spec.rb +41 -0
  79. data/spec/unit/virtus/attributes_writer_spec.rb +51 -0
  80. data/spec/unit/virtus/class_methods/new_spec.rb +39 -0
  81. data/spec/unit/virtus/config_spec.rb +13 -0
  82. data/spec/unit/virtus/element_reader_spec.rb +21 -0
  83. data/spec/unit/virtus/element_writer_spec.rb +19 -0
  84. data/spec/unit/virtus/freeze_spec.rb +21 -0
  85. data/spec/unit/virtus/model_spec.rb +134 -0
  86. data/spec/unit/virtus/module_spec.rb +76 -0
  87. data/spec/unit/virtus/set_default_attributes_spec.rb +25 -0
  88. data/spec/unit/virtus/value_object_spec.rb +105 -0
  89. data/virtus.gemspec +4 -2
  90. metadata +82 -191
  91. data/.rvmrc +0 -1
  92. data/TODO +0 -1
  93. data/config/roodi.yml +0 -17
  94. data/lib/virtus/attribute/array.rb +0 -24
  95. data/lib/virtus/attribute/class.rb +0 -21
  96. data/lib/virtus/attribute/date.rb +0 -34
  97. data/lib/virtus/attribute/date_time.rb +0 -36
  98. data/lib/virtus/attribute/decimal.rb +0 -21
  99. data/lib/virtus/attribute/embedded_value/from_open_struct.rb +0 -19
  100. data/lib/virtus/attribute/embedded_value/from_struct.rb +0 -19
  101. data/lib/virtus/attribute/float.rb +0 -30
  102. data/lib/virtus/attribute/integer.rb +0 -27
  103. data/lib/virtus/attribute/numeric.rb +0 -11
  104. data/lib/virtus/attribute/object.rb +0 -11
  105. data/lib/virtus/attribute/set.rb +0 -24
  106. data/lib/virtus/attribute/string.rb +0 -24
  107. data/lib/virtus/attribute/symbol.rb +0 -21
  108. data/lib/virtus/attribute/time.rb +0 -36
  109. data/lib/virtus/coercion.rb +0 -32
  110. data/lib/virtus/coercion/array.rb +0 -23
  111. data/lib/virtus/coercion/date.rb +0 -26
  112. data/lib/virtus/coercion/date_time.rb +0 -26
  113. data/lib/virtus/coercion/decimal.rb +0 -40
  114. data/lib/virtus/coercion/false_class.rb +0 -24
  115. data/lib/virtus/coercion/float.rb +0 -39
  116. data/lib/virtus/coercion/hash.rb +0 -71
  117. data/lib/virtus/coercion/integer.rb +0 -83
  118. data/lib/virtus/coercion/numeric.rb +0 -66
  119. data/lib/virtus/coercion/object.rb +0 -125
  120. data/lib/virtus/coercion/string.rb +0 -218
  121. data/lib/virtus/coercion/symbol.rb +0 -24
  122. data/lib/virtus/coercion/time.rb +0 -40
  123. data/lib/virtus/coercion/time_coercions.rb +0 -86
  124. data/lib/virtus/coercion/true_class.rb +0 -24
  125. data/spec/unit/virtus/attribute/array/coerce_spec.rb +0 -13
  126. data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +0 -85
  127. data/spec/unit/virtus/attribute/boolean/define_reader_method_spec.rb +0 -15
  128. data/spec/unit/virtus/attribute/boolean/value_coerced_spec.rb +0 -97
  129. data/spec/unit/virtus/attribute/boolean_spec.rb +0 -19
  130. data/spec/unit/virtus/attribute/class/coerce_spec.rb +0 -13
  131. data/spec/unit/virtus/attribute/class_methods/accessor_spec.rb +0 -12
  132. data/spec/unit/virtus/attribute/class_methods/coercion_method_spec.rb +0 -9
  133. data/spec/unit/virtus/attribute/class_methods/default_spec.rb +0 -9
  134. data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +0 -117
  135. data/spec/unit/virtus/attribute/class_methods/merge_options_spec.rb +0 -11
  136. data/spec/unit/virtus/attribute/class_methods/primitive_spec.rb +0 -9
  137. data/spec/unit/virtus/attribute/class_methods/reader_spec.rb +0 -9
  138. data/spec/unit/virtus/attribute/class_methods/writer_spec.rb +0 -9
  139. data/spec/unit/virtus/attribute/coercion_method_spec.rb +0 -12
  140. data/spec/unit/virtus/attribute/collection/class_methods/merge_options_spec.rb +0 -40
  141. data/spec/unit/virtus/attribute/collection/coerce_and_append_member_spec.rb +0 -16
  142. data/spec/unit/virtus/attribute/collection/member_coercion/coerce_and_append_member_spec.rb +0 -18
  143. data/spec/unit/virtus/attribute/collection/member_type_spec.rb +0 -17
  144. data/spec/unit/virtus/attribute/collection/new_collection_spec.rb +0 -9
  145. data/spec/unit/virtus/attribute/date/coerce_spec.rb +0 -47
  146. data/spec/unit/virtus/attribute/date/value_coerced_spec.rb +0 -46
  147. data/spec/unit/virtus/attribute/date_time/coerce_spec.rb +0 -80
  148. data/spec/unit/virtus/attribute/decimal/coerce_spec.rb +0 -123
  149. data/spec/unit/virtus/attribute/default_spec.rb +0 -28
  150. data/spec/unit/virtus/attribute/default_value/call_spec.rb +0 -21
  151. data/spec/unit/virtus/attribute/default_value/class_methods/build_spec.rb +0 -23
  152. data/spec/unit/virtus/attribute/default_value/class_methods/new_spec.rb +0 -21
  153. data/spec/unit/virtus/attribute/default_value/from_callable/call_spec.rb +0 -19
  154. data/spec/unit/virtus/attribute/default_value/from_callable/class_methods/handle_spec.rb +0 -17
  155. data/spec/unit/virtus/attribute/default_value/from_clonable/call_spec.rb +0 -20
  156. data/spec/unit/virtus/attribute/default_value/from_clonable/class_methods/handle_spec.rb +0 -19
  157. data/spec/unit/virtus/attribute/default_value/from_symbol/call_spec.rb +0 -17
  158. data/spec/unit/virtus/attribute/default_value/from_symbol/class_methods/handle_spec.rb +0 -17
  159. data/spec/unit/virtus/attribute/default_value/value_spec.rb +0 -10
  160. data/spec/unit/virtus/attribute/define_accessor_methods_spec.rb +0 -26
  161. data/spec/unit/virtus/attribute/define_reader_method_spec.rb +0 -24
  162. data/spec/unit/virtus/attribute/define_writer_method_spec.rb +0 -24
  163. data/spec/unit/virtus/attribute/embedded_value/class_methods/determine_type_spec.rb +0 -23
  164. data/spec/unit/virtus/attribute/embedded_value/class_methods/merge_options_spec.rb +0 -17
  165. data/spec/unit/virtus/attribute/embedded_value/from_open_struct/coerce_spec.rb +0 -34
  166. data/spec/unit/virtus/attribute/embedded_value/from_struct/coerce_spec.rb +0 -34
  167. data/spec/unit/virtus/attribute/float/coerce_spec.rb +0 -123
  168. data/spec/unit/virtus/attribute/hash/class_methods/merge_options_spec.rb +0 -33
  169. data/spec/unit/virtus/attribute/hash/key_type_spec.rb +0 -10
  170. data/spec/unit/virtus/attribute/hash/value_type_spec.rb +0 -10
  171. data/spec/unit/virtus/attribute/inspect_spec.rb +0 -27
  172. data/spec/unit/virtus/attribute/integer/coerce_spec.rb +0 -117
  173. data/spec/unit/virtus/attribute/name_spec.rb +0 -12
  174. data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +0 -15
  175. data/spec/unit/virtus/attribute/numeric/class_methods/max_spec.rb +0 -9
  176. data/spec/unit/virtus/attribute/numeric/class_methods/min_spec.rb +0 -9
  177. data/spec/unit/virtus/attribute/options_spec.rb +0 -14
  178. data/spec/unit/virtus/attribute/public_reader_spec.rb +0 -24
  179. data/spec/unit/virtus/attribute/public_writer_spec.rb +0 -24
  180. data/spec/unit/virtus/attribute/set/coerce_spec.rb +0 -13
  181. data/spec/unit/virtus/attribute/string/coerce_spec.rb +0 -11
  182. data/spec/unit/virtus/attribute/symbol/coerce_spec.rb +0 -13
  183. data/spec/unit/virtus/attribute/time/coerce_spec.rb +0 -67
  184. data/spec/unit/virtus/attribute/value_coerced_spec.rb +0 -19
  185. data/spec/unit/virtus/class_methods/attribute_set_spec.rb +0 -9
  186. data/spec/unit/virtus/class_methods/attribute_spec.rb +0 -30
  187. data/spec/unit/virtus/class_methods/attributes_spec.rb +0 -22
  188. data/spec/unit/virtus/class_methods/const_missing_spec.rb +0 -27
  189. data/spec/unit/virtus/class_methods/inherited_spec.rb +0 -21
  190. data/spec/unit/virtus/coercion/array/class_methods/to_set_spec.rb +0 -12
  191. data/spec/unit/virtus/coercion/class_methods/element_reference_spec.rb +0 -17
  192. data/spec/unit/virtus/coercion/class_methods/primitive_spec.rb +0 -13
  193. data/spec/unit/virtus/coercion/date/class_methods/to_date_spec.rb +0 -10
  194. data/spec/unit/virtus/coercion/date/class_methods/to_datetime_spec.rb +0 -30
  195. data/spec/unit/virtus/coercion/date/class_methods/to_string_spec.rb +0 -12
  196. data/spec/unit/virtus/coercion/date/class_methods/to_time_spec.rb +0 -12
  197. data/spec/unit/virtus/coercion/date_time/class_methods/to_date_spec.rb +0 -30
  198. data/spec/unit/virtus/coercion/date_time/class_methods/to_datetime_spec.rb +0 -10
  199. data/spec/unit/virtus/coercion/date_time/class_methods/to_string_spec.rb +0 -12
  200. data/spec/unit/virtus/coercion/date_time/class_methods/to_time_spec.rb +0 -30
  201. data/spec/unit/virtus/coercion/decimal/class_methods/to_decimal_spec.rb +0 -9
  202. data/spec/unit/virtus/coercion/decimal/class_methods/to_float_spec.rb +0 -12
  203. data/spec/unit/virtus/coercion/decimal/class_methods/to_integer_spec.rb +0 -12
  204. data/spec/unit/virtus/coercion/decimal/class_methods/to_string_spec.rb +0 -12
  205. data/spec/unit/virtus/coercion/false_class/class_methods/to_string_spec.rb +0 -12
  206. data/spec/unit/virtus/coercion/float/class_methods/to_decimal_spec.rb +0 -12
  207. data/spec/unit/virtus/coercion/float/class_methods/to_float_spec.rb +0 -9
  208. data/spec/unit/virtus/coercion/float/class_methods/to_integer_spec.rb +0 -12
  209. data/spec/unit/virtus/coercion/float/class_methods/to_string_spec.rb +0 -12
  210. data/spec/unit/virtus/coercion/hash/class_methods/to_date_spec.rb +0 -38
  211. data/spec/unit/virtus/coercion/hash/class_methods/to_datetime_spec.rb +0 -38
  212. data/spec/unit/virtus/coercion/hash/class_methods/to_time_spec.rb +0 -38
  213. data/spec/unit/virtus/coercion/integer/class_methods/to_boolean_spec.rb +0 -25
  214. data/spec/unit/virtus/coercion/integer/class_methods/to_decimal_spec.rb +0 -12
  215. data/spec/unit/virtus/coercion/integer/class_methods/to_float_spec.rb +0 -12
  216. data/spec/unit/virtus/coercion/integer/class_methods/to_integer_spec.rb +0 -9
  217. data/spec/unit/virtus/coercion/integer/class_methods/to_string_spec.rb +0 -12
  218. data/spec/unit/virtus/coercion/numeric/class_methods/to_decimal_spec.rb +0 -10
  219. data/spec/unit/virtus/coercion/numeric/class_methods/to_float_spec.rb +0 -10
  220. data/spec/unit/virtus/coercion/numeric/class_methods/to_integer_spec.rb +0 -10
  221. data/spec/unit/virtus/coercion/numeric/class_methods/to_string_spec.rb +0 -12
  222. data/spec/unit/virtus/coercion/object/class_methods/method_missing_spec.rb +0 -33
  223. data/spec/unit/virtus/coercion/object/class_methods/to_array_spec.rb +0 -51
  224. data/spec/unit/virtus/coercion/object/class_methods/to_hash_spec.rb +0 -22
  225. data/spec/unit/virtus/coercion/object/class_methods/to_integer_spec.rb +0 -22
  226. data/spec/unit/virtus/coercion/object/class_methods/to_string_spec.rb +0 -22
  227. data/spec/unit/virtus/coercion/string/class_methods/to_boolean_spec.rb +0 -29
  228. data/spec/unit/virtus/coercion/string/class_methods/to_constant_spec.rb +0 -49
  229. data/spec/unit/virtus/coercion/string/class_methods/to_date_spec.rb +0 -23
  230. data/spec/unit/virtus/coercion/string/class_methods/to_datetime_spec.rb +0 -50
  231. data/spec/unit/virtus/coercion/string/class_methods/to_decimal_spec.rb +0 -47
  232. data/spec/unit/virtus/coercion/string/class_methods/to_float_spec.rb +0 -57
  233. data/spec/unit/virtus/coercion/string/class_methods/to_integer_spec.rb +0 -68
  234. data/spec/unit/virtus/coercion/string/class_methods/to_symbol_spec.rb +0 -9
  235. data/spec/unit/virtus/coercion/string/class_methods/to_time_spec.rb +0 -50
  236. data/spec/unit/virtus/coercion/symbol/class_methods/to_string_spec.rb +0 -12
  237. data/spec/unit/virtus/coercion/time/class_methods/to_integer_spec.rb +0 -10
  238. data/spec/unit/virtus/coercion/time/class_methods/to_time_spec.rb +0 -10
  239. data/spec/unit/virtus/coercion/time_coercions/to_date_spec.rb +0 -33
  240. data/spec/unit/virtus/coercion/time_coercions/to_datetime_spec.rb +0 -33
  241. data/spec/unit/virtus/coercion/time_coercions/to_string_spec.rb +0 -18
  242. data/spec/unit/virtus/coercion/time_coercions/to_time_spec.rb +0 -33
  243. data/spec/unit/virtus/coercion/true_class/class_methods/to_string_spec.rb +0 -12
  244. data/spec/unit/virtus/equalizer/append_spec.rb +0 -82
  245. data/spec/unit/virtus/equalizer/class_method/new_spec.rb +0 -111
  246. data/spec/unit/virtus/equalizer/methods/eql_spec.rb +0 -47
  247. data/spec/unit/virtus/equalizer/methods/equal_value_spec.rb +0 -57
  248. data/spec/unit/virtus/extensions/allowed_writer_methods_spec.rb +0 -25
  249. data/spec/unit/virtus/extensions/attribute_spec.rb +0 -26
  250. data/spec/unit/virtus/instance_methods/attributes_spec.rb +0 -140
  251. data/spec/unit/virtus/instance_methods/element_reference_spec.rb +0 -24
  252. data/spec/unit/virtus/instance_methods/element_set_spec.rb +0 -28
  253. data/spec/unit/virtus/instance_methods/freeze_spec.rb +0 -64
  254. data/spec/unit/virtus/instance_methods/initialize_spec.rb +0 -48
  255. data/spec/unit/virtus/instance_methods/to_hash_spec.rb +0 -23
  256. data/spec/unit/virtus/module_extensions/attribute_spec.rb +0 -31
  257. data/spec/unit/virtus/options/accept_options_spec.rb +0 -37
  258. data/spec/unit/virtus/options/accepted_options_spec.rb +0 -21
  259. data/spec/unit/virtus/options/options_spec.rb +0 -34
  260. data/spec/unit/virtus/type_lookup/class_methods/extended_spec.rb +0 -9
  261. data/spec/unit/virtus/type_lookup/determine_type_spec.rb +0 -81
  262. data/spec/unit/virtus/type_lookup/primitive_spec.rb +0 -9
  263. data/spec/unit/virtus/value_object/class_methods/allowed_writer_methods_spec.rb +0 -15
  264. data/spec/unit/virtus/value_object/class_methods/attribute_spec.rb +0 -50
  265. data/spec/unit/virtus/value_object/class_methods/equalizer_spec.rb +0 -24
  266. data/spec/unit/virtus/value_object/initialize_spec.rb +0 -19
  267. data/spec/unit/virtus/value_object/instance_methods/clone_spec.rb +0 -21
  268. data/spec/unit/virtus/value_object/instance_methods/with_spec.rb +0 -31
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute, '.coerce' do
4
+ subject { described_class.coerce }
5
+
6
+ after :all do
7
+ described_class.coerce(true)
8
+ end
9
+
10
+ context 'with a value' do
11
+ it 'sets the value and return self' do
12
+ expect(described_class.coerce(false)).to be(described_class)
13
+ expect(subject).to be(false)
14
+ end
15
+ end
16
+
17
+ context 'when it is set to true' do
18
+ before do
19
+ described_class.coerce(true)
20
+ end
21
+
22
+ it { should be(true) }
23
+ end
24
+
25
+ context 'when it is set to false' do
26
+ before do
27
+ described_class.coerce(false)
28
+ end
29
+
30
+ it { should be(false) }
31
+ end
32
+ end
@@ -1,30 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute, '#coerce' do
4
- subject { object.coerce(value) }
5
-
6
- let(:object) { described_class.new(:name, options) }
7
- let(:options) { { :primitive => primitive, :coercion_method => coercion_method } }
8
- let(:primitive) { stub('primitive') }
9
- let(:coercion_method) { stub('coercion_method') }
10
- let(:value) { mock('value', :class => value_class) }
11
- let(:value_class) { stub('value_class') }
12
- let(:coercer) { mock('coercer', :public_send => coerced) }
13
- let(:coerced) { stub('coerced') }
14
-
15
- before do
16
- Virtus::Coercion.stub(:[]).with(value_class).and_return(coercer)
17
- end
4
+ subject { object.coerce(input) }
5
+
6
+ fake(:coercer) { Virtus::Attribute::Coercer }
7
+
8
+ let(:object) { described_class.build(String, :coercer => coercer, :strict => strict) }
9
+ let(:input) { 1 }
10
+ let(:output) { '1' }
18
11
 
19
- it { should be(coerced) }
12
+ context 'when strict mode is turned off' do
13
+ let(:strict) { false }
20
14
 
21
- it 'asks for a coercer object' do
22
- Virtus::Coercion.should_receive(:[]).with(value_class)
23
- subject
15
+ it 'uses coercer to coerce the input value' do
16
+ stub(coercer).call(input) { output }
17
+
18
+ expect(subject).to be(output)
19
+
20
+ expect(coercer).to have_received.call(input)
21
+ end
24
22
  end
25
23
 
26
- it 'asks the coercer to coerce the value' do
27
- coercer.should_receive(:public_send).with(coercion_method, value)
28
- subject
24
+ context 'when strict mode is turned on' do
25
+ let(:strict) { true }
26
+
27
+ it 'uses coercer to coerce the input value' do
28
+ stub(coercer).call(input) { output }
29
+ stub(coercer).success?(String, output) { true }
30
+
31
+ expect(subject).to be(output)
32
+
33
+ expect(coercer).to have_received.call(input)
34
+ expect(coercer).to have_received.success?(String, output)
35
+ end
36
+
37
+ it 'raises error when input was not coerced' do
38
+ stub(coercer).call(input) { input }
39
+ stub(coercer).success?(String, input) { false }
40
+
41
+ expect { subject }.to raise_error(ArgumentError)
42
+
43
+ expect(coercer).to have_received.call(input)
44
+ expect(coercer).to have_received.success?(String, input)
45
+ end
29
46
  end
30
47
  end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute, '#coercible?' do
4
+ subject { object.coercible? }
5
+
6
+ let(:object) { described_class.build(String, options) }
7
+ let(:options) { Hash[:coerce => coerce] }
8
+
9
+ context 'when :coerce is set to true' do
10
+ let(:coerce) { true }
11
+
12
+ it { should be(true) }
13
+ end
14
+
15
+ context 'when :coerce is set to false' do
16
+ let(:coerce) { false }
17
+
18
+ it { should be(false) }
19
+ end
20
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute, '.build' do
4
+ subject { described_class.build(type) }
5
+
6
+ share_examples_for 'a valid collection attribute instance' do
7
+ it { should be_instance_of(Virtus::Attribute::Collection) }
8
+
9
+ it { should be_frozen }
10
+ end
11
+
12
+ context 'when type is Array' do
13
+ let(:type) { Array }
14
+
15
+ it_behaves_like 'a valid collection attribute instance'
16
+
17
+ it 'sets default member type' do
18
+ expect(subject.type.member_type).to be(Axiom::Types::Object)
19
+ end
20
+ end
21
+
22
+ context 'when type is Array[Float]' do
23
+ let(:type) { Array[Float] }
24
+
25
+ it_behaves_like 'a valid collection attribute instance'
26
+
27
+ it 'sets member type' do
28
+ expect(subject.type.member_type).to be(Axiom::Types::Float)
29
+ end
30
+ end
31
+
32
+ context 'when type is Array[String, Integer]' do
33
+ let(:type) { Array[String, Integer] }
34
+
35
+ specify do
36
+ expect { subject }.to raise_error(
37
+ NotImplementedError,
38
+ "build SumType from list of types (#{type.inspect})"
39
+ )
40
+ end
41
+ end
42
+
43
+ context 'when type is Set' do
44
+ let(:type) { Set }
45
+
46
+ it_behaves_like 'a valid collection attribute instance'
47
+
48
+ it 'sets default member type' do
49
+ expect(subject.type.member_type).to be(Axiom::Types::Object)
50
+ end
51
+ end
52
+
53
+ context 'when type is Set[Float]' do
54
+ let(:type) { Set[Float] }
55
+
56
+ it_behaves_like 'a valid collection attribute instance'
57
+
58
+ it 'sets member type' do
59
+ expect(subject.type.member_type).to be(Axiom::Types::Float)
60
+ end
61
+ end
62
+
63
+ context 'when type is an Enumerable' do
64
+ let(:type) { Class.new { include Enumerable } }
65
+
66
+ it_behaves_like 'a valid collection attribute instance'
67
+ end
68
+
69
+ context 'when type is Array subclass' do
70
+ let(:type) { Class.new(Array) }
71
+
72
+ it_behaves_like 'a valid collection attribute instance'
73
+ end
74
+
75
+ context 'when type is a custom collection instance' do
76
+ let(:type) { Class.new(Array)[String] }
77
+
78
+ it_behaves_like 'a valid collection attribute instance'
79
+
80
+ it 'sets member type' do
81
+ expect(subject.type.member_type).to be(Axiom::Types::String)
82
+ end
83
+ end
84
+ end
@@ -1,39 +1,52 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::Collection, '#coerce' do
4
- subject { object.coerce(value) }
4
+ subject { object.coerce(input) }
5
5
 
6
- let(:described_class) { Class.new(Virtus::Attribute::Collection) }
7
- let(:object) { described_class.new(:things) }
8
- let(:value) { [ entry ] }
9
- let(:entry) { mock('entry') }
6
+ context 'when input is an array' do
7
+ context 'when member type is a primitive' do
8
+ fake(:coercer) { Virtus::Attribute::Coercer }
9
+ fake(:member_type) { Virtus::Attribute }
10
10
 
11
- before do
12
- described_class.primitive ::Array
13
- value.should_receive(:respond_to?).with(:inject).and_return(respond_to_inject)
14
- end
11
+ let(:member_primitive) { Integer }
12
+ let(:input) { ['1', '2'] }
15
13
 
16
- context 'when coerced value responds to #inject' do
17
- let(:respond_to_inject) { true }
14
+ let(:object) {
15
+ described_class.build(Array[member_primitive], :coercer => coercer, :member_type => member_type)
16
+ }
18
17
 
19
- context 'when the object has not implemented #coerce_and_append_member' do
20
- specify { expect { subject }.to raise_error(NotImplementedError, "#{object.class}#coerce_and_append_member has not been implemented") }
21
- end
18
+ it 'uses coercer to coerce members' do
19
+ stub(coercer).call(input) { input }
20
+ stub(member_type).coerce('1') { 1 }
21
+ stub(member_type).coerce('2') { 2 }
22
+
23
+ expect(subject).to eq([1, 2])
22
24
 
23
- context 'when the object has implemented #coerce_and_append_member' do
24
- before do
25
- def object.coerce_and_append_member(collection, entry)
26
- collection << entry
27
- end
25
+ expect(member_type).to have_received.coerce('1')
26
+ expect(member_type).to have_received.coerce('2')
28
27
  end
28
+ end
29
+
30
+ context 'when member type is an EV' do
31
+ let(:member_primitive) { Struct.new(:id) }
32
+ let(:input) { [1, 2] }
33
+ let(:object) { described_class.build(Array[member_primitive]) }
29
34
 
30
- it { should eql(value) }
35
+ it 'coerces members' do
36
+ expect(subject).to eq([member_primitive.new(1), member_primitive.new(2)])
37
+ end
31
38
  end
32
- end
33
39
 
34
- context 'when coerced value does not respond to #inject' do
35
- let(:respond_to_inject) { false }
40
+ context 'when member type is a hash with key/value coercion' do
41
+ let(:member_primitive) { Hash[String => Integer] }
42
+ let(:member_attribute) { Virtus::Attribute.build(member_primitive) }
43
+ let(:input) { [{:one => '1'}, {:two => '2'}] }
44
+ let(:output) { [member_attribute.coerce(input.first), member_attribute.coerce(input.last)] }
45
+ let(:object) { described_class.build(Array[member_primitive]) }
36
46
 
37
- it { should eql(value) }
47
+ it 'coerces members' do
48
+ expect(subject).to eq(output)
49
+ end
50
+ end
38
51
  end
39
52
  end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute::Collection, 'custom subclass' do
4
+ subject { attribute_class.build(primitive) }
5
+
6
+ let(:primitive) { Class.new { include Enumerable } }
7
+
8
+ after do
9
+ described_class.descendants.delete(attribute_class)
10
+ end
11
+
12
+ context 'when primitive is set on the attribute subclass' do
13
+ let(:attribute_class) { Class.new(described_class).primitive(primitive) }
14
+
15
+ its(:primitive) { should be(primitive) }
16
+ end
17
+
18
+ context 'when primitive is not set on the attribute subclass' do
19
+ let(:attribute_class) { Class.new(described_class) }
20
+
21
+ its(:primitive) { should be(primitive) }
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute::EmbeddedValue, '.build' do
4
+ subject { described_class.build(type) }
5
+
6
+ context 'when type is a virtus model' do
7
+ let(:type) { Class.new { include Virtus } }
8
+
9
+ it { should be_frozen }
10
+
11
+ it { should be_instance_of(Virtus::Attribute::EmbeddedValue::FromOpenStruct) }
12
+ end
13
+
14
+ context 'when type is an OpenStruct subclass' do
15
+ let(:type) { Class.new(OpenStruct) }
16
+
17
+ it { should be_frozen }
18
+
19
+ it { should be_instance_of(Virtus::Attribute::EmbeddedValue::FromOpenStruct) }
20
+ end
21
+
22
+ context 'when type is OpenStruct' do
23
+ let(:type) { OpenStruct }
24
+
25
+ it { should be_frozen }
26
+
27
+ it { should be_instance_of(Virtus::Attribute::EmbeddedValue::FromOpenStruct) }
28
+ end
29
+
30
+ context 'when type is Struct' do
31
+ let(:type) { Struct.new(:test) }
32
+
33
+ it { should be_frozen }
34
+
35
+ it { should be_instance_of(Virtus::Attribute::EmbeddedValue::FromStruct) }
36
+ end
37
+ end
@@ -1,21 +1,57 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::EmbeddedValue, '#coerce' do
4
- subject { object.coerce(value) }
4
+ subject { object.coerce(input) }
5
5
 
6
- let(:object) { described_class.new(:name, :primitive => primitive) }
7
- let(:instance) { Object.new }
8
- let(:value) { primitive.new }
6
+ let(:object) { described_class.build(model) }
9
7
 
10
- context 'when the value is a virtus object' do
11
- let(:primitive) { Class.new { include Virtus } }
8
+ context 'when primitive is OpenStruct' do
9
+ let(:model) { OpenStruct }
12
10
 
13
- it { should be(value) }
11
+ context 'when input is an attribute hash' do
12
+ let(:input) { Hash[name: 'Piotr', age: 30] }
13
+
14
+ it { should be_instance_of(model) }
15
+
16
+ its(:name) { should eql('Piotr') }
17
+ its(:age) { should eql(30) }
18
+ end
19
+
20
+ context 'when input is nil' do
21
+ let(:input) { nil }
22
+
23
+ it { should be(nil) }
24
+ end
25
+
26
+ context 'when input is a model instance' do
27
+ let(:input) { OpenStruct.new }
28
+
29
+ it { should be(input) }
30
+ end
14
31
  end
15
32
 
16
- context 'when the value is a virtus value object' do
17
- let(:primitive) { Class.new { include Virtus::ValueObject } }
33
+ context 'when primitive is Struct' do
34
+ let(:model) { Struct.new(:name, :age) }
35
+
36
+ context 'when input is an attribute hash' do
37
+ let(:input) { ['Piotr', 30] }
38
+
39
+ it { should be_instance_of(model) }
40
+
41
+ its(:name) { should eql('Piotr') }
42
+ its(:age) { should eql(30) }
43
+ end
44
+
45
+ context 'when input is nil' do
46
+ let(:input) { nil }
47
+
48
+ it { should be(nil) }
49
+ end
50
+
51
+ context 'when input is a model instance' do
52
+ let(:input) { model.new('Piotr', 30) }
18
53
 
19
- it { should be(value) }
54
+ it { should be(input) }
55
+ end
20
56
  end
21
57
  end
@@ -3,78 +3,30 @@ require 'spec_helper'
3
3
  describe Virtus::Attribute, '#get' do
4
4
  subject { object.get(instance) }
5
5
 
6
- let(:object) { described_class.new(:name, options) }
7
- let(:options) { { :primitive => primitive, :coercion_method => coercion_method } }
8
- let(:primitive) { stub('primitive') }
9
- let(:coercion_method) { stub('coercion_method') }
10
- let(:instance) { Object.new }
6
+ let(:object) { described_class.build(String, options.update(:name => name)) }
11
7
 
12
- context 'when the instance variable is set' do
13
- let(:value) { stub('value') }
8
+ let(:model) { Class.new { attr_accessor :test } }
9
+ let(:name) { :test }
10
+ let(:instance) { model.new }
11
+ let(:value) { 'Jane Doe' }
12
+ let(:options) { {} }
14
13
 
14
+ context 'with :lazy is set to false' do
15
15
  before do
16
- instance.instance_variable_set(:@name, value)
16
+ instance.test = value
17
17
  end
18
18
 
19
- it 'gets the value from the instance variable' do
20
- should be(value)
21
- end
22
- end
23
-
24
- context 'when the instance variable is not set' do
25
- context 'when there is no default' do
26
- it 'returns nil' do
27
- should be_nil
28
- end
29
-
30
- it 'sets the ivar' do
31
- expect { subject }.to change { instance.instance_variable_defined?(:@name) }.from(false).to(true)
32
- end
33
- end
34
-
35
- context 'when there is a default' do
36
- let(:default) { stub('default') }
37
-
38
- before do
39
- default.stub(:clone).and_return(default)
40
- options.update(:default => default)
41
- end
42
-
43
- it 'gets the default from the instance variable' do
44
- should be(default)
45
- end
46
- end
19
+ it { should be(value) }
47
20
  end
48
- end
49
21
 
50
- describe Virtus::Attribute, '#get!' do
51
- subject { object.get!(instance) }
22
+ context 'with :lazy is set to true' do
23
+ let(:options) { { :lazy => true, :default => value } }
52
24
 
53
- let(:object) { described_class.new(:name, options) }
54
- let(:options) { { :primitive => primitive, :coercion_method => coercion_method } }
55
- let(:primitive) { stub('primitive') }
56
- let(:coercion_method) { stub('coercion_method') }
57
- let(:instance) { Object.new }
58
-
59
- context 'when the instance variable is set' do
60
- let(:value) { stub('value') }
61
-
62
- before do
63
- instance.instance_variable_set(:@name, value)
64
- end
65
-
66
- it 'gets the value from the instance variable' do
67
- should be(value)
68
- end
69
- end
70
-
71
- context 'when the instance variable is not set' do
72
- it 'returns nil' do
73
- should be_nil
74
- end
25
+ it { should eql(value) }
75
26
 
76
- it 'does not set the ivar' do
77
- expect { subject }.to_not change { instance.instance_variable_defined?(:@name) }
27
+ it 'sets default only on first access' do
28
+ expect(object.get(instance)).to eql(value)
29
+ expect(object.get(instance)).to be(instance.test)
78
30
  end
79
31
  end
80
32
  end