brianmario-couchrest 0.23

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 (92) hide show
  1. data/LICENSE +176 -0
  2. data/README.md +95 -0
  3. data/Rakefile +75 -0
  4. data/THANKS.md +18 -0
  5. data/examples/model/example.rb +144 -0
  6. data/examples/word_count/markov +38 -0
  7. data/examples/word_count/views/books/chunked-map.js +3 -0
  8. data/examples/word_count/views/books/united-map.js +1 -0
  9. data/examples/word_count/views/markov/chain-map.js +6 -0
  10. data/examples/word_count/views/markov/chain-reduce.js +7 -0
  11. data/examples/word_count/views/word_count/count-map.js +6 -0
  12. data/examples/word_count/views/word_count/count-reduce.js +3 -0
  13. data/examples/word_count/word_count.rb +46 -0
  14. data/examples/word_count/word_count_query.rb +40 -0
  15. data/examples/word_count/word_count_views.rb +26 -0
  16. data/lib/couchrest.rb +198 -0
  17. data/lib/couchrest/commands/generate.rb +71 -0
  18. data/lib/couchrest/commands/push.rb +103 -0
  19. data/lib/couchrest/core/database.rb +303 -0
  20. data/lib/couchrest/core/design.rb +79 -0
  21. data/lib/couchrest/core/document.rb +87 -0
  22. data/lib/couchrest/core/response.rb +16 -0
  23. data/lib/couchrest/core/server.rb +88 -0
  24. data/lib/couchrest/core/view.rb +4 -0
  25. data/lib/couchrest/helper/pager.rb +103 -0
  26. data/lib/couchrest/helper/streamer.rb +44 -0
  27. data/lib/couchrest/helper/upgrade.rb +51 -0
  28. data/lib/couchrest/mixins.rb +4 -0
  29. data/lib/couchrest/mixins/attachments.rb +31 -0
  30. data/lib/couchrest/mixins/callbacks.rb +483 -0
  31. data/lib/couchrest/mixins/class_proxy.rb +108 -0
  32. data/lib/couchrest/mixins/design_doc.rb +90 -0
  33. data/lib/couchrest/mixins/document_queries.rb +44 -0
  34. data/lib/couchrest/mixins/extended_attachments.rb +68 -0
  35. data/lib/couchrest/mixins/extended_document_mixins.rb +7 -0
  36. data/lib/couchrest/mixins/properties.rb +129 -0
  37. data/lib/couchrest/mixins/validation.rb +242 -0
  38. data/lib/couchrest/mixins/views.rb +169 -0
  39. data/lib/couchrest/monkeypatches.rb +113 -0
  40. data/lib/couchrest/more/casted_model.rb +28 -0
  41. data/lib/couchrest/more/extended_document.rb +215 -0
  42. data/lib/couchrest/more/property.rb +40 -0
  43. data/lib/couchrest/support/blank.rb +42 -0
  44. data/lib/couchrest/support/class.rb +176 -0
  45. data/lib/couchrest/validation/auto_validate.rb +163 -0
  46. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  47. data/lib/couchrest/validation/validation_errors.rb +118 -0
  48. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  49. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  50. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  51. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  52. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  53. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  54. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  55. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  56. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  57. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  58. data/spec/couchrest/core/couchrest_spec.rb +201 -0
  59. data/spec/couchrest/core/database_spec.rb +699 -0
  60. data/spec/couchrest/core/design_spec.rb +138 -0
  61. data/spec/couchrest/core/document_spec.rb +267 -0
  62. data/spec/couchrest/core/server_spec.rb +35 -0
  63. data/spec/couchrest/helpers/pager_spec.rb +122 -0
  64. data/spec/couchrest/helpers/streamer_spec.rb +23 -0
  65. data/spec/couchrest/more/casted_extended_doc_spec.rb +40 -0
  66. data/spec/couchrest/more/casted_model_spec.rb +98 -0
  67. data/spec/couchrest/more/extended_doc_attachment_spec.rb +130 -0
  68. data/spec/couchrest/more/extended_doc_spec.rb +509 -0
  69. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  70. data/spec/couchrest/more/extended_doc_view_spec.rb +355 -0
  71. data/spec/couchrest/more/property_spec.rb +136 -0
  72. data/spec/fixtures/attachments/README +3 -0
  73. data/spec/fixtures/attachments/couchdb.png +0 -0
  74. data/spec/fixtures/attachments/test.html +11 -0
  75. data/spec/fixtures/more/article.rb +34 -0
  76. data/spec/fixtures/more/card.rb +20 -0
  77. data/spec/fixtures/more/course.rb +14 -0
  78. data/spec/fixtures/more/event.rb +6 -0
  79. data/spec/fixtures/more/invoice.rb +17 -0
  80. data/spec/fixtures/more/person.rb +8 -0
  81. data/spec/fixtures/more/question.rb +6 -0
  82. data/spec/fixtures/more/service.rb +12 -0
  83. data/spec/fixtures/views/lib.js +3 -0
  84. data/spec/fixtures/views/test_view/lib.js +3 -0
  85. data/spec/fixtures/views/test_view/only-map.js +4 -0
  86. data/spec/fixtures/views/test_view/test-map.js +3 -0
  87. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  88. data/spec/spec.opts +6 -0
  89. data/spec/spec_helper.rb +26 -0
  90. data/utils/remap.rb +27 -0
  91. data/utils/subset.rb +30 -0
  92. metadata +200 -0
@@ -0,0 +1,163 @@
1
+ # Ported from dm-migrations
2
+ require File.join(File.dirname(__FILE__), '..', 'support', 'class')
3
+
4
+ module CouchRest
5
+
6
+ class Property
7
+ # flag letting us know if we already checked the autovalidation settings
8
+ attr_accessor :autovalidation_check
9
+ @autovalidation_check = false
10
+ end
11
+
12
+ module Validation
13
+ module AutoValidate
14
+
15
+ # # Force the auto validation for the class properties
16
+ # # This feature is still not fully ported over,
17
+ # # test are lacking, so please use with caution
18
+ # def auto_validate!
19
+ # require 'ruby-debug'
20
+ # debugger
21
+ # auto_validation = true
22
+ # end
23
+
24
+ # adds message for validator
25
+ def options_with_message(base_options, property, validator_name)
26
+ options = base_options.clone
27
+ opts = property.options
28
+ options[:message] = if opts[:messages]
29
+ if opts[:messages].is_a?(Hash) and msg = opts[:messages][validator_name]
30
+ msg
31
+ else
32
+ nil
33
+ end
34
+ elsif opts[:message]
35
+ opts[:message]
36
+ else
37
+ nil
38
+ end
39
+ options
40
+ end
41
+
42
+
43
+ ##
44
+ # Auto-generate validations for a given property. This will only occur
45
+ # if the option :auto_validation is either true or left undefined.
46
+ #
47
+ # @details [Triggers]
48
+ # Triggers that generate validator creation
49
+ #
50
+ # :nullable => false
51
+ # Setting the option :nullable to false causes a
52
+ # validates_presence_of validator to be automatically created on
53
+ # the property
54
+ #
55
+ # :size => 20 or :length => 20
56
+ # Setting the option :size or :length causes a validates_length_of
57
+ # validator to be automatically created on the property. If the
58
+ # value is a Integer the validation will set :maximum => value if
59
+ # the value is a Range the validation will set :within => value
60
+ #
61
+ # :format => :predefined / lambda / Proc
62
+ # Setting the :format option causes a validates_format_of
63
+ # validator to be automatically created on the property
64
+ #
65
+ # :set => ["foo", "bar", "baz"]
66
+ # Setting the :set option causes a validates_within
67
+ # validator to be automatically created on the property
68
+ #
69
+ # Integer type
70
+ # Using a Integer type causes a validates_is_number
71
+ # validator to be created for the property. integer_only
72
+ # is set to true
73
+ #
74
+ # Float type
75
+ # Using a Integer type causes a validates_is_number
76
+ # validator to be created for the property. integer_only
77
+ # is set to false, and precision/scale match the property
78
+ #
79
+ #
80
+ # Messages
81
+ #
82
+ # :messages => {..}
83
+ # Setting :messages hash replaces standard error messages
84
+ # with custom ones. For instance:
85
+ # :messages => {:presence => "Field is required",
86
+ # :format => "Field has invalid format"}
87
+ # Hash keys are: :presence, :format, :length, :is_unique,
88
+ # :is_number, :is_primitive
89
+ #
90
+ # :message => "Some message"
91
+ # It is just shortcut if only one validation option is set
92
+ #
93
+ def auto_generate_validations(property)
94
+ return unless ((property.autovalidation_check != true) && self.auto_validation)
95
+ return if (property.options && (property.options.has_key?(:auto_validation) && !property.options[:auto_validation]) || property.read_only)
96
+ # value is set by the storage system
97
+ opts = {}
98
+ opts[:context] = property.options[:validates] if property.options.has_key?(:validates)
99
+
100
+ # presence
101
+ if opts[:allow_nil] == false
102
+ # validates_present property.name, opts
103
+ validates_present property.name, options_with_message(opts, property, :presence)
104
+ end
105
+
106
+ # length
107
+ if property.type == "String"
108
+ # XXX: maybe length should always return a Range, with the min defaulting to 1
109
+ # 52 being the max set
110
+ len = property.options.fetch(:length, property.options.fetch(:size, 52))
111
+ if len.is_a?(Range)
112
+ opts[:within] = len
113
+ else
114
+ opts[:maximum] = len
115
+ end
116
+ # validates_length property.name, opts
117
+ validates_length property.name, options_with_message(opts, property, :length)
118
+ end
119
+
120
+ # format
121
+ if property.options.has_key?(:format)
122
+ opts[:with] = property.options[:format]
123
+ # validates_format property.name, opts
124
+ validates_format property.name, options_with_message(opts, property, :format)
125
+ end
126
+
127
+ # uniqueness validator
128
+ if property.options.has_key?(:unique)
129
+ value = property.options[:unique]
130
+ if value.is_a?(Array) || value.is_a?(Symbol)
131
+ # validates_is_unique property.name, :scope => Array(value)
132
+ validates_is_unique property.name, options_with_message({:scope => Array(value)}, property, :is_unique)
133
+ elsif value.is_a?(TrueClass)
134
+ # validates_is_unique property.name
135
+ validates_is_unique property.name, options_with_message({}, property, :is_unique)
136
+ end
137
+ end
138
+
139
+ # within validator
140
+ if property.options.has_key?(:set)
141
+ validates_within property.name, options_with_message({:set => property.options[:set]}, property, :within)
142
+ end
143
+
144
+ # numeric validator
145
+ if "Integer" == property.type
146
+ opts[:integer_only] = true
147
+ # validates_is_number property.name, opts
148
+ validates_is_number property.name, options_with_message(opts, property, :is_number)
149
+ elsif Float == property.type
150
+ opts[:precision] = property.precision
151
+ opts[:scale] = property.scale
152
+ # validates_is_number property.name, opts
153
+ validates_is_number property.name, options_with_message(opts, property, :is_number)
154
+ end
155
+
156
+ # marked the property has checked
157
+ property.autovalidation_check = true
158
+
159
+ end
160
+
161
+ end # module AutoValidate
162
+ end # module Validation
163
+ end # module CouchRest
@@ -0,0 +1,78 @@
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 ContextualValidators
32
+
33
+ def dump
34
+ contexts.each_pair do |key, context|
35
+ puts "Key=#{key} Context: #{context}"
36
+ end
37
+ end
38
+
39
+ # Get a hash of named context validators for the resource
40
+ #
41
+ # @return <Hash> a hash of validators <GenericValidator>
42
+ def contexts
43
+ @contexts ||= {}
44
+ end
45
+
46
+ # Return an array of validators for a named context
47
+ #
48
+ # @return <Array> An array of validators
49
+ def context(name)
50
+ contexts[name] ||= []
51
+ end
52
+
53
+ # Clear all named context validators off of the resource
54
+ #
55
+ def clear!
56
+ contexts.clear
57
+ end
58
+
59
+ # Execute all validators in the named context against the target
60
+ #
61
+ # @param <Symbol> named_context the context we are validating against
62
+ # @param <Object> target the resource that we are validating
63
+ # @return <Boolean> true if all are valid, otherwise false
64
+ def execute(named_context, target)
65
+ raise(ArgumentError, 'invalid context specified') if !named_context || (contexts.length > 0 && !contexts[named_context])
66
+ target.errors.clear!
67
+ result = true
68
+ context(named_context).each do |validator|
69
+ next unless validator.execute?(target)
70
+ result = false unless validator.call(target)
71
+ end
72
+
73
+ result
74
+ end
75
+
76
+ end # module ContextualValidators
77
+ end # module Validation
78
+ end # module CouchRest
@@ -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 = CouchRest.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.to_sym]
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