virtus 0.5.5 → 1.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
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,91 @@
1
+ module Virtus
2
+ class Attribute
3
+
4
+ # Accessor extension provides methods to read and write attributes
5
+ #
6
+ # @example
7
+ #
8
+ # attribute = Virtus::Attribute.build(String, :name => :email)
9
+ # model = Class.new { attr_reader :email }
10
+ # object = model.new
11
+ #
12
+ # attribute.set(object, 'jane@doe.com')
13
+ # attribute.get(object) # => 'jane@doe.com'
14
+ #
15
+ module Accessor
16
+
17
+ # Return name of this accessor attribute
18
+ #
19
+ # @return [Symbol]
20
+ #
21
+ # @api public
22
+ attr_reader :name
23
+
24
+ # Return instance_variable_name used by this accessor
25
+ #
26
+ # @api private
27
+ attr_reader :instance_variable_name
28
+
29
+ # Return value of the attribute
30
+ #
31
+ # @param [Object] instance
32
+ #
33
+ # @return [Object]
34
+ #
35
+ # @api public
36
+ def get(instance)
37
+ instance.instance_variable_get(instance_variable_name)
38
+ end
39
+
40
+ # Set value of the attribute
41
+ #
42
+ # @param [Object] instance
43
+ # @param [Object] value
44
+ #
45
+ # @return [Object] value that was set
46
+ #
47
+ # @api public
48
+ def set(instance, value)
49
+ instance.instance_variable_set(instance_variable_name, value)
50
+ end
51
+
52
+ # Set default value
53
+ #
54
+ # @param [Object] instance
55
+ #
56
+ # @return [Object] value that was set
57
+ #
58
+ # @api public
59
+ def set_default_value(instance)
60
+ set(instance, default_value.call(instance, self))
61
+ end
62
+
63
+ # Returns a Boolean indicating whether the reader method is public
64
+ #
65
+ # @return [Boolean]
66
+ #
67
+ # @api private
68
+ def public_reader?
69
+ options[:reader] == :public
70
+ end
71
+
72
+ # Returns a Boolean indicating whether the writer method is public
73
+ #
74
+ # @return [Boolean]
75
+ #
76
+ # @api private
77
+ def public_writer?
78
+ options[:writer] == :public
79
+ end
80
+
81
+ # @api private
82
+ def finalize
83
+ @name = options.fetch(:name).to_sym
84
+ @instance_variable_name = "@#{@name}"
85
+ super
86
+ end
87
+
88
+ end # Accessor
89
+
90
+ end # Attribute
91
+ end # Virtus
@@ -14,9 +14,13 @@ module Virtus
14
14
  # post = Post.new(:published => false)
15
15
  # post.published? # => false
16
16
  #
17
- class Boolean < Object
18
- primitive TrueClass
19
- coercion_method :to_boolean
17
+ class Boolean < Attribute
18
+ primitive TrueClass
19
+
20
+ # @api private
21
+ def self.build_type(*)
22
+ Axiom::Types::Boolean
23
+ end
20
24
 
21
25
  # Returns if the given value is either true or false
22
26
  #
@@ -31,20 +35,19 @@ module Virtus
31
35
  #
32
36
  # @api public
33
37
  def value_coerced?(value)
34
- value.equal?(true) or value.equal?(false)
38
+ value.equal?(true) || value.equal?(false)
35
39
  end
36
40
 
37
41
  # Creates an attribute reader method as a query
38
42
  #
39
43
  # @param [Module] mod
40
44
  #
41
- # @return [self]
45
+ # @return [undefined]
42
46
  #
43
47
  # @api private
44
- def define_reader_method(mod)
48
+ def define_accessor_methods(attribute_set)
45
49
  super
46
- mod.define_reader_method(self, "#{name}?", @reader_visibility)
47
- self
50
+ attribute_set.define_reader_method(self, "#{name}?", options[:reader])
48
51
  end
49
52
 
50
53
  end # class Boolean
@@ -0,0 +1,120 @@
1
+ module Virtus
2
+ class Attribute
3
+
4
+ # TODO: this is a huge class and it might be a good idea to split it into
5
+ # smaller chunks. We probably need some option parser with dedicated
6
+ # sub-classes per attribute type (different one for Hash, Collection, EV)
7
+ #
8
+ # @private
9
+ class Builder
10
+ attr_reader :attribute
11
+
12
+ # @api private
13
+ def self.call(*args)
14
+ new(*args).attribute
15
+ end
16
+
17
+ # @api private
18
+ def self.determine_type(klass, default = nil)
19
+ type = Attribute.determine_type(klass)
20
+
21
+ if klass.is_a?(Class)
22
+ type ||=
23
+ if klass < Axiom::Types::Type
24
+ determine_type(klass.primitive)
25
+ elsif EmbeddedValue.handles?(klass)
26
+ EmbeddedValue.determine_type(klass)
27
+ elsif klass < Enumerable
28
+ Collection
29
+ end
30
+ end
31
+
32
+ type || default
33
+ end
34
+
35
+ # @api private
36
+ def initialize(type, options)
37
+ initialize_primitive(type)
38
+ initialize_class
39
+ initialize_type(:type => type, :primitive => @primitive)
40
+ initialize_options(options)
41
+ initialize_default_value
42
+ initialize_coercer
43
+ initialize_attribute
44
+ end
45
+
46
+ private
47
+
48
+ # @api private
49
+ def initialize_attribute
50
+ @attribute = @klass.new(@type, @options) do |attribute|
51
+ attribute.extend(Accessor) if @options[:name]
52
+ attribute.extend(Coercible) if @options[:coerce]
53
+ attribute.extend(Strict) if @options[:strict]
54
+ attribute.extend(LazyDefault) if @options[:lazy]
55
+ end
56
+ end
57
+
58
+ # @api private
59
+ def initialize_default_value
60
+ @options.update(:default_value => DefaultValue.build(@options[:default]))
61
+ end
62
+
63
+ # @api private
64
+ def initialize_coercer
65
+ @options.update(:coercer => @options.fetch(:coercer) { build_coercer })
66
+ end
67
+
68
+ # @api private
69
+ def initialize_primitive(type)
70
+ @primitive =
71
+ if type.instance_of?(String) || type.instance_of?(Symbol)
72
+ begin
73
+ Object.const_get(type)
74
+ rescue
75
+ type
76
+ end
77
+ elsif not type.is_a?(Class)
78
+ type.class
79
+ else
80
+ type
81
+ end
82
+ end
83
+
84
+ # @api private
85
+ def initialize_class
86
+ @klass = self.class.determine_type(@primitive, Attribute)
87
+ end
88
+
89
+ # @api private
90
+ def initialize_type(options)
91
+ @type = @klass.build_type(options)
92
+ end
93
+
94
+ # @api private
95
+ def initialize_options(options)
96
+ @options = @klass.options.merge(:coerce => Virtus.coerce).update(options)
97
+ @klass.merge_options!(@type, @options)
98
+ determine_visibility!
99
+ end
100
+
101
+ # @api private
102
+ def determine_visibility!
103
+ default_accessor = @options.fetch(:accessor)
104
+ reader_visibility = @options.fetch(:reader, default_accessor)
105
+ writer_visibility = @options.fetch(:writer, default_accessor)
106
+ @options.update(:reader => reader_visibility, :writer => writer_visibility)
107
+ end
108
+
109
+ # @api private
110
+ def build_coercer
111
+ Coercer.new(
112
+ @options.fetch(:configured_coercer) { Virtus.coercer },
113
+ @type.coercion_method
114
+ )
115
+ end
116
+
117
+ end # class Builder
118
+
119
+ end # class Attribute
120
+ end # module Virtus
@@ -0,0 +1,51 @@
1
+ module Virtus
2
+ class Attribute
3
+
4
+ # Coercer accessor wrapper
5
+ #
6
+ # @api private
7
+ class Coercer
8
+ attr_reader :method
9
+
10
+ # Initialize a new coercer object
11
+ #
12
+ # @param [Object] coercers accessor
13
+ # @param [Symbol] coercion method
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ def initialize(coercers, method)
19
+ @coercers = coercers
20
+ @method = method
21
+ end
22
+
23
+ # Coerce given value
24
+ #
25
+ # @return [Object]
26
+ #
27
+ # @api private
28
+ def call(value)
29
+ self[value.class].public_send(@method, value)
30
+ rescue ::Coercible::UnsupportedCoercion
31
+ value
32
+ end
33
+
34
+ # @api public
35
+ def success?(primitive, value)
36
+ self[primitive].coerced?(value)
37
+ end
38
+
39
+ # Return coercer object for the given type
40
+ #
41
+ # @return [Object]
42
+ #
43
+ # @api private
44
+ def [](type)
45
+ @coercers[type]
46
+ end
47
+
48
+ end # class Coercer
49
+
50
+ end # class Attribute
51
+ end # module Virtus
@@ -0,0 +1,14 @@
1
+ module Virtus
2
+ class Attribute
3
+
4
+ module Coercible
5
+
6
+ # @api public
7
+ def set(instance, value)
8
+ super(instance, coerce(value))
9
+ end
10
+
11
+ end # Coercible
12
+
13
+ end # Attribute
14
+ end # Virtus
@@ -6,111 +6,65 @@ module Virtus
6
6
  # Handles coercing members to the designated member type.
7
7
  #
8
8
  # @abstract
9
- class Collection < Object
9
+ class Collection < Attribute
10
+ default Proc.new { |_, attribute| attribute.type.primitive.new }
10
11
 
11
- # The type to which members of this collection will be coerced
12
- #
13
- # @example
14
- #
15
- # class Post
16
- # include Virtus
17
- #
18
- # attribute :tags, Array[String]
19
- # end
20
- #
21
- # Post.attributes[:tags].member_type # => Virtus::Attribute::String
22
- #
23
- # @return [Virtus::Attribute]
24
- #
25
- # @api public
26
- attr_reader :member_type
12
+ # FIXME: temporary hack, remove when Axiom::Type works with EV as member_type
13
+ Type = Struct.new(:primitive, :member_type) do
14
+ def self.infer(type, primitive)
15
+ return type if type.is_a?(Class) && type < Axiom::Types::Type
27
16
 
28
- # Handles collection with member_type syntax
29
- #
30
- # @param [Class]
31
- #
32
- # @param [Hash]
33
- #
34
- # @return [Hash]
35
- #
36
- # @api private
37
- def self.merge_options(type, options)
38
- if !type.respond_to?(:size)
39
- options
40
- elsif type.size > 1
41
- raise NotImplementedError, "build SumType from list of types (#{type.inspect})"
42
- else
43
- options.merge(:member_type => type.first)
17
+ klass = Axiom::Types.infer(type)
18
+ member = infer_member_type(type) || Object
19
+
20
+ if EmbeddedValue.handles?(member)
21
+ Type.new(primitive, member)
22
+ else
23
+ klass.new {
24
+ primitive primitive
25
+ member_type Axiom::Types.infer(member)
26
+ }
27
+ end
44
28
  end
45
- end
46
29
 
47
- # Init an instance of Virtus::Attribute::Collection
48
- #
49
- # @api private
50
- def initialize(*)
51
- super
52
- @member_type = @options.fetch(:member_type, Virtus::Attribute::Object)
53
- @member_type_instance = Attribute.build(@name, @member_type)
54
- end
30
+ def self.infer_member_type(type)
31
+ return unless type.respond_to?(:count)
55
32
 
56
- # Coerce a collection with members
57
- #
58
- # @param [Object]
59
- #
60
- # @return [Object]
61
- #
62
- # @api private
63
- def coerce(value)
64
- coerced = super
65
- return coerced unless coerced.respond_to?(:inject)
66
- coerced.inject(new_collection) do |*args|
67
- coerce_and_append_member(*args)
33
+ if type.count > 1
34
+ raise NotImplementedError, "build SumType from list of types (#{type})"
35
+ else
36
+ type.first
37
+ end
38
+ end
39
+
40
+ def coercion_method
41
+ :to_array
68
42
  end
69
43
  end
70
44
 
71
- # Return an instance of the collection
72
- #
73
- # @return [Enumerable]
74
- #
75
45
  # @api private
76
- def new_collection
77
- self.class.primitive.new
46
+ def self.build_type(options)
47
+ Type.infer(options.fetch(:type), options.fetch(:primitive))
78
48
  end
79
49
 
80
- # Coerce entry and add it to the collection
81
- #
82
- # @abstract
83
- #
84
- # @raise NotImplementedError
85
- #
86
- # @return [undefined]
87
- #
88
50
  # @api private
89
- def coerce_and_append_member(collection, entry)
90
- raise NotImplementedError,
91
- "#{self.class}#coerce_and_append_member has not been implemented"
51
+ def self.merge_options!(type, options)
52
+ unless options.key?(:member_type)
53
+ options[:member_type] = Attribute.build(type.member_type)
54
+ end
92
55
  end
93
56
 
94
- # Default coercion method for collection members used by Array and Set
95
- module MemberCoercion
96
-
97
- # Coerce a member of a source collection and append it to the target collection
98
- #
99
- # @param [Array, Set] collection
100
- # target collection to which the coerced member should be appended
101
- #
102
- # @param [Object] entry
103
- # the member that should be coerced and appended
104
- #
105
- # @return [Array, Set]
106
- # collection with the coerced member appended to it
107
- #
108
- # @api private
109
- def coerce_and_append_member(collection, entry)
110
- collection << @member_type_instance.coerce(entry)
57
+ # @api public
58
+ def coerce(*)
59
+ super.each_with_object(primitive.new) do |entry, collection|
60
+ collection << member_type.coerce(entry)
111
61
  end
112
- end # module MemberCoercion
62
+ end
63
+
64
+ def member_type
65
+ @options[:member_type]
66
+ end
113
67
 
114
- end # class Array
68
+ end # class Collection
115
69
  end # class Attribute
116
70
  end # module Virtus