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