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
@@ -13,29 +13,36 @@ module Virtus
13
13
  def self.included(descendant)
14
14
  super
15
15
  descendant.extend(ClassMethods)
16
+ descendant.class_eval { include Methods }
16
17
  descendant.class_eval { include InstanceMethods }
18
+ descendant.class_eval { include InstanceMethods::Constructor }
19
+ descendant.class_eval { include InstanceMethods::MassAssignment }
17
20
  end
18
21
  private_class_method :included
19
22
 
20
- private
23
+ module Methods
21
24
 
22
- # Return class' attribute set
23
- #
24
- # @return [Virtus::AttributeSet]
25
- #
26
- # @api private
27
- def attribute_set
28
- self.class.attribute_set
29
- end
25
+ # Return a list of allowed writer method names
26
+ #
27
+ # @return [Set]
28
+ #
29
+ # @api private
30
+ def allowed_writer_methods
31
+ self.class.allowed_writer_methods
32
+ end
30
33
 
31
- # Return a list of allowed writer method names
32
- #
33
- # @return [Set]
34
- #
35
- # @api private
36
- def allowed_writer_methods
37
- self.class.allowed_writer_methods
38
- end
34
+ private
35
+
36
+ # Return class' attribute set
37
+ #
38
+ # @return [Virtus::AttributeSet]
39
+ #
40
+ # @api private
41
+ def attribute_set
42
+ self.class.attribute_set
43
+ end
44
+
45
+ end # Methods
39
46
 
40
47
  end # module ClassInclusions
41
48
  end # module Virtus
@@ -2,7 +2,8 @@ module Virtus
2
2
 
3
3
  # Class methods that are added when you include Virtus
4
4
  module ClassMethods
5
- include Extensions
5
+ include Extensions::Methods
6
+ include ConstMissingExtensions
6
7
 
7
8
  # Hook called when module is extended
8
9
  #
@@ -13,12 +14,12 @@ module Virtus
13
14
  # @api private
14
15
  def self.extended(descendant)
15
16
  super
17
+ AttributeSet.create(descendant)
16
18
  descendant.module_eval do
17
19
  extend DescendantsTracker
18
20
  include attribute_set
19
21
  end
20
22
  end
21
-
22
23
  private_class_method :extended
23
24
 
24
25
  # Returns all the attributes defined on a Class
@@ -39,11 +40,7 @@ module Virtus
39
40
  #
40
41
  # @api public
41
42
  def attribute_set
42
- return @attribute_set if defined?(@attribute_set)
43
- superclass = self.superclass
44
- method = __method__
45
- parent = superclass.public_send(method) if superclass.respond_to?(method)
46
- @attribute_set = AttributeSet.new(parent)
43
+ @attribute_set
47
44
  end
48
45
 
49
46
  # @see Virtus::ClassMethods.attribute_set
@@ -56,18 +53,7 @@ module Virtus
56
53
  attribute_set
57
54
  end
58
55
 
59
- # Hooks into const missing process to determine types of attributes
60
- #
61
- # @param [String] name
62
- #
63
- # @return [Class]
64
- #
65
- # @api private
66
- def const_missing(name)
67
- Attribute.determine_type(name) or super
68
- end
69
-
70
- private
56
+ private
71
57
 
72
58
  # Setup descendants' own Attribute-accessor-method-hosting modules
73
59
  #
@@ -84,21 +70,10 @@ module Virtus
84
70
  # @api private
85
71
  def inherited(descendant)
86
72
  super
73
+ AttributeSet.create(descendant)
87
74
  descendant.module_eval { include attribute_set }
88
75
  end
89
76
 
90
- # Add the attribute to the class' and descendants' attributes
91
- #
92
- # @param [Attribute]
93
- #
94
- # @return [undefined]
95
- #
96
- # @api private
97
- def virtus_add_attribute(attribute)
98
- super
99
- descendants.each { |descendant| descendant.attribute_set.reset }
100
- end
101
-
102
77
  # The list of allowed public methods
103
78
  #
104
79
  # @return [Array<String>]
@@ -108,5 +83,12 @@ module Virtus
108
83
  public_instance_methods.map(&:to_s)
109
84
  end
110
85
 
86
+ # @api private
87
+ def assert_valid_name(name)
88
+ if instance_methods.include?(:attributes) && name.to_sym == :attributes
89
+ raise ArgumentError, "#{name.inspect} is not allowed as an attribute name"
90
+ end
91
+ end
92
+
111
93
  end # module ClassMethods
112
94
  end # module Virtus
@@ -0,0 +1,77 @@
1
+ module Virtus
2
+
3
+ # A Configuration instance
4
+ class Configuration
5
+
6
+ # Access the coerce setting for this instance
7
+ attr_accessor :coerce
8
+
9
+ # Access the strict setting for this instance
10
+ attr_accessor :strict
11
+
12
+ # Access the constructor setting for this instance
13
+ attr_accessor :constructor
14
+
15
+ # Access the mass-assignment setting for this instance
16
+ attr_accessor :mass_assignment
17
+
18
+ # Build new configuration instance using the passed block
19
+ #
20
+ # @example
21
+ # Configuration.build do |config|
22
+ # config.coerce = false
23
+ # end
24
+ #
25
+ # @return [Configuration]
26
+ #
27
+ # @api public
28
+ def self.build(&block)
29
+ new.call(&block)
30
+ end
31
+
32
+ # Initialized a configuration instance
33
+ #
34
+ # @return [undefined]
35
+ #
36
+ # @api private
37
+ def initialize
38
+ @coerce = true
39
+ @strict = false
40
+ @constructor = true
41
+ @mass_assignment = true
42
+ @coercer = Coercible::Coercer.new
43
+ end
44
+
45
+ # Provide access to the attributes and methods via the passed block
46
+ #
47
+ # @example
48
+ # configuration.call do |config|
49
+ # config.coerce = false
50
+ # end
51
+ #
52
+ # @return [self]
53
+ #
54
+ # @api private
55
+ def call(&block)
56
+ block.call(self) if block_given?
57
+ self
58
+ end
59
+
60
+ # Access the coercer for this instance and optional configure a
61
+ # new coercer with the passed block
62
+ #
63
+ # @example
64
+ # configuration.coercer do |config|
65
+ # config.string.boolean_map = { true => '1', false => '0' }
66
+ # end
67
+ #
68
+ # @return [Coercer]
69
+ #
70
+ # @api private
71
+ def coercer(&block)
72
+ @coercer = Coercible::Coercer.new(&block) if block_given?
73
+ @coercer
74
+ end
75
+
76
+ end # class Configuration
77
+ end # module Virtus
@@ -0,0 +1,16 @@
1
+ module Virtus
2
+ module ConstMissingExtensions
3
+
4
+ # Hooks into const missing process to determine types of attributes
5
+ #
6
+ # @param [String] name
7
+ #
8
+ # @return [Class]
9
+ #
10
+ # @api private
11
+ def const_missing(name)
12
+ Attribute::Builder.determine_type(name) or Axiom::Types.const_get(name) or super
13
+ end
14
+
15
+ end
16
+ end
@@ -4,6 +4,7 @@ module Virtus
4
4
  module Extensions
5
5
  WRITER_METHOD_REGEXP = /=\z/.freeze
6
6
  INVALID_WRITER_METHODS = %w[ == != === []= attributes= ].to_set.freeze
7
+ RESERVED_NAMES = [:attributes].to_set.freeze
7
8
 
8
9
  # A hook called when an object is extended with Virtus
9
10
  #
@@ -15,78 +16,102 @@ module Virtus
15
16
  def self.extended(object)
16
17
  super
17
18
  object.instance_eval do
19
+ extend Methods
18
20
  extend InstanceMethods
21
+ extend InstanceMethods::Constructor
22
+ extend InstanceMethods::MassAssignment
19
23
  extend attribute_set
20
24
  end
21
25
  end
22
26
  private_class_method :extended
23
27
 
24
- # Defines an attribute on an object's class
25
- #
26
- # @example
27
- # class Book
28
- # include Virtus
29
- #
30
- # attribute :title, String
31
- # attribute :author, String
32
- # attribute :published_at, DateTime
33
- # attribute :page_count, Integer
34
- # attribute :index # defaults to Object
35
- # end
36
- #
37
- # @param [Symbol] name
38
- # the name of an attribute
39
- #
40
- # @param [Class] type
41
- # the type class of an attribute
42
- #
43
- # @param [#to_hash] options
44
- # the extra options hash
45
- #
46
- # @return [self]
47
- #
48
- # @see Attribute.build
49
- #
50
- # @api public
51
- def attribute(*args)
52
- attribute = Attribute.build(*args)
53
- virtus_add_attribute(attribute)
54
- self
55
- end
28
+ module Methods
56
29
 
57
- # The list of writer methods that can be mass-assigned to in #attributes=
58
- #
59
- # @return [Set]
60
- #
61
- # @api private
62
- def allowed_writer_methods
63
- @allowed_writer_methods ||=
64
- begin
65
- allowed_writer_methods = allowed_methods.grep(WRITER_METHOD_REGEXP).to_set
66
- allowed_writer_methods -= INVALID_WRITER_METHODS
67
- allowed_writer_methods.freeze
30
+ # @api private
31
+ def self.extended(descendant)
32
+ AttributeSet.create(descendant)
33
+ descendant.instance_eval do
34
+ extend attribute_set
35
+ end
68
36
  end
69
- end
37
+ private_class_method :extended
70
38
 
71
- private
39
+ # Defines an attribute on an object's class
40
+ #
41
+ # @example
42
+ # class Book
43
+ # include Virtus
44
+ #
45
+ # attribute :title, String
46
+ # attribute :author, String
47
+ # attribute :published_at, DateTime
48
+ # attribute :page_count, Integer
49
+ # attribute :index # defaults to Object
50
+ # end
51
+ #
52
+ # @param [Symbol] name
53
+ # the name of an attribute
54
+ #
55
+ # @param [Class] type
56
+ # the type class of an attribute
57
+ #
58
+ # @param [#to_hash] options
59
+ # the extra options hash
60
+ #
61
+ # @return [self]
62
+ #
63
+ # @see Attribute.build
64
+ #
65
+ # @api public
66
+ def attribute(name, type, options = {})
67
+ assert_valid_name(name)
68
+ attribute_set << Attribute.build(type, merge_options(name, options))
69
+ self
70
+ end
72
71
 
73
- # Return an attribute set for that instance
74
- #
75
- # @return [AttributeSet]
76
- #
77
- # @api private
78
- def attribute_set
79
- @attribute_set ||= AttributeSet.new
80
- end
72
+ # @api public
73
+ def values(&block)
74
+ private :attributes=
75
+ yield
76
+ include(::Equalizer.new(*attribute_set.map(&:name)))
77
+ self
78
+ end
81
79
 
82
- # Add an attribute to the attribute set
83
- #
84
- # @return [AttributeSet]
85
- #
86
- # @api private
87
- def virtus_add_attribute(attribute)
88
- attribute_set << attribute
89
- end
80
+ # The list of writer methods that can be mass-assigned to in #attributes=
81
+ #
82
+ # @return [Set]
83
+ #
84
+ # @api private
85
+ def allowed_writer_methods
86
+ @allowed_writer_methods ||=
87
+ begin
88
+ allowed_writer_methods = allowed_methods.grep(WRITER_METHOD_REGEXP).to_set
89
+ allowed_writer_methods -= INVALID_WRITER_METHODS
90
+ allowed_writer_methods.freeze
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ # Return an attribute set for that instance
97
+ #
98
+ # @return [AttributeSet]
99
+ #
100
+ # @api private
101
+ def attribute_set
102
+ @attribute_set
103
+ end
104
+
105
+ # Merge default options
106
+ #
107
+ # @return [Hash]
108
+ #
109
+ # @api private
110
+ def merge_options(name, options)
111
+ { :name => name }.merge(options)
112
+ end
113
+
114
+ end # Methods
90
115
 
91
116
  end # module Extensions
92
117
  end # module Virtus
@@ -3,17 +3,74 @@ module Virtus
3
3
  # Instance methods that are added when you include Virtus
4
4
  module InstanceMethods
5
5
 
6
- # Set attributes during initialization of an object
7
- #
8
- # @param [#to_hash] attributes
9
- # the attributes hash to be set
10
- #
11
- # @return [undefined]
12
- #
13
- # @api private
14
- def initialize(attributes = nil)
15
- self.attributes = attributes if attributes
16
- end
6
+ module Constructor
7
+
8
+ # Set attributes during initialization of an object
9
+ #
10
+ # @param [#to_hash] attributes
11
+ # the attributes hash to be set
12
+ #
13
+ # @return [undefined]
14
+ #
15
+ # @api private
16
+ def initialize(attributes = nil)
17
+ attribute_set.set(self, attributes) if attributes
18
+ set_default_attributes
19
+ end
20
+
21
+ end # Constructor
22
+
23
+ module MassAssignment
24
+
25
+ # Returns a hash of all publicly accessible attributes
26
+ #
27
+ # @example
28
+ # class User
29
+ # include Virtus
30
+ #
31
+ # attribute :name, String
32
+ # attribute :age, Integer
33
+ # end
34
+ #
35
+ # user = User.new(:name => 'John', :age => 28)
36
+ # user.attributes # => { :name => 'John', :age => 28 }
37
+ #
38
+ # @return [Hash]
39
+ #
40
+ # @api public
41
+ def attributes
42
+ attribute_set.get(self)
43
+ end
44
+ alias_method :to_hash, :attributes
45
+
46
+ # Mass-assign attribute values
47
+ #
48
+ # Keys in the +attributes+ param can be symbols or strings.
49
+ # All referenced Attribute writer methods *will* be called.
50
+ # Non-attribute setter methods on the receiver *will* be called.
51
+ #
52
+ # @example
53
+ # class User
54
+ # include Virtus
55
+ #
56
+ # attribute :name, String
57
+ # attribute :age, Integer
58
+ # end
59
+ #
60
+ # user = User.new
61
+ # user.attributes = { :name => 'John', 'age' => 28 }
62
+ #
63
+ # @param [#to_hash] attributes
64
+ # a hash of attribute names and values to set on the receiver
65
+ #
66
+ # @return [Hash]
67
+ #
68
+ # @api public
69
+ def attributes=(attributes)
70
+ attribute_set.set(self, attributes)
71
+ end
72
+
73
+ end # MassAssignment
17
74
 
18
75
  # Returns a value of the attribute with the given name
19
76
  #
@@ -35,7 +92,7 @@ module Virtus
35
92
  #
36
93
  # @api public
37
94
  def [](name)
38
- get_attribute(name)
95
+ public_send(name)
39
96
  end
40
97
 
41
98
  # Sets a value of the attribute with the given name
@@ -62,59 +119,17 @@ module Virtus
62
119
  #
63
120
  # @api public
64
121
  def []=(name, value)
65
- set_attribute(name, value)
122
+ public_send("#{name}=", value)
66
123
  end
67
124
 
68
- # Returns a hash of all publicly accessible attributes
69
- #
70
- # @example
71
- # class User
72
- # include Virtus
73
- #
74
- # attribute :name, String
75
- # attribute :age, Integer
76
- # end
77
- #
78
- # user = User.new(:name => 'John', :age => 28)
79
- # user.attributes # => { :name => 'John', :age => 28 }
125
+ # Freeze object
80
126
  #
81
- # @return [Hash]
127
+ # @return [self]
82
128
  #
83
129
  # @api public
84
- def attributes
85
- get_attributes(&:public_reader?)
86
- end
87
-
88
- # Mass-assign attribute values
89
- #
90
- # Keys in the +attributes+ param can be symbols or strings.
91
- # All referenced Attribute writer methods *will* be called.
92
- # Non-attribute setter methods on the receiver *will* be called.
93
130
  #
94
131
  # @example
95
- # class User
96
- # include Virtus
97
- #
98
- # attribute :name, String
99
- # attribute :age, Integer
100
- # end
101
- #
102
- # user = User.new
103
- # user.attributes = { :name => 'John', 'age' => 28 }
104
- #
105
- # @param [#to_hash] attributes
106
- # a hash of attribute names and values to set on the receiver
107
132
  #
108
- # @return [Hash]
109
- #
110
- # @api public
111
- def attributes=(attributes)
112
- set_attributes(attributes)
113
- end
114
-
115
- # Returns a hash of all publicly accessible attributes
116
- #
117
- # @example
118
133
  # class User
119
134
  # include Virtus
120
135
  #
@@ -123,16 +138,17 @@ module Virtus
123
138
  # end
124
139
  #
125
140
  # user = User.new(:name => 'John', :age => 28)
126
- # user.attributes # => { :name => 'John', :age => 28 }
127
- #
128
- # @return [Hash]
141
+ # user.frozen? # => false
142
+ # user.freeze
143
+ # user.frozen? # => true
129
144
  #
130
145
  # @api public
131
- def to_hash
132
- attributes
146
+ def freeze
147
+ set_default_attributes!
148
+ super
133
149
  end
134
150
 
135
- # Freeze object
151
+ # Reset an attribute to its default
136
152
  #
137
153
  # @return [self]
138
154
  #
@@ -143,87 +159,43 @@ module Virtus
143
159
  # class User
144
160
  # include Virtus
145
161
  #
146
- # attribute :name, String
147
- # attribute :age, Integer
162
+ # attribute :age, Integer, default: 21
148
163
  # end
149
164
  #
150
165
  # user = User.new(:name => 'John', :age => 28)
151
- # user.frozen? # => false
152
- # user.freeze
153
- # user.frozen? # => true
166
+ # user.age = 30
167
+ # user.age # => 30
168
+ # user.reset_attribute(:age)
169
+ # user.age # => 21
154
170
  #
155
171
  # @api public
156
- def freeze
157
- set_defaults
158
- super
172
+ def reset_attribute(attribute_name)
173
+ attribute = attribute_set[attribute_name]
174
+ attribute_set.set_default(self, attribute) if attribute
175
+ self
159
176
  end
160
177
 
161
- private
162
-
163
- # Get values of all attributes defined for this class, ignoring privacy
164
- #
165
- # @return [Hash]
166
- #
167
- # @api private
168
- def get_attributes
169
- attribute_set.each_with_object({}) do |attribute, attributes|
170
- name = attribute.name
171
- attributes[name] = get_attribute(name) if yield(attribute)
172
- end
173
- end
174
-
175
- # Ensure all defaults are set
176
- #
177
- # @return [AttributeSet]
178
- #
179
- # @api private
180
- def set_defaults
181
- attribute_set.each do |attribute|
182
- get_attribute(attribute.name)
183
- end
184
- end
185
-
186
- # Mass-assign attribute values
187
- #
188
- # @see Virtus::InstanceMethods#attributes=
178
+ # Set default attributes
189
179
  #
190
- # @return [Hash]
180
+ # @return [self]
191
181
  #
192
182
  # @api private
193
- def set_attributes(attributes)
194
- hash = ::Hash.try_convert(attributes)
195
-
196
- if hash.nil?
197
- raise NoMethodError,
198
- "Expected #{attributes.inspect} to respond to #to_hash"
199
- end
200
-
201
- hash.each do |name, value|
202
- set_attribute(name, value) if allowed_writer_methods.include?("#{name}=")
203
- end
183
+ def set_default_attributes
184
+ attribute_set.set_defaults(self)
185
+ self
204
186
  end
205
187
 
206
- # Returns a value of the attribute with the given name
188
+ # Set default attributes even lazy ones
207
189
  #
208
- # @see Virtus::InstanceMethods#[]
209
- #
210
- # @return [Object]
190
+ # @return [self]
211
191
  #
212
- # @api private
213
- def get_attribute(name)
214
- __send__(name)
192
+ # @api public
193
+ def set_default_attributes!
194
+ attribute_set.set_defaults(self, proc { |_| false })
195
+ self
215
196
  end
216
197
 
217
- # Sets a value of the attribute with the given name
218
- #
219
- # @see Virtus::InstanceMethods#[]=
220
- #
221
- # @return [Object]
222
- #
223
- # @api private
224
- def set_attribute(name, value)
225
- __send__("#{name}=", value)
226
- end
198
+ private
227
199
 
228
200
  # The list of allowed public methods
229
201
  #
@@ -234,5 +206,12 @@ module Virtus
234
206
  public_methods.map(&:to_s)
235
207
  end
236
208
 
209
+ # @api private
210
+ def assert_valid_name(name)
211
+ if respond_to?(:attributes) && name.to_sym == :attributes || name.to_sym == :attribute_set
212
+ raise ArgumentError, "#{name.inspect} is not allowed as an attribute name"
213
+ end
214
+ end
215
+
237
216
  end # module InstanceMethods
238
217
  end # module Virtus