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
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
1
  --color
2
- --profile
2
+ --order random
@@ -0,0 +1 @@
1
+ virtus
@@ -0,0 +1 @@
1
+ 1.9.3
@@ -1,19 +1,17 @@
1
1
  language: ruby
2
- bundler_args: --without guard metrics
2
+ before_install: gem install bundler
3
+ bundler_args: --without yard guard benchmarks
3
4
  script: "bundle exec rake spec"
4
5
  rvm:
5
- - 1.8.7
6
- - 1.9.2
7
6
  - 1.9.3
8
- - jruby-18mode
7
+ - 2.0.0
9
8
  - jruby-19mode
10
- - rbx-18mode
11
9
  - rbx-19mode
12
- - ree
13
- - jruby-head
10
+ - ruby-head
14
11
  matrix:
15
12
  allow_failures:
16
- - rvm: jruby-head
13
+ - rvm: ruby-head
14
+ - rvm: rbx-19mode
17
15
  notifications:
18
16
  email:
19
17
  - piotr.solnica@gmail.com
data/Gemfile CHANGED
@@ -2,6 +2,12 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'devtools', :git => 'https://github.com/datamapper/devtools'
5
+ gem 'bogus', '~> 0.1'
6
6
 
7
- eval File.read('Gemfile.devtools')
7
+ gem 'axiom-types', :git => 'https://github.com/dkubb/axiom-types'
8
+
9
+ gem 'devtools', :git => 'https://github.com/rom-rb/devtools', branch: 'master'
10
+
11
+ eval_gemfile 'Gemfile.devtools'
12
+
13
+ gem 'mutant', git: 'https://github.com/solnic/mutant.git', branch: 'auto-expand-scope'
@@ -1,52 +1,46 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  group :development do
4
- gem 'rake', '~> 10.0.4'
5
- gem 'rspec', '~> 2.13.0'
6
- gem 'yard', '~> 0.8.6.1'
4
+ gem 'rake', '~> 10.1.0'
5
+ gem 'rspec', '~> 2.14.1'
6
+ gem 'yard', '~> 0.8.7'
7
7
  end
8
8
 
9
9
  group :yard do
10
- gem 'kramdown', '~> 1.0.1'
10
+ gem 'kramdown', '~> 1.2.0'
11
11
  end
12
12
 
13
13
  group :guard do
14
- gem 'guard', '~> 1.8.0'
14
+ gem 'guard', '~> 1.8.1'
15
15
  gem 'guard-bundler', '~> 1.0.0'
16
- gem 'guard-rspec', '~> 2.5.4'
16
+ gem 'guard-rspec', '~> 3.0.2'
17
+ gem 'guard-rubocop', '~> 0.2.0'
18
+ gem 'guard-mutant', '~> 0.0.1'
17
19
 
18
20
  # file system change event handling
19
- gem 'listen', '~> 1.0.2'
20
- gem 'rb-fchange', '~> 0.0.6', :require => false
21
- gem 'rb-fsevent', '~> 0.9.3', :require => false
22
- gem 'rb-inotify', '~> 0.9.0', :require => false
21
+ gem 'listen', '~> 1.3.0'
22
+ gem 'rb-fchange', '~> 0.0.6', require: false
23
+ gem 'rb-fsevent', '~> 0.9.3', require: false
24
+ gem 'rb-inotify', '~> 0.9.0', require: false
23
25
 
24
26
  # notification handling
25
- gem 'libnotify', '~> 0.8.0', :require => false
26
- gem 'rb-notifu', '~> 0.0.4', :require => false
27
- gem 'terminal-notifier-guard', '~> 1.5.3', :require => false
27
+ gem 'libnotify', '~> 0.8.0', require: false
28
+ gem 'rb-notifu', '~> 0.0.4', require: false
29
+ gem 'terminal-notifier-guard', '~> 1.5.3', require: false
28
30
  end
29
31
 
30
32
  group :metrics do
31
- gem 'backports', '~> 3.3', '>= 3.3.0'
32
- gem 'coveralls', '~> 0.6.6'
33
- gem 'flay', '~> 2.2.0'
34
- gem 'flog', '~> 4.0.0'
35
- gem 'reek', '~> 1.3.1', :git => 'https://github.com/troessner/reek.git'
36
- gem 'simplecov', '~> 0.7.1'
37
- gem 'yardstick', '~> 0.9.6'
38
-
39
- platforms :ruby_19 do
33
+ gem 'coveralls', '~> 0.6.7'
34
+ gem 'flay', '~> 2.4.0'
35
+ gem 'flog', '~> 4.1.1'
36
+ gem 'reek', '~> 1.3.2'
37
+ gem 'rubocop', '~> 0.13.0'
38
+ gem 'simplecov', '~> 0.7.1'
39
+ gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
40
+
41
+ platforms :ruby_19, :ruby_20 do
40
42
  gem 'yard-spellcheck', '~> 0.1.5'
41
43
  end
42
-
43
- platforms :mri_19, :rbx do
44
- gem 'mutant', '~> 0.2.20'
45
- end
46
-
47
- platforms :rbx do
48
- gem 'pelusa', '~> 0.2.2'
49
- end
50
44
  end
51
45
 
52
46
  group :benchmarks do
data/Guardfile CHANGED
@@ -1,8 +1,19 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
1
+ guard :rspec, spec_paths: 'spec/unit' do
2
+ #run all specs if configuration is modified
3
+ watch('Guardfile') { 'spec' }
4
+ watch('Gemfile.lock') { 'spec' }
5
+ watch('spec/spec_helper.rb') { 'spec' }
3
6
 
4
- guard 'rspec', :version => 1 do
5
- watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
- watch('spec/spec_helper.rb') { "spec" }
7
+ # run all specs if supporting files files are modified
8
+ watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec' }
9
+
10
+ # run unit specs if associated lib code is modified
11
+ watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}"] }
12
+ watch(%r{\Alib/(.+)/support/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}/#{m[2]}"] }
13
+ watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
14
+
15
+ # run a spec if it is modified
16
+ watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
17
+
18
+ notification :tmux, :display_message => true
8
19
  end
data/README.md CHANGED
@@ -1,9 +1,17 @@
1
1
  Virtus
2
2
  ======
3
3
 
4
- [![Build Status](https://secure.travis-ci.org/solnic/virtus.png)](http://travis-ci.org/solnic/virtus)
5
- [![Dependency Status](https://gemnasium.com/solnic/virtus.png)](https://gemnasium.com/solnic/virtus)
6
- [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/solnic/virtus)
4
+ [![Gem Version](https://badge.fury.io/rb/virtus.png)][gem]
5
+ [![Build Status](https://secure.travis-ci.org/solnic/virtus.png?branch=master)][travis]
6
+ [![Dependency Status](https://gemnasium.com/solnic/virtus.png)][gemnasium]
7
+ [![Code Climate](https://codeclimate.com/github/solnic/virtus.png)][codeclimate]
8
+ [![Coverage Status](https://coveralls.io/repos/solnic/virtus/badge.png?branch=master)][coveralls]
9
+
10
+ [gem]: https://rubygems.org/gems/virtus
11
+ [travis]: https://travis-ci.org/solnic/virtus
12
+ [gemnasium]: https://gemnasium.com/solnic/virtus
13
+ [codeclimate]: https://codeclimate.com/github/solnic/virtus
14
+ [coveralls]: https://coveralls.io/r/solnic/virtus
7
15
 
8
16
  This is a partial extraction of the DataMapper [Property
9
17
  API](http://rubydoc.info/github/datamapper/dm-core/master/DataMapper/Property)
@@ -35,19 +43,19 @@ You can create classes extended with virtus and define attributes:
35
43
 
36
44
  ``` ruby
37
45
  class User
38
- include Virtus
46
+ include Virtus.model
39
47
 
40
48
  attribute :name, String
41
49
  attribute :age, Integer
42
50
  attribute :birthday, DateTime
43
51
  end
44
52
 
45
- user = User.new(:name => 'Piotr', :age => 28)
46
- user.attributes # => { :name => "Piotr", :age => 28 }
53
+ user = User.new(:name => 'Piotr', :age => 29)
54
+ user.attributes # => { :name => "Piotr", :age => 29 }
47
55
 
48
56
  user.name # => "Piotr"
49
57
 
50
- user.age = '28' # => 28
58
+ user.age = '29' # => 29
51
59
  user.age.class # => Fixnum
52
60
 
53
61
  user.birthday = 'November 18th, 1983' # => #<DateTime: 1983-11-18T00:00:00+00:00 (4891313/2,0/1,2299161)>
@@ -58,6 +66,51 @@ user.name # => "Jane"
58
66
  user.age # => 21
59
67
  ```
60
68
 
69
+ ### Cherry-picking extensions
70
+
71
+ ``` ruby
72
+ # include just the attribute DSL
73
+ class User
74
+ include Virtus::Model::Core
75
+
76
+ attribute :name, String
77
+ end
78
+
79
+ user = User.new
80
+ user.name = 'Piotr'
81
+
82
+ # include attribute DSL + constructor
83
+ class User
84
+ include Virtus::Model::Core
85
+ include Virtus::Model::Constructor
86
+
87
+ attribute :name, String
88
+ end
89
+
90
+ User.new(:name => 'Piotr')
91
+
92
+ # include attribute DSL + constructor + mass-assignment
93
+ class User
94
+ include Virtus::Model::Core
95
+ include Virtus::Model::Constructor
96
+ include Virtus::Model::MassAssignment
97
+
98
+ attribute :name, String
99
+ end
100
+
101
+ user = User.new(:name => 'Piotr')
102
+ user.attributes = { :name => 'John' }
103
+ user.attributes
104
+ # => {:name => 'John'}
105
+
106
+ # starting from virtus 1.0.0 preffered way to do this is to use module builder
107
+ MyModel = Virtus.model(:constructor => false, :mass_assignment => false)
108
+
109
+ class User
110
+ include MyModel
111
+ end
112
+ ```
113
+
61
114
  ### Using Virtus with Modules
62
115
 
63
116
  You can create modules extended with virtus and define attributes for later
@@ -65,13 +118,13 @@ inclusion in your classes:
65
118
 
66
119
  ```ruby
67
120
  module Name
68
- include Virtus
121
+ include Virtus.module
69
122
 
70
123
  attribute :name, String
71
124
  end
72
125
 
73
126
  module Age
74
- include Virtus
127
+ include Virtus.module(:coerce => false)
75
128
 
76
129
  attribute :age, Integer
77
130
  end
@@ -80,7 +133,7 @@ class User
80
133
  include Name, Age
81
134
  end
82
135
 
83
- user = User.new(:name => 'John', :age => '30')
136
+ user = User.new(:name => 'John', :age => 30)
84
137
  ```
85
138
 
86
139
  ### Dynamically Extending Instances
@@ -93,7 +146,7 @@ class User
93
146
  end
94
147
 
95
148
  user = User.new
96
- user.extend(Virtus)
149
+ user.extend(Virtus.model)
97
150
  user.attribute :name, String
98
151
  user.name = 'John'
99
152
  user.name # => 'John'
@@ -103,7 +156,7 @@ user.name # => 'John'
103
156
 
104
157
  ``` ruby
105
158
  class Page
106
- include Virtus
159
+ include Virtus.model
107
160
 
108
161
  attribute :title, String
109
162
 
@@ -129,19 +182,24 @@ page.slug # => 'virtus-readme'
129
182
  page.views # => 0
130
183
  page.published # => false
131
184
  page.editor_title # => "UNPUBLISHED: Virtus README"
185
+
186
+ page.views = 10
187
+ page.views # => 10
188
+ page.reset_attribute(:views) # => 0
189
+ page.views # => 0
132
190
  ```
133
191
 
134
192
  ### Embedded Value
135
193
 
136
194
  ``` ruby
137
195
  class City
138
- include Virtus
196
+ include Virtus.model
139
197
 
140
198
  attribute :name, String
141
199
  end
142
200
 
143
201
  class Address
144
- include Virtus
202
+ include Virtus.model
145
203
 
146
204
  attribute :street, String
147
205
  attribute :zipcode, String
@@ -149,7 +207,7 @@ class Address
149
207
  end
150
208
 
151
209
  class User
152
- include Virtus
210
+ include Virtus.model
153
211
 
154
212
  attribute :name, String
155
213
  attribute :address, Address
@@ -167,7 +225,7 @@ user.address.city.name # => "NYC"
167
225
  ``` ruby
168
226
  # Support "primitive" classes
169
227
  class Book
170
- include Virtus
228
+ include Virtus.model
171
229
 
172
230
  attribute :page_numbers, Array[Integer]
173
231
  end
@@ -177,7 +235,7 @@ book.page_numbers # => [1, 2, 3]
177
235
 
178
236
  # Support EmbeddedValues, too!
179
237
  class Address
180
- include Virtus
238
+ include Virtus.model
181
239
 
182
240
  attribute :address, String
183
241
  attribute :locality, String
@@ -186,13 +244,13 @@ class Address
186
244
  end
187
245
 
188
246
  class PhoneNumber
189
- include Virtus
247
+ include Virtus.model
190
248
 
191
249
  attribute :number, String
192
250
  end
193
251
 
194
252
  class User
195
- include Virtus
253
+ include Virtus.model
196
254
 
197
255
  attribute :phone_numbers, Array[PhoneNumber]
198
256
  attribute :addresses, Set[Address]
@@ -214,7 +272,7 @@ user.addresses # => #<Set: {#<Address:0x007fdb2d3be448 @address="1234 Any St.",
214
272
 
215
273
  ``` ruby
216
274
  class Package
217
- include Virtus
275
+ include Virtus.model
218
276
 
219
277
  attribute :dimensions, Hash[Symbol => Float]
220
278
  end
@@ -232,13 +290,13 @@ Here's an example:
232
290
 
233
291
  ``` ruby
234
292
  class Book
235
- include Virtus
293
+ include Virtus.model
236
294
 
237
295
  attribute :title, String
238
296
  end
239
297
 
240
298
  class Library
241
- include Virtus
299
+ include Virtus.model
242
300
 
243
301
  attribute :books, Array[Book]
244
302
  end
@@ -257,7 +315,7 @@ mutation methods that perform coercions. For example:
257
315
 
258
316
  ``` ruby
259
317
  class Book
260
- include Virtus
318
+ include Virtus.model
261
319
 
262
320
  attribute :title, String
263
321
  end
@@ -273,7 +331,7 @@ class BookCollection < Array
273
331
  end
274
332
 
275
333
  class Library
276
- include Virtus
334
+ include Virtus.model
277
335
 
278
336
  attribute :books, BookCollection[Book]
279
337
  end
@@ -286,17 +344,21 @@ library.books << { :title => 'Another Introduction to Virtus' }
286
344
 
287
345
  ``` ruby
288
346
  class GeoLocation
289
- include Virtus::ValueObject
347
+ include Virtus.value_object
290
348
 
291
- attribute :latitude, Float
292
- attribute :longitude, Float
349
+ values do
350
+ attribute :latitude, Float
351
+ attribute :longitude, Float
352
+ end
293
353
  end
294
354
 
295
355
  class Venue
296
- include Virtus
356
+ include Virtus.value_object
297
357
 
298
- attribute :name, String
299
- attribute :location, GeoLocation
358
+ values do
359
+ attribute :name, String
360
+ attribute :location, GeoLocation
361
+ end
300
362
  end
301
363
 
302
364
  venue = Venue.new(
@@ -315,75 +377,151 @@ venue_other = Venue.new(
315
377
  venue.location === venue_other.location # => true
316
378
  ```
317
379
 
318
- ### Adding Coercions
380
+ ### Custom Coercions
381
+
382
+ ``` ruby
383
+ require 'json'
384
+
385
+ class Json < Virtus::Attribute
386
+ def coerce(value)
387
+ value.is_a?(::Hash) ? value : JSON.parse(value)
388
+ end
389
+ end
390
+
391
+ class User
392
+ include Virtus.model
393
+
394
+ attribute :info, Json
395
+ end
396
+
397
+ user = User.new
398
+ user.info = '{"email":"john@domain.com"}' # => {"email"=>"john@domain.com"}
399
+ user.info.class # => Hash
400
+
401
+ # With a custom attribute encapsulating coercion-specific configuration
402
+ class NoisyString < Virtus::Attribute
403
+ def coerce(value)
404
+ coercer[value.class].to_string.upcase
405
+ end
406
+ end
407
+
408
+ class User
409
+ include Virtus.model
410
+
411
+ attribute :scream, NoisyString
412
+ end
319
413
 
320
- Virtus comes with a builtin coercion library.
321
- It's super easy to add your own coercion classes.
322
- Take a look:
414
+ user = User.new(:scream => 'hello world!')
415
+ user.scream # => "HELLO WORLD!"
416
+ ```
417
+
418
+ ### Private Attributes
323
419
 
324
420
  ``` ruby
325
- require 'digest/md5'
326
-
327
- # Our new attribute type
328
- class MD5 < Virtus::Attribute::Object
329
- primitive String
330
- coercion_method :to_md5
331
- end
332
-
333
- # Defining the Coercion method
334
- module Virtus
335
- class Coercion
336
- class String < Virtus::Coercion::Object
337
- def self.to_md5(value)
338
- Digest::MD5.hexdigest value
339
- end
340
- end
421
+ class User
422
+ include Virtus.model
423
+
424
+ attribute :unique_id, String, :writer => :private
425
+
426
+ def set_unique_id(id)
427
+ self.unique_id = id
341
428
  end
342
429
  end
343
430
 
344
- # And now the user!
431
+ user = User.new(:unique_id => '1234-1234')
432
+ user.unique_id # => nil
433
+
434
+ user.unique_id = '1234-1234' # => NoMethodError: private method `unique_id='
435
+
436
+ user.set_unique_id('1234-1234')
437
+ user.unique_id # => '1234-1234'
438
+ ```
439
+
440
+ Coercions
441
+ ---------
442
+
443
+ Virtus uses [Coercible](https://github.com/solnic/coercible) for coercions. This
444
+ feature is turned on by default. You can turn it off for all attributes like that:
445
+
446
+ ```ruby
447
+ # Turn coercions off globally
448
+ Virtus.coerce(false)
449
+
450
+ # ...or you can turn it off for a single attribute
345
451
  class User
346
- include Virtus
452
+ include Virtus.model
347
453
 
348
- attribute :name, String
349
- attribute :password, MD5
454
+ attribute :name, String, :coerce => false
455
+ end
456
+ ```
457
+
458
+ You can configure coercers too:
459
+
460
+ ```ruby
461
+ Virtus.coercer do |config|
462
+ config.string.boolean_map = { 'yup' => true, 'nope' => false }
350
463
  end
351
464
 
352
- user = User.new(:name => 'Piotr', :password => 'foobar')
353
- user.name # => 'Piotr'
354
- user.password # => '3858f62230ac3c915f300c664312c63f'
465
+ # Virtus.coercer instance is used by default for all attributes.
466
+ # You *can* override it for a single attribute if you want:
467
+
468
+ my_cool_coercer = Coercible::Coercer.new do |config|
469
+ # some customization
470
+ end
471
+
472
+ class User
473
+ include Virtus.model
474
+
475
+ attribute :name, String, :coercer => my_cool_coercer
476
+ end
355
477
  ```
356
478
 
357
- ### Custom Attributes
479
+ ## Strict Coercion Mode
480
+
481
+ By default virtus returns input value even when it couldn't coerce it to expected type.
482
+ If you want to catch such cases in a noisy way you can use the strict mode in which
483
+ virtus raises an exception when it failed to coerce an input value.
358
484
 
359
485
  ``` ruby
360
- require 'json'
486
+ class User
487
+ include Virtus.model(:strict => true)
361
488
 
362
- module MyApp
489
+ attribute :admin, Boolean
490
+ end
363
491
 
364
- # Defining the custom attribute(s)
365
- module Attributes
366
- class JSON < Virtus::Attribute::Object
367
- primitive Hash
492
+ # this will raise an error
493
+ User.new :admin => "can't really say if true or false"
494
+ ```
368
495
 
369
- def coerce(value)
370
- ::JSON.parse value
371
- end
372
- end
373
- end
496
+ ## Building modules with custom configuration
374
497
 
375
- class User
376
- include Virtus
498
+ You can also build Virtus modules that contain their own configuration.
377
499
 
378
- attribute :info, Attributes::JSON
379
- end
500
+ ```ruby
501
+ YupNopeBooleans = Virtus.model { |mod|
502
+ mod.coerce = true
503
+ mod.string.boolean_map = { 'yup' => true, 'nope' => false }
504
+ }
505
+
506
+ class User
507
+ include YupNopeBooleans
508
+
509
+ attribute :name, String
510
+ attribute :admin, Boolean
380
511
  end
381
512
 
382
- user = MyApp::User.new
383
- user.info = '{"email":"john@domain.com"}' # => {"email"=>"john@domain.com"}
384
- user.info.class # => Hash
513
+ # Or just include the module straight away ...
514
+ class User
515
+ include Virtus.model(:coerce => false)
516
+
517
+ attribute :name, String
518
+ attribute :admin, Boolean
519
+ end
385
520
  ```
386
521
 
522
+ Please check out [Coercible README](https://github.com/solnic/coercible/blob/master/README.md)
523
+ for more information.
524
+
387
525
  Credits
388
526
  -------
389
527
 
@@ -409,7 +547,7 @@ Contributing
409
547
  License
410
548
  -------
411
549
 
412
- Copyright (c) 2011-2012 Piotr Solnica
550
+ Copyright (c) 2011-2013 Piotr Solnica
413
551
 
414
552
  Permission is hereby granted, free of charge, to any person obtaining
415
553
  a copy of this software and associated documentation files (the