aequitas 0.0.1

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 (216) hide show
  1. data/.gitignore +4 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +6 -0
  4. data/LICENSE +21 -0
  5. data/README.rdoc +125 -0
  6. data/Rakefile +25 -0
  7. data/VERSION +1 -0
  8. data/aequitas.gemspec +20 -0
  9. data/lib/aequitas.rb +80 -0
  10. data/lib/aequitas/class_methods.rb +26 -0
  11. data/lib/aequitas/context.rb +53 -0
  12. data/lib/aequitas/contextual_rule_set.rb +221 -0
  13. data/lib/aequitas/exceptions.rb +10 -0
  14. data/lib/aequitas/macros.rb +466 -0
  15. data/lib/aequitas/message_transformer.rb +127 -0
  16. data/lib/aequitas/rule.rb +153 -0
  17. data/lib/aequitas/rule/absence.rb +14 -0
  18. data/lib/aequitas/rule/absence/blank.rb +21 -0
  19. data/lib/aequitas/rule/absence/nil.rb +21 -0
  20. data/lib/aequitas/rule/acceptance.rb +36 -0
  21. data/lib/aequitas/rule/block.rb +33 -0
  22. data/lib/aequitas/rule/confirmation.rb +41 -0
  23. data/lib/aequitas/rule/format.rb +81 -0
  24. data/lib/aequitas/rule/format/proc.rb +28 -0
  25. data/lib/aequitas/rule/format/regexp.rb +44 -0
  26. data/lib/aequitas/rule/formats/email.rb +52 -0
  27. data/lib/aequitas/rule/formats/url.rb +14 -0
  28. data/lib/aequitas/rule/guard.rb +51 -0
  29. data/lib/aequitas/rule/length.rb +87 -0
  30. data/lib/aequitas/rule/length/equal.rb +46 -0
  31. data/lib/aequitas/rule/length/maximum.rb +46 -0
  32. data/lib/aequitas/rule/length/minimum.rb +46 -0
  33. data/lib/aequitas/rule/length/range.rb +46 -0
  34. data/lib/aequitas/rule/method.rb +31 -0
  35. data/lib/aequitas/rule/numericalness.rb +85 -0
  36. data/lib/aequitas/rule/numericalness/equal.rb +30 -0
  37. data/lib/aequitas/rule/numericalness/greater_than.rb +30 -0
  38. data/lib/aequitas/rule/numericalness/greater_than_or_equal.rb +30 -0
  39. data/lib/aequitas/rule/numericalness/integer.rb +37 -0
  40. data/lib/aequitas/rule/numericalness/less_than.rb +30 -0
  41. data/lib/aequitas/rule/numericalness/less_than_or_equal.rb +30 -0
  42. data/lib/aequitas/rule/numericalness/non_integer.rb +64 -0
  43. data/lib/aequitas/rule/numericalness/not_equal.rb +30 -0
  44. data/lib/aequitas/rule/presence.rb +14 -0
  45. data/lib/aequitas/rule/presence/not_blank.rb +21 -0
  46. data/lib/aequitas/rule/presence/not_nil.rb +21 -0
  47. data/lib/aequitas/rule/primitive_type.rb +28 -0
  48. data/lib/aequitas/rule/skip_condition.rb +104 -0
  49. data/lib/aequitas/rule/within.rb +28 -0
  50. data/lib/aequitas/rule/within/range.rb +53 -0
  51. data/lib/aequitas/rule/within/range/bounded.rb +25 -0
  52. data/lib/aequitas/rule/within/range/unbounded_begin.rb +25 -0
  53. data/lib/aequitas/rule/within/range/unbounded_end.rb +25 -0
  54. data/lib/aequitas/rule/within/set.rb +39 -0
  55. data/lib/aequitas/rule_set.rb +80 -0
  56. data/lib/aequitas/support/blank.rb +22 -0
  57. data/lib/aequitas/support/equalizable.rb +113 -0
  58. data/lib/aequitas/support/ordered_hash.rb +438 -0
  59. data/lib/aequitas/version.rb +5 -0
  60. data/lib/aequitas/violation.rb +116 -0
  61. data/lib/aequitas/violation_set.rb +123 -0
  62. data/lib/aequitas/virtus.rb +29 -0
  63. data/lib/aequitas/virtus/inline_attribute_rule_extractor.rb +41 -0
  64. data/lib/aequitas/virtus/inline_attribute_rule_extractor/boolean.rb +17 -0
  65. data/lib/aequitas/virtus/inline_attribute_rule_extractor/object.rb +25 -0
  66. data/lib/aequitas/virtus/inline_attribute_rule_extractor/string.rb +27 -0
  67. data/spec/integration/aequitas/macros/validates_absence_of_spec.rb +19 -0
  68. data/spec/integration/aequitas/macros/validates_acceptance_of_spec.rb +19 -0
  69. data/spec/integration/aequitas/macros/validates_confirmation_of_spec.rb +25 -0
  70. data/spec/integration/aequitas/macros/validates_format_of_spec.rb +87 -0
  71. data/spec/integration/aequitas/macros/validates_length_of.rb +77 -0
  72. data/spec/integration/aequitas/macros/validates_numericalness_of_spec.rb +221 -0
  73. data/spec/integration/aequitas/macros/validates_presence_of_spec.rb +19 -0
  74. data/spec/integration/aequitas/macros/validates_with_block.rb +23 -0
  75. data/spec/integration/aequitas/macros/validates_with_method.rb +19 -0
  76. data/spec/integration/aequitas/macros/validates_within.rb +87 -0
  77. data/spec/integration/shared/macros/integration_spec.rb +67 -0
  78. data/spec/integration/virtus/boolean/presence_spec.rb +49 -0
  79. data/spec/integration/virtus/string/format/email_address_spec.rb +55 -0
  80. data/spec/integration/virtus/string/format/regexp_spec.rb +55 -0
  81. data/spec/integration/virtus/string/format/url_spec.rb +55 -0
  82. data/spec/integration/virtus/string/length/equal_spec.rb +49 -0
  83. data/spec/integration/virtus/string/length/range_spec.rb +49 -0
  84. data/spec/integration/virtus/string/presence_spec.rb +49 -0
  85. data/spec/rcov.opts +6 -0
  86. data/spec/spec_helper.rb +5 -0
  87. data/spec/suite.rb +5 -0
  88. data/spec/unit/aequitas/rule/absence/blank_spec.rb +45 -0
  89. data/spec/unit/aequitas/rule/acceptance_spec.rb +71 -0
  90. data/spec/unit/aequitas/rule/confirmation_spec.rb +80 -0
  91. data/spec/unit/aequitas/rule/guard_spec.rb +120 -0
  92. data/spec/unit/aequitas/rule/skip_condition_spec.rb +170 -0
  93. data/spec/unit/aequitas/rule_spec.rb +40 -0
  94. data/spec/unit/aequitas/support/blank_spec.rb +83 -0
  95. data/spec/unit/aequitas/support/equalizable/equalizer_spec.rb +21 -0
  96. data/spec/unit/aequitas/support/equalizable_spec.rb +67 -0
  97. data/spec/unit/aequitas/violation_set_spec.rb +154 -0
  98. data/spec_legacy/fixtures/barcode.rb +40 -0
  99. data/spec_legacy/fixtures/basketball_court.rb +58 -0
  100. data/spec_legacy/fixtures/basketball_player.rb +34 -0
  101. data/spec_legacy/fixtures/beta_tester_account.rb +33 -0
  102. data/spec_legacy/fixtures/bill_of_landing.rb +47 -0
  103. data/spec_legacy/fixtures/boat_dock.rb +26 -0
  104. data/spec_legacy/fixtures/city.rb +24 -0
  105. data/spec_legacy/fixtures/company.rb +93 -0
  106. data/spec_legacy/fixtures/corporate_world.rb +39 -0
  107. data/spec_legacy/fixtures/country.rb +24 -0
  108. data/spec_legacy/fixtures/ethernet_frame.rb +56 -0
  109. data/spec_legacy/fixtures/event.rb +44 -0
  110. data/spec_legacy/fixtures/g3_concert.rb +57 -0
  111. data/spec_legacy/fixtures/jabberwock.rb +27 -0
  112. data/spec_legacy/fixtures/kayak.rb +28 -0
  113. data/spec_legacy/fixtures/lernean_hydra.rb +39 -0
  114. data/spec_legacy/fixtures/llama_spaceship.rb +15 -0
  115. data/spec_legacy/fixtures/mathematical_function.rb +34 -0
  116. data/spec_legacy/fixtures/memory_object.rb +30 -0
  117. data/spec_legacy/fixtures/mittelschnauzer.rb +39 -0
  118. data/spec_legacy/fixtures/motor_launch.rb +21 -0
  119. data/spec_legacy/fixtures/multibyte.rb +16 -0
  120. data/spec_legacy/fixtures/page.rb +32 -0
  121. data/spec_legacy/fixtures/phone_number.rb +28 -0
  122. data/spec_legacy/fixtures/pirogue.rb +28 -0
  123. data/spec_legacy/fixtures/programming_language.rb +83 -0
  124. data/spec_legacy/fixtures/reservation.rb +38 -0
  125. data/spec_legacy/fixtures/scm_operation.rb +56 -0
  126. data/spec_legacy/fixtures/sms_message.rb +22 -0
  127. data/spec_legacy/fixtures/udp_packet.rb +49 -0
  128. data/spec_legacy/integration/absent_field_validator/absent_field_validator_spec.rb +90 -0
  129. data/spec_legacy/integration/absent_field_validator/spec_helper.rb +7 -0
  130. data/spec_legacy/integration/acceptance_validator/acceptance_validator_spec.rb +196 -0
  131. data/spec_legacy/integration/acceptance_validator/spec_helper.rb +7 -0
  132. data/spec_legacy/integration/automatic_validation/custom_messages_for_inferred_validation_spec.rb +57 -0
  133. data/spec_legacy/integration/automatic_validation/disabling_inferred_validation_spec.rb +49 -0
  134. data/spec_legacy/integration/automatic_validation/inferred_boolean_properties_validation_spec.rb +100 -0
  135. data/spec_legacy/integration/automatic_validation/inferred_float_property_validation_spec.rb +45 -0
  136. data/spec_legacy/integration/automatic_validation/inferred_format_validation_spec.rb +35 -0
  137. data/spec_legacy/integration/automatic_validation/inferred_integer_properties_validation_spec.rb +70 -0
  138. data/spec_legacy/integration/automatic_validation/inferred_length_validation_spec.rb +142 -0
  139. data/spec_legacy/integration/automatic_validation/inferred_presence_validation_spec.rb +45 -0
  140. data/spec_legacy/integration/automatic_validation/inferred_primitive_validation_spec.rb +22 -0
  141. data/spec_legacy/integration/automatic_validation/inferred_uniqueness_validation_spec.rb +48 -0
  142. data/spec_legacy/integration/automatic_validation/inferred_within_validation_spec.rb +35 -0
  143. data/spec_legacy/integration/automatic_validation/spec_helper.rb +57 -0
  144. data/spec_legacy/integration/block_validator/block_validator_spec.rb +32 -0
  145. data/spec_legacy/integration/block_validator/spec_helper.rb +5 -0
  146. data/spec_legacy/integration/conditional_validation/if_condition_spec.rb +63 -0
  147. data/spec_legacy/integration/conditional_validation/spec_helper.rb +5 -0
  148. data/spec_legacy/integration/confirmation_validator/confirmation_validator_spec.rb +76 -0
  149. data/spec_legacy/integration/confirmation_validator/spec_helper.rb +5 -0
  150. data/spec_legacy/integration/datamapper_models/association_validation_spec.rb +29 -0
  151. data/spec_legacy/integration/datamapper_models/inheritance_spec.rb +82 -0
  152. data/spec_legacy/integration/dirty_attributes/dirty_attributes_spec.rb +13 -0
  153. data/spec_legacy/integration/duplicated_validations/duplicated_validations_spec.rb +24 -0
  154. data/spec_legacy/integration/duplicated_validations/spec_helper.rb +5 -0
  155. data/spec_legacy/integration/format_validator/email_format_validator_spec.rb +139 -0
  156. data/spec_legacy/integration/format_validator/format_validator_spec.rb +64 -0
  157. data/spec_legacy/integration/format_validator/regexp_validator_spec.rb +33 -0
  158. data/spec_legacy/integration/format_validator/spec_helper.rb +5 -0
  159. data/spec_legacy/integration/format_validator/url_format_validator_spec.rb +93 -0
  160. data/spec_legacy/integration/length_validator/default_value_spec.rb +14 -0
  161. data/spec_legacy/integration/length_validator/equality_spec.rb +87 -0
  162. data/spec_legacy/integration/length_validator/error_message_spec.rb +22 -0
  163. data/spec_legacy/integration/length_validator/maximum_spec.rb +49 -0
  164. data/spec_legacy/integration/length_validator/minimum_spec.rb +54 -0
  165. data/spec_legacy/integration/length_validator/range_spec.rb +87 -0
  166. data/spec_legacy/integration/length_validator/spec_helper.rb +7 -0
  167. data/spec_legacy/integration/method_validator/method_validator_spec.rb +242 -0
  168. data/spec_legacy/integration/method_validator/spec_helper.rb +5 -0
  169. data/spec_legacy/integration/numeric_validator/equality_with_float_type_spec.rb +65 -0
  170. data/spec_legacy/integration/numeric_validator/equality_with_integer_type_spec.rb +41 -0
  171. data/spec_legacy/integration/numeric_validator/float_type_spec.rb +90 -0
  172. data/spec_legacy/integration/numeric_validator/gt_with_float_type_spec.rb +37 -0
  173. data/spec_legacy/integration/numeric_validator/gte_with_float_type_spec.rb +37 -0
  174. data/spec_legacy/integration/numeric_validator/integer_only_true_spec.rb +91 -0
  175. data/spec_legacy/integration/numeric_validator/integer_type_spec.rb +86 -0
  176. data/spec_legacy/integration/numeric_validator/lt_with_float_type_spec.rb +37 -0
  177. data/spec_legacy/integration/numeric_validator/lte_with_float_type_spec.rb +37 -0
  178. data/spec_legacy/integration/numeric_validator/spec_helper.rb +5 -0
  179. data/spec_legacy/integration/primitive_validator/primitive_validator_spec.rb +92 -0
  180. data/spec_legacy/integration/primitive_validator/spec_helper.rb +5 -0
  181. data/spec_legacy/integration/pure_ruby_objects/plain_old_ruby_object_validation_spec.rb +118 -0
  182. data/spec_legacy/integration/required_field_validator/association_spec.rb +69 -0
  183. data/spec_legacy/integration/required_field_validator/boolean_type_value_spec.rb +164 -0
  184. data/spec_legacy/integration/required_field_validator/date_type_value_spec.rb +127 -0
  185. data/spec_legacy/integration/required_field_validator/datetime_type_value_spec.rb +127 -0
  186. data/spec_legacy/integration/required_field_validator/float_type_value_spec.rb +131 -0
  187. data/spec_legacy/integration/required_field_validator/integer_type_value_spec.rb +99 -0
  188. data/spec_legacy/integration/required_field_validator/plain_old_ruby_object_spec.rb +35 -0
  189. data/spec_legacy/integration/required_field_validator/shared_examples.rb +26 -0
  190. data/spec_legacy/integration/required_field_validator/spec_helper.rb +7 -0
  191. data/spec_legacy/integration/required_field_validator/string_type_value_spec.rb +167 -0
  192. data/spec_legacy/integration/required_field_validator/text_type_value_spec.rb +49 -0
  193. data/spec_legacy/integration/shared/default_validation_context.rb +13 -0
  194. data/spec_legacy/integration/shared/valid_and_invalid_model.rb +35 -0
  195. data/spec_legacy/integration/uniqueness_validator/spec_helper.rb +5 -0
  196. data/spec_legacy/integration/uniqueness_validator/uniqueness_validator_spec.rb +116 -0
  197. data/spec_legacy/integration/within_validator/spec_helper.rb +5 -0
  198. data/spec_legacy/integration/within_validator/within_validator_spec.rb +168 -0
  199. data/spec_legacy/public/resource_spec.rb +105 -0
  200. data/spec_legacy/spec.opts +4 -0
  201. data/spec_legacy/spec_helper.rb +29 -0
  202. data/spec_legacy/unit/contextual_validators/emptiness_spec.rb +50 -0
  203. data/spec_legacy/unit/contextual_validators/execution_spec.rb +48 -0
  204. data/spec_legacy/unit/contextual_validators/spec_helper.rb +37 -0
  205. data/spec_legacy/unit/generic_validator/equality_operator_spec.rb +26 -0
  206. data/spec_legacy/unit/generic_validator/optional_spec.rb +54 -0
  207. data/spec_legacy/unit/validators/within_validator_spec.rb +23 -0
  208. data/spec_legacy/unit/violation_set/adding_spec.rb +54 -0
  209. data/spec_legacy/unit/violation_set/emptiness_spec.rb +38 -0
  210. data/spec_legacy/unit/violation_set/enumerable_spec.rb +32 -0
  211. data/spec_legacy/unit/violation_set/reading_spec.rb +35 -0
  212. data/spec_legacy/unit/violation_set/respond_to_spec.rb +15 -0
  213. data/tasks/spec.rake +38 -0
  214. data/tasks/yard.rake +9 -0
  215. data/tasks/yardstick.rake +19 -0
  216. metadata +302 -0
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/numericalness'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Numericalness
8
+ class NotEqual < Rule
9
+
10
+ include Numericalness
11
+
12
+ def valid_numericalness?(value)
13
+ value != expected
14
+ rescue ArgumentError
15
+ # TODO: figure out better solution for: can't compare String with Integer
16
+ true
17
+ end
18
+
19
+ def violation_type(resource)
20
+ :not_equal_to
21
+ end
22
+
23
+ def violation_data(resource)
24
+ [ [ :not_expected, expected ] ]
25
+ end
26
+
27
+ end # class NotEqual
28
+ end # module Numericalness
29
+ end # class Rule
30
+ end # module Aequitas
@@ -0,0 +1,14 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ class Presence < Rule
8
+
9
+ end # class Presence
10
+ end # class Rule
11
+ end # module Aequitas
12
+
13
+ require 'aequitas/rule/presence/not_blank'
14
+ require 'aequitas/rule/presence/not_nil'
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/presence'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ class Presence
8
+ class NotBlank < Presence
9
+
10
+ def valid?(resource)
11
+ !Aequitas.blank?(attribute_value(resource))
12
+ end
13
+
14
+ def violation_type(resource)
15
+ :blank
16
+ end
17
+
18
+ end # class NonNil
19
+ end # class Presence
20
+ end # class Rule
21
+ end # module Aequitas
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/presence'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ class Presence
8
+ class NotNil < Presence
9
+
10
+ def valid?(resource)
11
+ !attribute_value(resource).nil?
12
+ end
13
+
14
+ def violation_type(resource)
15
+ :nil
16
+ end
17
+
18
+ end # class NonNil
19
+ end # class Presence
20
+ end # class Rule
21
+ end # module Aequitas
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ class PrimitiveType < Rule
8
+
9
+ def valid?(resource)
10
+ property = get_resource_property(resource, attribute_name)
11
+ value = attribute_value(resource)
12
+
13
+ value.nil? || property.value_dumped?(value)
14
+ end
15
+
16
+ def violation_type(resource)
17
+ :primitive
18
+ end
19
+
20
+ def violation_data(resource)
21
+ property = get_resource_property(resource, attribute_name)
22
+
23
+ [ [ :primitive, property.load_as ] ]
24
+ end
25
+
26
+ end # class PrimitiveType
27
+ end # class Rule
28
+ end # module Aequitas
@@ -0,0 +1,104 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/support/blank'
4
+ require 'aequitas/support/equalizable'
5
+
6
+ module Aequitas
7
+ class Rule
8
+ class SkipCondition
9
+ extend Equalizable
10
+
11
+ equalize_on :allow_nil, :allow_blank
12
+
13
+ attr_reader :allow_nil
14
+ attr_reader :allow_blank
15
+
16
+ def initialize(options = {})
17
+ @allow_nil = !!options[:allow_nil] if options.include?(:allow_nil)
18
+ @allow_blank = !!options[:allow_blank] if options.include?(:allow_blank)
19
+ end
20
+
21
+ # Test a value to determine if it should be skipped,
22
+ # according to the receiver's configuration
23
+ #
24
+ # @param [#nil?] value
25
+ # the value to be tested
26
+ #
27
+ # @return [Boolean]
28
+ def skip?(value)
29
+ if value.nil?
30
+ @allow_nil.nil? ? allow_blank? : allow_nil?
31
+ elsif Aequitas.blank?(value)
32
+ allow_blank?
33
+ else
34
+ false
35
+ end
36
+ end
37
+
38
+ # Inquire whether the receiver is configured to allow nil values
39
+ #
40
+ # @return [Boolean]
41
+ def allow_nil?
42
+ @allow_nil.nil? ? false : @allow_nil
43
+ end
44
+
45
+ # Inquire whether the receiver is configured to allow blank values
46
+ #
47
+ # @return [Boolean]
48
+ def allow_blank?
49
+ @allow_blank.nil? ? false : @allow_blank
50
+ end
51
+
52
+ # Set the receiver to allow nil values
53
+ #
54
+ # @return [self]
55
+ def allow_nil!
56
+ @allow_nil = true
57
+ self
58
+ end
59
+
60
+ # Set the receiver to allow blank values
61
+ #
62
+ # @return [self]
63
+ def allow_blank!
64
+ @allow_blank = true
65
+ self
66
+ end
67
+
68
+ # Set the receiver to reject nil values
69
+ #
70
+ # @return [self]
71
+ def reject_nil!
72
+ @allow_nil = false
73
+ self
74
+ end
75
+
76
+ # Set the receiver to reject blank values
77
+ #
78
+ # @return [self]
79
+ def reject_blank!
80
+ @allow_blank = false
81
+ self
82
+ end
83
+
84
+ # Set the receiver to allow nil values
85
+ # if a value has not already been set
86
+ #
87
+ # @return [self]
88
+ def default_to_allowing_nil!
89
+ allow_nil! if allow_nil.nil?
90
+ self
91
+ end
92
+
93
+ # Set the receiver to allow blank values
94
+ # if a value has not already been set
95
+ #
96
+ # @return [self]
97
+ def default_to_allowing_blank!
98
+ allow_blank! if allow_blank.nil?
99
+ self
100
+ end
101
+
102
+ end # class SkipCondition
103
+ end # class Rule
104
+ end # module Aequitas
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Within
8
+
9
+ # TODO: DRY this up (also implemented in Rule)
10
+ def self.rules_for(attribute_name, options)
11
+ Array(new(attribute_name, options))
12
+ end
13
+
14
+ # TODO: move options normalization into the validator macros
15
+ def self.new(attribute_name, options)
16
+ if options.fetch(:set).is_a?(::Range)
17
+ Within::Range.new(attribute_name, options)
18
+ else
19
+ Within::Set.new(attribute_name, options)
20
+ end
21
+ end
22
+
23
+ end # module Within
24
+ end # class Rule
25
+ end # module Aequitas
26
+
27
+ require 'aequitas/rule/within/range'
28
+ require 'aequitas/rule/within/set'
@@ -0,0 +1,53 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/within'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Within
8
+ module Range
9
+
10
+ Infinity = 1.0 / 0
11
+
12
+ include Within
13
+
14
+ attr_reader :range
15
+
16
+ def self.rules_for(attribute_name, options)
17
+ Array(new(attribute_name, options))
18
+ end
19
+
20
+ def self.new(attribute_name, options)
21
+ super if Within::Range != self
22
+
23
+ range = options.fetch(:range) { options.fetch(:set) }
24
+
25
+ if range.first != -Infinity && range.last != Infinity
26
+ Bounded.new(attribute_name, options)
27
+ elsif range.first == -Infinity
28
+ UnboundedBegin.new(attribute_name, options)
29
+ elsif range.last == Infinity
30
+ UnboundedEnd.new(attribute_name, options)
31
+ end
32
+ end
33
+
34
+ def initialize(attribute_name, options={})
35
+ super
36
+
37
+ @range = options.fetch(:range) { options.fetch(:set) }
38
+ end
39
+
40
+ def valid?(resource)
41
+ value = attribute_value(resource)
42
+
43
+ skip?(value) || range.include?(value)
44
+ end
45
+
46
+ end # module Range
47
+ end # module Within
48
+ end # class Rule
49
+ end # module Aequitas
50
+
51
+ require 'aequitas/rule/within/range/bounded'
52
+ require 'aequitas/rule/within/range/unbounded_begin'
53
+ require 'aequitas/rule/within/range/unbounded_end'
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/within/range'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Within
8
+ module Range
9
+ class Bounded < Rule
10
+
11
+ include Range
12
+
13
+ def violation_type(resource)
14
+ :value_between
15
+ end
16
+
17
+ def violation_data(resource)
18
+ [ [ :minimum, range.begin ], [ :maximum, range.end ] ]
19
+ end
20
+
21
+ end # class Bounded
22
+ end # module Range
23
+ end # module Within
24
+ end # class Rule
25
+ end # module Aequitas
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/within/range'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Within
8
+ module Range
9
+ class UnboundedBegin < Rule
10
+
11
+ include Range
12
+
13
+ def violation_type(resource)
14
+ :less_than_or_equal_to
15
+ end
16
+
17
+ def violation_data(resource)
18
+ [ [ :maximum, range.max ] ]
19
+ end
20
+
21
+ end # class UnboundedBegin
22
+ end # module Range
23
+ end # module Within
24
+ end # class Rule
25
+ end # module Aequitas
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/within/range'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Within
8
+ module Range
9
+ class UnboundedEnd < Rule
10
+
11
+ include Range
12
+
13
+ def violation_type(resource)
14
+ :greater_than_or_equal_to
15
+ end
16
+
17
+ def violation_data(resource)
18
+ [ [ :minimum, range.begin ] ]
19
+ end
20
+
21
+ end # class UnboundedBegin
22
+ end # module Range
23
+ end # module Within
24
+ end # class Rule
25
+ end # module Aequitas
@@ -0,0 +1,39 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/within'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Within
8
+ class Set < Rule
9
+
10
+ equalize_on *(superclass.equalizer.keys + [:set])
11
+
12
+ include Within
13
+
14
+ attr_reader :set
15
+
16
+ def initialize(attribute_name, options={})
17
+ super
18
+
19
+ @set = options.fetch(:set, [])
20
+ end
21
+
22
+ def valid?(resource)
23
+ value = attribute_value(resource)
24
+
25
+ skip?(value) || set.include?(value)
26
+ end
27
+
28
+ def violation_type(resource)
29
+ :inclusion
30
+ end
31
+
32
+ def violation_data(resource)
33
+ [ [ :set, set.to_a.join(', ') ] ]
34
+ end
35
+
36
+ end # class Set
37
+ end # module Within
38
+ end # class Rule
39
+ end # module Aequitas
@@ -0,0 +1,80 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'forwardable'
4
+ require 'set'
5
+ require 'aequitas/support/equalizable'
6
+
7
+ module Aequitas
8
+ class RuleSet
9
+ # Holds a collection of Rule instances to be run against
10
+ # Resources to validate the Resources in a specific context
11
+
12
+ extend Equalizable
13
+ extend Forwardable
14
+ include Enumerable
15
+
16
+ equalize_on :rules
17
+
18
+ # @api public
19
+ def_delegators :attribute_index, :[], :fetch
20
+
21
+ # @api public
22
+ def_delegators :rules, :each, :empty?
23
+
24
+ # @api public
25
+ attr_reader :rules
26
+
27
+ # @api private
28
+ attr_reader :attribute_index
29
+
30
+ def initialize
31
+ @rules = Set.new
32
+ @attribute_index = Hash.new { |h,k| h[k] = [] }
33
+ end
34
+
35
+ def <<(rule)
36
+ unless rules.include?(rule)
37
+ rules << rule
38
+ attribute_index[rule.attribute_name] << rule
39
+ end
40
+
41
+ self
42
+ end
43
+
44
+ # Execute all rules in this context against the resource.
45
+ #
46
+ # @param [Object] resource
47
+ # the resource to be validated
48
+ #
49
+ # @return [Array(Violation)]
50
+ # an Array of Violations
51
+ def validate(resource)
52
+ rules = rules_for_resource(resource)
53
+ rules.map { |rule| rule.validate(resource) }.compact
54
+ # TODO:
55
+ # violations = rules.map { |rule| rule.validate(resource) }.compact
56
+ # ViolationSet.new(resource).concat(violations)
57
+ end
58
+
59
+ # Assimilate all the rules from another RuleSet into the receiver
60
+ #
61
+ # @param [RuleSet, Array] rules
62
+ # The other RuleSet (or Array) whose rules are to be assimilated
63
+ #
64
+ # @return [self]
65
+ def concat(rules)
66
+ rules.each { |rule| self << rule.dup }
67
+
68
+ self
69
+ end
70
+
71
+ def inspect
72
+ "#<#{ self.class } {#{ rules.map { |e| e.inspect }.join( ', ' ) }}>"
73
+ end
74
+
75
+ def rules_for_resource(resource)
76
+ rules.select { |r| r.execute?(resource) }
77
+ end
78
+
79
+ end # class RuleSet
80
+ end # module Aequitas