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,81 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule'
4
+ require 'aequitas/exceptions'
5
+
6
+ require 'aequitas/rule/formats/email'
7
+ require 'aequitas/rule/formats/url'
8
+
9
+ module Aequitas
10
+ class Rule
11
+ module Format
12
+
13
+ FORMATS = {
14
+ :email_address => Formats::EmailAddress,
15
+ :url => Formats::Url
16
+ }
17
+ # TODO: evaluate re-implementing custom error messages per format type
18
+ # previously these strings were wrapped in lambdas, which were, at one
19
+ # point, invoked with #try_call with the humanized attribute name and value
20
+ FORMAT_MESSAGES = {
21
+ :email_address => '%s is not a valid email address',
22
+ :url => '%s is not a valid URL',
23
+ }
24
+
25
+
26
+ def self.rules_for(attribute_name, options)
27
+ Array(new(attribute_name, options))
28
+ end
29
+
30
+ # @raise [UnknownValidationFormat]
31
+ # if the :as (or :with) option is a Symbol that is not a key in FORMATS,
32
+ # or if the provided format is not a Regexp, Symbol or Proc
33
+ def self.new(attribute_name, options)
34
+ format = options.delete(:as) || options.delete(:with)
35
+
36
+ case format
37
+ when Symbol
38
+ regexp = FORMATS.fetch(format) do
39
+ raise UnknownValidationFormat, "No such predefined format '#{format}'"
40
+ end
41
+ self::Regexp.new(attribute_name, options.merge(:format => regexp, :format_name => format))
42
+ when ::Regexp
43
+ self::Regexp.new(attribute_name, options.merge(:format => format))
44
+ when ::Proc
45
+ self::Proc.new(attribute_name, options.merge(:format => format))
46
+ else
47
+ raise UnknownValidationFormat, "Expected a Regexp, Symbol, or Proc format. Got: #{format.inspect}"
48
+ end
49
+ end
50
+
51
+
52
+ attr_reader :format
53
+
54
+ def initialize(attribute_name, options)
55
+ super
56
+
57
+ @format = options.fetch(:format)
58
+
59
+ skip_condition.default_to_allowing_nil!
60
+ skip_condition.default_to_allowing_blank!
61
+ end
62
+
63
+ def violation_type(resource)
64
+ :invalid
65
+ end
66
+
67
+ # TODO: integrate format into error message key?
68
+ # def error_message_args
69
+ # if format.is_a?(Symbol)
70
+ # [ :"invalid_#{format}", attribute_name ]
71
+ # else
72
+ # [ :invalid, attribute_name ]
73
+ # end
74
+ # end
75
+
76
+ end # class Format
77
+ end # class Rule
78
+ end # module Aequitas
79
+
80
+ require 'aequitas/rule/format/proc'
81
+ require 'aequitas/rule/format/regexp'
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/format'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Format
8
+ class Proc < Rule
9
+
10
+ include Format
11
+
12
+ equalize_on *(superclass.equalizer.keys + [:format])
13
+
14
+
15
+ def valid?(resource)
16
+ value = attribute_value(resource)
17
+ return true if skip?(value)
18
+
19
+ self.format.call(value)
20
+ # rescue ::Encoding::CompatibilityError
21
+ # # This is to work around a bug in jruby - see formats/email.rb
22
+ # false
23
+ end
24
+
25
+ end # class Proc
26
+ end # module Format
27
+ end # class Rule
28
+ end # module Aequitas
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/format'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Format
8
+ class Regexp < Rule
9
+
10
+ include Format
11
+
12
+ equalize_on *(superclass.equalizer.keys + [:format, :format_name])
13
+
14
+ attr_reader :format_name
15
+
16
+ def initialize(attribute_name, options = {})
17
+ super
18
+
19
+ @format_name = options.fetch(:format_name, nil)
20
+ end
21
+
22
+ def valid?(resource)
23
+ value = attribute_value(resource)
24
+ return true if skip?(value)
25
+
26
+ value ? value.to_s =~ self.format : false
27
+ rescue ::Encoding::CompatibilityError
28
+ # This is to work around a bug in jruby - see formats/email.rb
29
+ false
30
+ end
31
+
32
+ # TODO: integrate format into error message key?
33
+ # def error_message_args
34
+ # if format_name.is_a?(Symbol)
35
+ # [ :"invalid_#{format_name}", attribute_name ]
36
+ # else
37
+ # [ :invalid, attribute_name ]
38
+ # end
39
+ # end
40
+
41
+ end # class Regexp
42
+ end # module Format
43
+ end # class Rule
44
+ end # module Aequitas
@@ -0,0 +1,52 @@
1
+ # encoding: UTF-8
2
+
3
+ module Aequitas
4
+ class Rule
5
+ module Formats
6
+
7
+ # Almost RFC2822 (No attribution reference available).
8
+ #
9
+ # This differs in that it does not allow local domains (test@localhost).
10
+ # 99% of the time you do not want to allow these email addresses
11
+ # in a public web application.
12
+ EmailAddress = begin
13
+ if (RUBY_VERSION == '1.9.2' && RUBY_ENGINE == 'jruby' && JRUBY_VERSION <= '1.6.3') || RUBY_VERSION == '1.9.3'
14
+ # There is an obscure bug in jruby 1.6 that prevents matching
15
+ # on unicode properties here. Remove this logic branch once
16
+ # a stable jruby release fixes this.
17
+ #
18
+ # http://jira.codehaus.org/browse/JRUBY-5622
19
+ #
20
+ # There is a similar bug in preview releases of 1.9.3
21
+ #
22
+ # http://redmine.ruby-lang.org/issues/5126
23
+ letter = 'a-zA-Z'
24
+ else
25
+ letter = 'a-zA-Z\p{L}' # Changed from RFC2822 to include unicode chars
26
+ end
27
+ digit = '0-9'
28
+ atext = "[#{letter}#{digit}\!\#\$\%\&\'\*+\/\=\?\^\_\`\{\|\}\~\-]"
29
+ dot_atom_text = "#{atext}+([.]#{atext}*)+"
30
+ dot_atom = dot_atom_text
31
+ no_ws_ctl = '\x01-\x08\x11\x12\x14-\x1f\x7f'
32
+ qtext = "[^#{no_ws_ctl}\\x0d\\x22\\x5c]" # Non-whitespace, non-control character except for \ and "
33
+ text = '[\x01-\x09\x11\x12\x14-\x7f]'
34
+ quoted_pair = "(\\x5c#{text})"
35
+ qcontent = "(?:#{qtext}|#{quoted_pair})"
36
+ quoted_string = "[\"]#{qcontent}+[\"]"
37
+ atom = "#{atext}+"
38
+ word = "(?:#{atom}|#{quoted_string})"
39
+ obs_local_part = "#{word}([.]#{word})*"
40
+ local_part = "(?:#{dot_atom}|#{quoted_string}|#{obs_local_part})"
41
+ dtext = "[#{no_ws_ctl}\\x21-\\x5a\\x5e-\\x7e]"
42
+ dcontent = "(?:#{dtext}|#{quoted_pair})"
43
+ domain_literal = "\\[#{dcontent}+\\]"
44
+ obs_domain = "#{atom}([.]#{atom})+"
45
+ domain = "(?:#{dot_atom}|#{domain_literal}|#{obs_domain})"
46
+ addr_spec = "#{local_part}\@#{domain}"
47
+ pattern = /\A#{addr_spec}\z/u
48
+ end
49
+
50
+ end # module Formats
51
+ end # class Rule
52
+ end # module Aequitas
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ module Aequitas
4
+ class Rule
5
+ module Formats
6
+
7
+ # Regex from http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/
8
+ Url = begin
9
+ /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}((\:[0-9]{1,5})?\/?.*)?$)/ix
10
+ end
11
+
12
+ end # module Formats
13
+ end # class Rule
14
+ end # module Aequitas
@@ -0,0 +1,51 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/support/equalizable'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ class Guard
8
+ extend Equalizable
9
+
10
+ equalize_on :if_test, :unless_test
11
+
12
+ attr_reader :if_test
13
+ attr_reader :unless_test
14
+
15
+ def initialize(options = {})
16
+ @if_test = options.fetch(:if, nil)
17
+ @unless_test = options.fetch(:unless, nil)
18
+ end
19
+
20
+ # Determines if this RuleGuard allows the given resource
21
+ # by evaluating the if_test and unless_test
22
+ #
23
+ # @param [Object] resource
24
+ # The resource that we check against.
25
+ #
26
+ # @return [Boolean]
27
+ # true if allowed, otherwise false.
28
+ #
29
+ # @api private
30
+ def allow?(resource)
31
+ if if_test
32
+ !!evaluate_conditional_clause(resource, if_test)
33
+ elsif unless_test
34
+ !evaluate_conditional_clause(resource, unless_test)
35
+ else
36
+ true
37
+ end
38
+ end
39
+
40
+ # @api private
41
+ def evaluate_conditional_clause(resource, clause)
42
+ if clause.respond_to?(:call)
43
+ clause.call(resource)
44
+ elsif clause.kind_of?(Symbol)
45
+ resource.__send__(clause)
46
+ end
47
+ end
48
+
49
+ end # class Guard
50
+ end # class Rule
51
+ end # module Aequitas
@@ -0,0 +1,87 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Length
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
+ options = options.dup
17
+
18
+ equal = options.values_at(:is, :equals).compact.first
19
+ range = options.values_at(:in, :within).compact.first
20
+ minimum = options.values_at(:min, :minimum).compact.first
21
+ maximum = options.values_at(:max, :maximum).compact.first
22
+
23
+ if minimum && maximum
24
+ range ||= minimum..maximum
25
+ end
26
+
27
+ if equal
28
+ Length::Equal.new(attribute_name, options.merge(:expected => equal))
29
+ elsif range
30
+ Length::Range.new(attribute_name, options.merge(:range => range))
31
+ elsif minimum
32
+ Length::Minimum.new(attribute_name, options.merge(:bound => minimum))
33
+ elsif maximum
34
+ Length::Maximum.new(attribute_name, options.merge(:bound => maximum))
35
+ else
36
+ # raise ArgumentError, "expected one of :is, :equals, :within, :in, :minimum, :min, :maximum, or :max; got #{options.keys.inspect}"
37
+ warn "expected length specification: one of :is, :equals, :in, :within, :min, :minimum, :max, or :maximum; got #{options.keys.inspect}"
38
+ Length::Dummy.new(attribute_name, options)
39
+ end
40
+ end
41
+
42
+ class Dummy < Rule
43
+ include Length
44
+ end
45
+
46
+ def valid?(resource)
47
+ value = attribute_value(resource)
48
+
49
+ skip?(value) || valid_length?(value_length(value.to_s))
50
+ end
51
+
52
+ private
53
+
54
+ def valid_length?(length)
55
+ raise NotImplementedError, "#{self.class}#valid_length? must be implemented"
56
+ end
57
+
58
+ # Return the length in characters
59
+ #
60
+ # @param [#to_str] value
61
+ # the string to get the number of characters for
62
+ #
63
+ # @return [Integer]
64
+ # the number of characters in the string
65
+ #
66
+ # @api private
67
+ def value_length(value)
68
+ value.to_str.length
69
+ end
70
+
71
+ if RUBY_VERSION < '1.9'
72
+ # calculate length of multi-byte-encoded strings
73
+ # as characters rather than bytes
74
+ def value_length(value)
75
+ value.to_str.scan(/./u).size
76
+ end
77
+ end
78
+
79
+ end # module Length
80
+ end # class Rule
81
+ end # module Aequitas
82
+
83
+ # meh, I don't like doing this, but the superclass must be loaded before subclasses
84
+ require 'aequitas/rule/length/equal'
85
+ require 'aequitas/rule/length/range'
86
+ require 'aequitas/rule/length/minimum'
87
+ require 'aequitas/rule/length/maximum'
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/length'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Length
8
+ class Equal < Rule
9
+
10
+ include Length
11
+
12
+ attr_reader :expected
13
+
14
+ def initialize(attribute_name, options)
15
+ super
16
+
17
+ @expected = options.fetch(:expected)
18
+ end
19
+
20
+ def violation_type(resource)
21
+ :wrong_length
22
+ end
23
+
24
+ def violation_data(resource)
25
+ [ [ :expected, expected ] ]
26
+ end
27
+
28
+ private
29
+
30
+ # Validate the value length is equal to the expected length
31
+ #
32
+ # @param [Integer] length
33
+ # the value length
34
+ #
35
+ # @return [String, nil]
36
+ # the error message if invalid, nil if not
37
+ #
38
+ # @api private
39
+ def valid_length?(length)
40
+ expected == length
41
+ end
42
+
43
+ end # class Equal
44
+ end # module Length
45
+ end # class Rule
46
+ end # module Aequitas
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'aequitas/rule/length'
4
+
5
+ module Aequitas
6
+ class Rule
7
+ module Length
8
+ class Maximum < Rule
9
+
10
+ include Length
11
+
12
+ attr_reader :bound
13
+
14
+ def initialize(attribute_name, options)
15
+ super
16
+
17
+ @bound = options.fetch(:bound)
18
+ end
19
+
20
+ def violation_type(resource)
21
+ :too_long
22
+ end
23
+
24
+ def violation_data(resource)
25
+ [ [ :maximum, bound ] ]
26
+ end
27
+
28
+ private
29
+
30
+ # Validate the value length is less than or equal to the bound
31
+ #
32
+ # @param [Integer] length
33
+ # the value length
34
+ #
35
+ # @return [String, NilClass]
36
+ # the error message if invalid, nil if valid
37
+ #
38
+ # @api private
39
+ def valid_length?(length)
40
+ bound >= length
41
+ end
42
+
43
+ end # class Maximum
44
+ end # module Length
45
+ end # class Rule
46
+ end # module Aequitas