jchris-couchrest 0.12.6 → 0.16

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 (59) hide show
  1. data/README.md +33 -8
  2. data/Rakefile +1 -1
  3. data/examples/model/example.rb +19 -13
  4. data/lib/couchrest.rb +27 -2
  5. data/lib/couchrest/core/database.rb +113 -41
  6. data/lib/couchrest/core/document.rb +48 -27
  7. data/lib/couchrest/core/response.rb +15 -0
  8. data/lib/couchrest/core/server.rb +47 -10
  9. data/lib/couchrest/mixins.rb +4 -0
  10. data/lib/couchrest/mixins/attachments.rb +31 -0
  11. data/lib/couchrest/mixins/callbacks.rb +442 -0
  12. data/lib/couchrest/mixins/design_doc.rb +63 -0
  13. data/lib/couchrest/mixins/document_queries.rb +48 -0
  14. data/lib/couchrest/mixins/extended_attachments.rb +68 -0
  15. data/lib/couchrest/mixins/extended_document_mixins.rb +6 -0
  16. data/lib/couchrest/mixins/properties.rb +120 -0
  17. data/lib/couchrest/mixins/validation.rb +234 -0
  18. data/lib/couchrest/mixins/views.rb +168 -0
  19. data/lib/couchrest/monkeypatches.rb +75 -0
  20. data/lib/couchrest/more/casted_model.rb +28 -0
  21. data/lib/couchrest/more/extended_document.rb +215 -0
  22. data/lib/couchrest/more/property.rb +40 -0
  23. data/lib/couchrest/support/blank.rb +42 -0
  24. data/lib/couchrest/support/class.rb +175 -0
  25. data/lib/couchrest/validation/auto_validate.rb +163 -0
  26. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  27. data/lib/couchrest/validation/validation_errors.rb +118 -0
  28. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  29. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  30. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  31. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  32. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  33. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  34. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  35. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  36. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  37. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  38. data/spec/couchrest/core/database_spec.rb +183 -67
  39. data/spec/couchrest/core/design_spec.rb +1 -1
  40. data/spec/couchrest/core/document_spec.rb +271 -173
  41. data/spec/couchrest/core/server_spec.rb +35 -0
  42. data/spec/couchrest/helpers/pager_spec.rb +1 -1
  43. data/spec/couchrest/more/casted_model_spec.rb +97 -0
  44. data/spec/couchrest/more/extended_doc_attachment_spec.rb +129 -0
  45. data/spec/couchrest/more/extended_doc_spec.rb +509 -0
  46. data/spec/couchrest/more/extended_doc_view_spec.rb +204 -0
  47. data/spec/couchrest/more/property_spec.rb +129 -0
  48. data/spec/fixtures/more/article.rb +34 -0
  49. data/spec/fixtures/more/card.rb +20 -0
  50. data/spec/fixtures/more/course.rb +14 -0
  51. data/spec/fixtures/more/event.rb +6 -0
  52. data/spec/fixtures/more/invoice.rb +17 -0
  53. data/spec/fixtures/more/person.rb +8 -0
  54. data/spec/fixtures/more/question.rb +6 -0
  55. data/spec/fixtures/more/service.rb +12 -0
  56. data/spec/spec_helper.rb +13 -7
  57. metadata +76 -3
  58. data/lib/couchrest/core/model.rb +0 -613
  59. data/spec/couchrest/core/model_spec.rb +0 -855
@@ -0,0 +1,118 @@
1
+ # Extracted from dm-validations 0.9.10
2
+ #
3
+ # Copyright (c) 2007 Guy van den Berg
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ module CouchRest
25
+ module Validation
26
+
27
+ ##
28
+ #
29
+ # @author Guy van den Berg
30
+ # @since 0.9
31
+ class ValidationErrors
32
+
33
+ include Enumerable
34
+
35
+ @@default_error_messages = {
36
+ :absent => '%s must be absent',
37
+ :inclusion => '%s must be one of [%s]',
38
+ :invalid => '%s has an invalid format',
39
+ :confirmation => '%s does not match the confirmation',
40
+ :accepted => "%s is not accepted",
41
+ :nil => '%s must not be nil',
42
+ :blank => '%s must not be blank',
43
+ :length_between => '%s must be between %s and %s characters long',
44
+ :too_long => '%s must be less than %s characters long',
45
+ :too_short => '%s must be more than %s characters long',
46
+ :wrong_length => '%s must be %s characters long',
47
+ :taken => '%s is already taken',
48
+ :not_a_number => '%s must be a number',
49
+ :not_an_integer => '%s must be an integer',
50
+ :greater_than => '%s must be greater than %s',
51
+ :greater_than_or_equal_to => "%s must be greater than or equal to %s",
52
+ :equal_to => "%s must be equal to %s",
53
+ :less_than => '%s must be less than %s',
54
+ :less_than_or_equal_to => "%s must be less than or equal to %s",
55
+ :value_between => '%s must be between %s and %s',
56
+ :primitive => '%s must be of type %s'
57
+ }
58
+
59
+ # Holds a hash with all the default error messages that can be replaced by your own copy or localizations.
60
+ cattr_writer :default_error_messages
61
+
62
+ def self.default_error_message(key, field, *values)
63
+ field = Extlib::Inflection.humanize(field)
64
+ @@default_error_messages[key] % [field, *values].flatten
65
+ end
66
+
67
+ # Clear existing validation errors.
68
+ def clear!
69
+ errors.clear
70
+ end
71
+
72
+ # Add a validation error. Use the field_name :general if the errors does
73
+ # not apply to a specific field of the Resource.
74
+ #
75
+ # @param <Symbol> field_name the name of the field that caused the error
76
+ # @param <String> message the message to add
77
+ def add(field_name, message)
78
+ (errors[field_name.to_sym] ||= []) << message
79
+ end
80
+
81
+ # Collect all errors into a single list.
82
+ def full_messages
83
+ errors.inject([]) do |list, pair|
84
+ list += pair.last
85
+ end
86
+ end
87
+
88
+ # Return validation errors for a particular field_name.
89
+ #
90
+ # @param <Symbol> field_name the name of the field you want an error for
91
+ def on(field_name)
92
+ errors_for_field = errors[field_name]
93
+ errors_for_field.blank? ? nil : errors_for_field
94
+ end
95
+
96
+ def each
97
+ errors.map.each do |k, v|
98
+ next if v.blank?
99
+ yield(v)
100
+ end
101
+ end
102
+
103
+ def empty?
104
+ entries.empty?
105
+ end
106
+
107
+ def method_missing(meth, *args, &block)
108
+ errors.send(meth, *args, &block)
109
+ end
110
+
111
+ private
112
+ def errors
113
+ @errors ||= {}
114
+ end
115
+
116
+ end # class ValidationErrors
117
+ end # module Validation
118
+ end # module CouchRest
@@ -0,0 +1,74 @@
1
+ # Extracted from dm-validations 0.9.10
2
+ #
3
+ # Copyright (c) 2007 Guy van den Berg
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ module CouchRest
25
+ module Validation
26
+
27
+ ##
28
+ #
29
+ # @author Guy van den Berg
30
+ class AbsentFieldValidator < GenericValidator
31
+
32
+ def initialize(field_name, options={})
33
+ super
34
+ @field_name, @options = field_name, options
35
+ end
36
+
37
+ def call(target)
38
+ value = target.send(field_name)
39
+ return true if (value.nil? || (value.respond_to?(:empty?) && value.empty?))
40
+
41
+ error_message = @options[:message] || ValidationErrors.default_error_message(:absent, field_name)
42
+ add_error(target, error_message, field_name)
43
+
44
+ return false
45
+ end
46
+ end # class AbsentFieldValidator
47
+
48
+ module ValidatesAbsent
49
+
50
+ ##
51
+ #
52
+ # @example [Usage]
53
+ #
54
+ # class Page
55
+ #
56
+ # property :unwanted_attribute, String
57
+ # property :another_unwanted, String
58
+ # property :yet_again, String
59
+ #
60
+ # validates_absent :unwanted_attribute
61
+ # validates_absent :another_unwanted, :yet_again
62
+ #
63
+ # # a call to valid? will return false unless
64
+ # # all three attributes are blank
65
+ # end
66
+ #
67
+ def validates_absent(*fields)
68
+ opts = opts_from_validator_args(fields)
69
+ add_validator_to_context(opts, fields, CouchRest::Validation::AbsentFieldValidator)
70
+ end
71
+
72
+ end # module ValidatesAbsent
73
+ end # module Validation
74
+ end # module CouchRest
@@ -0,0 +1,99 @@
1
+ # Extracted from dm-validations 0.9.10
2
+ #
3
+ # Copyright (c) 2007 Guy van den Berg
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ module CouchRest
25
+ module Validation
26
+
27
+ ##
28
+ #
29
+ # @author Guy van den Berg
30
+ # @since 0.9
31
+ class ConfirmationValidator < GenericValidator
32
+
33
+ def initialize(field_name, options = {})
34
+ super
35
+ @options = options
36
+ @field_name, @confirm_field_name = field_name, (options[:confirm] || "#{field_name}_confirmation").to_sym
37
+ @options[:allow_nil] = true unless @options.has_key?(:allow_nil)
38
+ end
39
+
40
+ def call(target)
41
+ unless valid?(target)
42
+ error_message = @options[:message] || ValidationErrors.default_error_message(:confirmation, field_name)
43
+ add_error(target, error_message, field_name)
44
+ return false
45
+ end
46
+
47
+ return true
48
+ end
49
+
50
+ def valid?(target)
51
+ field_value = target.send(field_name)
52
+ return true if @options[:allow_nil] && field_value.nil?
53
+ return false if !@options[:allow_nil] && field_value.nil?
54
+
55
+ confirm_value = target.instance_variable_get("@#{@confirm_field_name}")
56
+ field_value == confirm_value
57
+ end
58
+
59
+ end # class ConfirmationValidator
60
+
61
+ module ValidatesIsConfirmed
62
+
63
+ ##
64
+ # Validates that the given attribute is confirmed by another attribute.
65
+ # A common use case scenario is when you require a user to confirm their
66
+ # password, for which you use both password and password_confirmation
67
+ # attributes.
68
+ #
69
+ # @option :allow_nil<Boolean> true/false (default is true)
70
+ # @option :confirm<Symbol> the attribute that you want to validate
71
+ # against (default is firstattr_confirmation)
72
+ #
73
+ # @example [Usage]
74
+ #
75
+ # class Page < Hash
76
+ # include CouchRest::ExtendedModel
77
+ # include CouchRest::Validations
78
+ #
79
+ # property :password, String
80
+ # property :email, String
81
+ # attr_accessor :password_confirmation
82
+ # attr_accessor :email_repeated
83
+ #
84
+ # validates_is_confirmed :password
85
+ # validates_is_confirmed :email, :confirm => :email_repeated
86
+ #
87
+ # # a call to valid? will return false unless:
88
+ # # password == password_confirmation
89
+ # # and
90
+ # # email == email_repeated
91
+ #
92
+ def validates_is_confirmed(*fields)
93
+ opts = opts_from_validator_args(fields)
94
+ add_validator_to_context(opts, fields, CouchRest::Validation::ConfirmationValidator)
95
+ end
96
+
97
+ end # module ValidatesIsConfirmed
98
+ end # module Validation
99
+ end # module CouchRest
@@ -0,0 +1,117 @@
1
+ # Extracted from dm-validations 0.9.10
2
+ #
3
+ # Copyright (c) 2007 Guy van den Berg
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ require 'pathname'
25
+ require Pathname(__FILE__).dirname.expand_path + 'formats/email'
26
+ require Pathname(__FILE__).dirname.expand_path + 'formats/url'
27
+
28
+ module CouchRest
29
+ module Validation
30
+
31
+ ##
32
+ #
33
+ # @author Guy van den Berg
34
+ # @since 0.9
35
+ class FormatValidator < GenericValidator
36
+
37
+ FORMATS = {}
38
+ include CouchRest::Validation::Format::Email
39
+ include CouchRest::Validation::Format::Url
40
+
41
+ def initialize(field_name, options = {}, &b)
42
+ super(field_name, options)
43
+ @field_name, @options = field_name, options
44
+ @options[:allow_nil] = false unless @options.has_key?(:allow_nil)
45
+ end
46
+
47
+ def call(target)
48
+ value = target.validation_property_value(field_name)
49
+ return true if @options[:allow_nil] && value.nil?
50
+
51
+ validation = @options[:as] || @options[:with]
52
+
53
+ raise "No such predefined format '#{validation}'" if validation.is_a?(Symbol) && !FORMATS.has_key?(validation)
54
+ validator = validation.is_a?(Symbol) ? FORMATS[validation][0] : validation
55
+
56
+ valid = case validator
57
+ when Proc then validator.call(value)
58
+ when Regexp then value =~ validator
59
+ else
60
+ raise UnknownValidationFormat, "Can't determine how to validate #{target.class}##{field_name} with #{validator.inspect}"
61
+ end
62
+
63
+ return true if valid
64
+
65
+ error_message = @options[:message] || ValidationErrors.default_error_message(:invalid, field_name)
66
+
67
+ field = Extlib::Inflection.humanize(field_name)
68
+ error_message = error_message.call(field, value) if error_message.respond_to?(:call)
69
+
70
+ add_error(target, error_message, field_name)
71
+
72
+ false
73
+ end
74
+
75
+ #class UnknownValidationFormat < StandardError; end
76
+
77
+ end # class FormatValidator
78
+
79
+ module ValidatesFormat
80
+
81
+ ##
82
+ # Validates that the attribute is in the specified format. You may use the
83
+ # :as (or :with, it's an alias) option to specify the pre-defined format
84
+ # that you want to validate against. You may also specify your own format
85
+ # via a Proc or Regexp passed to the the :as or :with options.
86
+ #
87
+ # @option :allow_nil<Boolean> true/false (default is true)
88
+ # @option :as<Format, Proc, Regexp> the pre-defined format, Proc or Regexp to validate against
89
+ # @option :with<Format, Proc, Regexp> an alias for :as
90
+ #
91
+ # @details [Pre-defined Formats]
92
+ # :email_address (format is specified in DataMapper::Validation::Format::Email)
93
+ # :url (format is specified in DataMapper::Validation::Format::Url)
94
+ #
95
+ # @example [Usage]
96
+ #
97
+ # class Page
98
+ #
99
+ # property :email, String
100
+ # property :zip_code, String
101
+ #
102
+ # validates_format :email, :as => :email_address
103
+ # validates_format :zip_code, :with => /^\d{5}$/
104
+ #
105
+ # # a call to valid? will return false unless:
106
+ # # email is formatted like an email address
107
+ # # and
108
+ # # zip_code is a string of 5 digits
109
+ #
110
+ def validates_format(*fields)
111
+ opts = opts_from_validator_args(fields)
112
+ add_validator_to_context(opts, fields, CouchRest::Validation::FormatValidator)
113
+ end
114
+
115
+ end # module ValidatesFormat
116
+ end # module Validation
117
+ end # module CouchRest
@@ -0,0 +1,66 @@
1
+ # encoding: binary
2
+
3
+ # Extracted from dm-validations 0.9.10
4
+ #
5
+ # Copyright (c) 2007 Guy van den Berg
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ module CouchRest
27
+ module Validation
28
+ module Format
29
+ module Email
30
+
31
+ def self.included(base)
32
+ CouchRest::Validation::FormatValidator::FORMATS.merge!(
33
+ :email_address => [ EmailAddress, lambda { |field, value| '%s is not a valid email address'.t(value) }]
34
+ )
35
+ end
36
+
37
+ # RFC2822 (No attribution reference available)
38
+ EmailAddress = begin
39
+ alpha = "a-zA-Z"
40
+ digit = "0-9"
41
+ atext = "[#{alpha}#{digit}\!\#\$\%\&\'\*+\/\=\?\^\_\`\{\|\}\~\-]"
42
+ dot_atom_text = "#{atext}+([.]#{atext}*)*"
43
+ dot_atom = "#{dot_atom_text}"
44
+ qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'
45
+ text = "[\\x01-\\x09\\x11\\x12\\x14-\\x7f]"
46
+ quoted_pair = "(\\x5c#{text})"
47
+ qcontent = "(?:#{qtext}|#{quoted_pair})"
48
+ quoted_string = "[\"]#{qcontent}+[\"]"
49
+ atom = "#{atext}+"
50
+ word = "(?:#{atom}|#{quoted_string})"
51
+ obs_local_part = "#{word}([.]#{word})*"
52
+ local_part = "(?:#{dot_atom}|#{quoted_string}|#{obs_local_part})"
53
+ no_ws_ctl = "\\x01-\\x08\\x11\\x12\\x14-\\x1f\\x7f"
54
+ dtext = "[#{no_ws_ctl}\\x21-\\x5a\\x5e-\\x7e]"
55
+ dcontent = "(?:#{dtext}|#{quoted_pair})"
56
+ domain_literal = "\\[#{dcontent}+\\]"
57
+ obs_domain = "#{atom}([.]#{atom})*"
58
+ domain = "(?:#{dot_atom}|#{domain_literal}|#{obs_domain})"
59
+ addr_spec = "#{local_part}\@#{domain}"
60
+ pattern = /^#{addr_spec}$/
61
+ end
62
+
63
+ end # module Email
64
+ end # module Format
65
+ end # module Validation
66
+ end # module CouchRest