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,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