norr-couchrest 0.30

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 (96) hide show
  1. data/LICENSE +176 -0
  2. data/README.md +117 -0
  3. data/Rakefile +74 -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/history.txt +19 -0
  17. data/lib/couchrest.rb +198 -0
  18. data/lib/couchrest/commands/generate.rb +71 -0
  19. data/lib/couchrest/commands/push.rb +103 -0
  20. data/lib/couchrest/core/database.rb +320 -0
  21. data/lib/couchrest/core/design.rb +79 -0
  22. data/lib/couchrest/core/document.rb +87 -0
  23. data/lib/couchrest/core/response.rb +16 -0
  24. data/lib/couchrest/core/server.rb +88 -0
  25. data/lib/couchrest/core/view.rb +4 -0
  26. data/lib/couchrest/helper/pager.rb +103 -0
  27. data/lib/couchrest/helper/streamer.rb +44 -0
  28. data/lib/couchrest/helper/upgrade.rb +51 -0
  29. data/lib/couchrest/mixins.rb +4 -0
  30. data/lib/couchrest/mixins/attachments.rb +31 -0
  31. data/lib/couchrest/mixins/callbacks.rb +483 -0
  32. data/lib/couchrest/mixins/class_proxy.rb +112 -0
  33. data/lib/couchrest/mixins/collection.rb +220 -0
  34. data/lib/couchrest/mixins/design_doc.rb +101 -0
  35. data/lib/couchrest/mixins/document_queries.rb +53 -0
  36. data/lib/couchrest/mixins/extended_attachments.rb +74 -0
  37. data/lib/couchrest/mixins/extended_document_mixins.rb +8 -0
  38. data/lib/couchrest/mixins/properties.rb +147 -0
  39. data/lib/couchrest/mixins/validation.rb +257 -0
  40. data/lib/couchrest/mixins/views.rb +181 -0
  41. data/lib/couchrest/monkeypatches.rb +113 -0
  42. data/lib/couchrest/more/casted_model.rb +29 -0
  43. data/lib/couchrest/more/extended_document.rb +229 -0
  44. data/lib/couchrest/more/property.rb +40 -0
  45. data/lib/couchrest/support/blank.rb +42 -0
  46. data/lib/couchrest/support/class.rb +176 -0
  47. data/lib/couchrest/support/rails.rb +35 -0
  48. data/lib/couchrest/validation/auto_validate.rb +161 -0
  49. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  50. data/lib/couchrest/validation/validation_errors.rb +118 -0
  51. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  52. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  53. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  54. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  55. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  56. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  57. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  58. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  59. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  60. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  61. data/spec/couchrest/core/couchrest_spec.rb +201 -0
  62. data/spec/couchrest/core/database_spec.rb +700 -0
  63. data/spec/couchrest/core/design_spec.rb +138 -0
  64. data/spec/couchrest/core/document_spec.rb +267 -0
  65. data/spec/couchrest/core/server_spec.rb +35 -0
  66. data/spec/couchrest/helpers/pager_spec.rb +122 -0
  67. data/spec/couchrest/helpers/streamer_spec.rb +23 -0
  68. data/spec/couchrest/more/casted_extended_doc_spec.rb +75 -0
  69. data/spec/couchrest/more/casted_model_spec.rb +177 -0
  70. data/spec/couchrest/more/extended_doc_attachment_spec.rb +135 -0
  71. data/spec/couchrest/more/extended_doc_spec.rb +563 -0
  72. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  73. data/spec/couchrest/more/extended_doc_view_spec.rb +414 -0
  74. data/spec/couchrest/more/property_spec.rb +146 -0
  75. data/spec/fixtures/attachments/README +3 -0
  76. data/spec/fixtures/attachments/couchdb.png +0 -0
  77. data/spec/fixtures/attachments/test.html +11 -0
  78. data/spec/fixtures/more/article.rb +34 -0
  79. data/spec/fixtures/more/card.rb +22 -0
  80. data/spec/fixtures/more/cat.rb +18 -0
  81. data/spec/fixtures/more/course.rb +14 -0
  82. data/spec/fixtures/more/event.rb +6 -0
  83. data/spec/fixtures/more/invoice.rb +17 -0
  84. data/spec/fixtures/more/person.rb +8 -0
  85. data/spec/fixtures/more/question.rb +6 -0
  86. data/spec/fixtures/more/service.rb +12 -0
  87. data/spec/fixtures/views/lib.js +3 -0
  88. data/spec/fixtures/views/test_view/lib.js +3 -0
  89. data/spec/fixtures/views/test_view/only-map.js +4 -0
  90. data/spec/fixtures/views/test_view/test-map.js +3 -0
  91. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  92. data/spec/spec.opts +6 -0
  93. data/spec/spec_helper.rb +37 -0
  94. data/utils/remap.rb +27 -0
  95. data/utils/subset.rb +30 -0
  96. metadata +194 -0
@@ -0,0 +1,74 @@
1
+ module CouchRest
2
+ module Mixins
3
+ module ExtendedAttachments
4
+
5
+ # creates a file attachment to the current doc
6
+ def create_attachment(args={})
7
+ raise ArgumentError unless args[:file] && args[:name]
8
+ return if has_attachment?(args[:name])
9
+ self['_attachments'] ||= {}
10
+ set_attachment_attr(args)
11
+ rescue ArgumentError => e
12
+ raise ArgumentError, 'You must specify :file and :name'
13
+ end
14
+
15
+ # reads the data from an attachment
16
+ def read_attachment(attachment_name)
17
+ Base64.decode64(database.fetch_attachment(self, attachment_name))
18
+ end
19
+
20
+ # modifies a file attachment on the current doc
21
+ def update_attachment(args={})
22
+ raise ArgumentError unless args[:file] && args[:name]
23
+ return unless has_attachment?(args[:name])
24
+ delete_attachment(args[:name])
25
+ set_attachment_attr(args)
26
+ rescue ArgumentError => e
27
+ raise ArgumentError, 'You must specify :file and :name'
28
+ end
29
+
30
+ # deletes a file attachment from the current doc
31
+ def delete_attachment(attachment_name)
32
+ return unless self['_attachments']
33
+ self['_attachments'].delete attachment_name
34
+ end
35
+
36
+ # returns true if attachment_name exists
37
+ def has_attachment?(attachment_name)
38
+ !!(self['_attachments'] && self['_attachments'][attachment_name] && !self['_attachments'][attachment_name].empty?)
39
+ end
40
+
41
+ # returns URL to fetch the attachment from
42
+ def attachment_url(attachment_name)
43
+ return unless has_attachment?(attachment_name)
44
+ "#{database.root}/#{self.id}/#{attachment_name}"
45
+ end
46
+
47
+ # returns URI to fetch the attachment from
48
+ def attachment_uri(attachment_name)
49
+ return unless has_attachment?(attachment_name)
50
+ "#{database.uri}/#{self.id}/#{attachment_name}"
51
+ end
52
+
53
+ private
54
+
55
+ def encode_attachment(data)
56
+ ::Base64.encode64(data).gsub(/\r|\n/,'')
57
+ end
58
+
59
+ def get_mime_type(file)
60
+ ::MIME::Types.type_for(file.path).empty? ?
61
+ 'text\/plain' : MIME::Types.type_for(file.path).first.content_type.gsub(/\//,'\/')
62
+ end
63
+
64
+ def set_attachment_attr(args)
65
+ content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file])
66
+ self['_attachments'][args[:name]] = {
67
+ 'content-type' => content_type,
68
+ 'data' => encode_attachment(args[:file].read)
69
+ }
70
+ end
71
+
72
+ end # module ExtendedAttachments
73
+ end
74
+ end
@@ -0,0 +1,8 @@
1
+ require File.join(File.dirname(__FILE__), 'properties')
2
+ require File.join(File.dirname(__FILE__), 'document_queries')
3
+ require File.join(File.dirname(__FILE__), 'views')
4
+ require File.join(File.dirname(__FILE__), 'design_doc')
5
+ require File.join(File.dirname(__FILE__), 'validation')
6
+ require File.join(File.dirname(__FILE__), 'extended_attachments')
7
+ require File.join(File.dirname(__FILE__), 'class_proxy')
8
+ require File.join(File.dirname(__FILE__), 'collection')
@@ -0,0 +1,147 @@
1
+ require 'time'
2
+ require File.join(File.dirname(__FILE__), '..', 'more', 'property')
3
+
4
+ class Time
5
+ # returns a local time value much faster than Time.parse
6
+ def self.mktime_with_offset(string)
7
+ string =~ /(\d{4})\/(\d{2})\/(\d{2}) (\d{2}):(\d{2}):(\d{2}) ([\+\-])(\d{2})/
8
+ # $1 = year
9
+ # $2 = month
10
+ # $3 = day
11
+ # $4 = hours
12
+ # $5 = minutes
13
+ # $6 = seconds
14
+ # $7 = time zone direction
15
+ # $8 = tz difference
16
+ # utc time with wrong TZ info:
17
+ time = mktime($1, RFC2822_MONTH_NAME[$2.to_i - 1], $3, $4, $5, $6, $7)
18
+ tz_difference = ("#{$7 == '-' ? '+' : '-'}#{$8}".to_i * 3600)
19
+ time + tz_difference + zone_offset(time.zone)
20
+ end
21
+ end
22
+
23
+ module CouchRest
24
+ module Mixins
25
+ module Properties
26
+
27
+ class IncludeError < StandardError; end
28
+
29
+ def self.included(base)
30
+ base.class_eval <<-EOS, __FILE__, __LINE__
31
+ extlib_inheritable_accessor(:properties) unless self.respond_to?(:properties)
32
+ self.properties ||= []
33
+ EOS
34
+ base.extend(ClassMethods)
35
+ raise CouchRest::Mixins::Properties::IncludeError, "You can only mixin Properties in a class responding to [] and []=, if you tried to mixin CastedModel, make sure your class inherits from Hash or responds to the proper methods" unless (base.new.respond_to?(:[]) && base.new.respond_to?(:[]=))
36
+ end
37
+
38
+ def apply_defaults
39
+ return if self.respond_to?(:new_document?) && (new_document? == false)
40
+ return unless self.class.respond_to?(:properties)
41
+ return if self.class.properties.empty?
42
+ # TODO: cache the default object
43
+ self.class.properties.each do |property|
44
+ key = property.name.to_s
45
+ # let's make sure we have a default
46
+ unless property.default.nil?
47
+ if property.default.class == Proc
48
+ self[key] = property.default.call
49
+ else
50
+ self[key] = Marshal.load(Marshal.dump(property.default))
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def cast_keys
57
+ return unless self.class.properties
58
+ self.class.properties.each do |property|
59
+
60
+ next unless property.casted
61
+ key = self.has_key?(property.name) ? property.name : property.name.to_sym
62
+ # Don't cast the property unless it has a value
63
+ next unless self[key]
64
+ target = property.type
65
+ if target.is_a?(Array)
66
+ klass = ::CouchRest.constantize(target[0])
67
+ self[property.name] = self[key].collect do |value|
68
+ # Auto parse Time objects
69
+ obj = ( (property.init_method == 'new') && klass == Time) ? Time.parse(value) : klass.send(property.init_method, value)
70
+ obj.casted_by = self if obj.respond_to?(:casted_by)
71
+ obj
72
+ end
73
+ else
74
+ # Auto parse Time objects
75
+ self[property.name] = if ((property.init_method == 'new') && target == 'Time')
76
+ # Using custom time parsing method because Ruby's default method is toooo slow
77
+ self[key].is_a?(String) ? Time.mktime_with_offset(self[key].dup) : self[key]
78
+ else
79
+ # Let people use :send as a Time parse arg
80
+ klass = ::CouchRest.constantize(target)
81
+ klass.send(property.init_method, self[key].dup)
82
+ end
83
+ self[property.name].casted_by = self if self[property.name].respond_to?(:casted_by)
84
+ end
85
+
86
+ end
87
+ end
88
+
89
+ module ClassMethods
90
+
91
+ def property(name, options={})
92
+ existing_property = self.properties.find{|p| p.name == name.to_s}
93
+ if existing_property.nil? || (existing_property.default != options[:default])
94
+ define_property(name, options)
95
+ end
96
+ end
97
+
98
+ protected
99
+
100
+ # This is not a thread safe operation, if you have to set new properties at runtime
101
+ # make sure to use a mutex.
102
+ def define_property(name, options={})
103
+ # check if this property is going to casted
104
+ options[:casted] = options[:cast_as] ? options[:cast_as] : false
105
+ property = CouchRest::Property.new(name, (options.delete(:cast_as) || options.delete(:type)), options)
106
+ create_property_getter(property)
107
+ create_property_setter(property) unless property.read_only == true
108
+ properties << property
109
+ end
110
+
111
+ # defines the getter for the property (and optional aliases)
112
+ def create_property_getter(property)
113
+ # meth = property.name
114
+ class_eval <<-EOS, __FILE__, __LINE__
115
+ def #{property.name}
116
+ self['#{property.name}']
117
+ end
118
+ EOS
119
+
120
+ if property.alias
121
+ class_eval <<-EOS, __FILE__, __LINE__
122
+ alias #{property.alias.to_sym} #{property.name.to_sym}
123
+ EOS
124
+ end
125
+ end
126
+
127
+ # defines the setter for the property (and optional aliases)
128
+ def create_property_setter(property)
129
+ meth = property.name
130
+ class_eval <<-EOS
131
+ def #{meth}=(value)
132
+ self['#{meth}'] = value
133
+ end
134
+ EOS
135
+
136
+ if property.alias
137
+ class_eval <<-EOS
138
+ alias #{property.alias.to_sym}= #{meth.to_sym}=
139
+ EOS
140
+ end
141
+ end
142
+
143
+ end # module ClassMethods
144
+
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,257 @@
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
+ class Object
25
+ def validatable?
26
+ false
27
+ end
28
+ end
29
+
30
+ require 'pathname'
31
+ require File.join(File.dirname(__FILE__), '..', 'support', 'class')
32
+
33
+ dir = File.join(Pathname(__FILE__).dirname.expand_path, '..', 'validation')
34
+
35
+ require File.join(dir, 'validation_errors')
36
+ require File.join(dir, 'contextual_validators')
37
+ require File.join(dir, 'auto_validate')
38
+
39
+ require File.join(dir, 'validators', 'generic_validator')
40
+ require File.join(dir, 'validators', 'required_field_validator')
41
+ require File.join(dir, 'validators', 'absent_field_validator')
42
+ require File.join(dir, 'validators', 'format_validator')
43
+ require File.join(dir, 'validators', 'length_validator')
44
+ require File.join(dir, 'validators', 'numeric_validator')
45
+ require File.join(dir, 'validators', 'method_validator')
46
+ require File.join(dir, 'validators', 'confirmation_validator')
47
+
48
+ module CouchRest
49
+ module Validation
50
+
51
+ def self.included(base)
52
+ base.extlib_inheritable_accessor(:auto_validation)
53
+ base.class_eval <<-EOS, __FILE__, __LINE__
54
+ # Turn off auto validation by default
55
+ self.auto_validation ||= false
56
+
57
+ # Force the auto validation for the class properties
58
+ # This feature is still not fully ported over,
59
+ # test are lacking, so please use with caution
60
+ def self.auto_validate!
61
+ self.auto_validation = true
62
+ end
63
+
64
+ # share the validations with subclasses
65
+ def self.inherited(subklass)
66
+ self.validators.contexts.each do |k, v|
67
+ subklass.validators.contexts[k] = v.dup
68
+ end
69
+ super
70
+ end
71
+ EOS
72
+
73
+ base.extend(ClassMethods)
74
+ base.class_eval <<-EOS, __FILE__, __LINE__
75
+ if method_defined?(:_run_save_callbacks)
76
+ save_callback :before, :check_validations
77
+ end
78
+ EOS
79
+ base.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
80
+ def self.define_property(name, options={})
81
+ super
82
+ auto_generate_validations(properties.last) if properties && properties.size > 0
83
+ autovalidation_check = true
84
+ end
85
+ RUBY_EVAL
86
+ end
87
+
88
+ # Ensures the object is valid for the context provided, and otherwise
89
+ # throws :halt and returns false.
90
+ #
91
+ def check_validations(context = :default)
92
+ throw(:halt, false) unless context.nil? || valid?(context)
93
+ end
94
+
95
+ # Return the ValidationErrors
96
+ #
97
+ def errors
98
+ @errors ||= ValidationErrors.new
99
+ end
100
+
101
+ # Mark this resource as validatable. When we validate associations of a
102
+ # resource we can check if they respond to validatable? before trying to
103
+ # recursivly validate them
104
+ #
105
+ def validatable?
106
+ true
107
+ end
108
+
109
+ # Alias for valid?(:default)
110
+ #
111
+ def valid_for_default?
112
+ valid?(:default)
113
+ end
114
+
115
+ # Check if a resource is valid in a given context
116
+ #
117
+ def valid?(context = :default)
118
+ result = self.class.validators.execute(context, self)
119
+ result && validate_casted_arrays
120
+ end
121
+
122
+ # checking on casted objects
123
+ def validate_casted_arrays
124
+ result = true
125
+ array_casted_properties = self.class.properties.select { |property| property.casted && property.type.instance_of?(Array) }
126
+ array_casted_properties.each do |property|
127
+ casted_values = self.send(property.name)
128
+ next unless casted_values.is_a?(Array) && casted_values.first.respond_to?(:valid?)
129
+ casted_values.each do |value|
130
+ result = (result && value.valid?) if value.respond_to?(:valid?)
131
+ end
132
+ end
133
+ result
134
+ end
135
+
136
+ # Begin a recursive walk of the model checking validity
137
+ #
138
+ def all_valid?(context = :default)
139
+ recursive_valid?(self, context, true)
140
+ end
141
+
142
+ # Do recursive validity checking
143
+ #
144
+ def recursive_valid?(target, context, state)
145
+ valid = state
146
+ target.instance_variables.each do |ivar|
147
+ ivar_value = target.instance_variable_get(ivar)
148
+ if ivar_value.validatable?
149
+ valid = valid && recursive_valid?(ivar_value, context, valid)
150
+ elsif ivar_value.respond_to?(:each)
151
+ ivar_value.each do |item|
152
+ if item.validatable?
153
+ valid = valid && recursive_valid?(item, context, valid)
154
+ end
155
+ end
156
+ end
157
+ end
158
+ return valid && target.valid?
159
+ end
160
+
161
+
162
+ def validation_property_value(name)
163
+ self.respond_to?(name, true) ? self.send(name) : nil
164
+ end
165
+
166
+ # Get the corresponding Object property, if it exists.
167
+ def validation_property(field_name)
168
+ properties.find{|p| p.name == field_name}
169
+ end
170
+
171
+ module ClassMethods
172
+ include CouchRest::Validation::ValidatesPresent
173
+ include CouchRest::Validation::ValidatesAbsent
174
+ include CouchRest::Validation::ValidatesIsConfirmed
175
+ # include CouchRest::Validation::ValidatesIsPrimitive
176
+ # include CouchRest::Validation::ValidatesIsAccepted
177
+ include CouchRest::Validation::ValidatesFormat
178
+ include CouchRest::Validation::ValidatesLength
179
+ # include CouchRest::Validation::ValidatesWithin
180
+ include CouchRest::Validation::ValidatesIsNumber
181
+ include CouchRest::Validation::ValidatesWithMethod
182
+ # include CouchRest::Validation::ValidatesWithBlock
183
+ # include CouchRest::Validation::ValidatesIsUnique
184
+ include CouchRest::Validation::AutoValidate
185
+
186
+ # Return the set of contextual validators or create a new one
187
+ #
188
+ def validators
189
+ @validations ||= ContextualValidators.new
190
+ end
191
+
192
+ # Clean up the argument list and return a opts hash, including the
193
+ # merging of any default opts. Set the context to default if none is
194
+ # provided. Also allow :context to be aliased to :on, :when & group
195
+ #
196
+ def opts_from_validator_args(args, defaults = nil)
197
+ opts = args.last.kind_of?(Hash) ? args.pop : {}
198
+ context = :default
199
+ context = opts[:context] if opts.has_key?(:context)
200
+ context = opts.delete(:on) if opts.has_key?(:on)
201
+ context = opts.delete(:when) if opts.has_key?(:when)
202
+ context = opts.delete(:group) if opts.has_key?(:group)
203
+ opts[:context] = context
204
+ opts.merge!(defaults) unless defaults.nil?
205
+ opts
206
+ end
207
+
208
+ # Given a new context create an instance method of
209
+ # valid_for_<context>? which simply calls valid?(context)
210
+ # if it does not already exist
211
+ #
212
+ def create_context_instance_methods(context)
213
+ name = "valid_for_#{context.to_s}?" # valid_for_signup?
214
+ if !self.instance_methods.include?(name)
215
+ class_eval <<-EOS, __FILE__, __LINE__
216
+ def #{name} # def valid_for_signup?
217
+ valid?('#{context.to_s}'.to_sym) # valid?('signup'.to_sym)
218
+ end # end
219
+ EOS
220
+ end
221
+
222
+ all = "all_valid_for_#{context.to_s}?" # all_valid_for_signup?
223
+ if !self.instance_methods.include?(all)
224
+ class_eval <<-EOS, __FILE__, __LINE__
225
+ def #{all} # def all_valid_for_signup?
226
+ all_valid?('#{context.to_s}'.to_sym) # all_valid?('signup'.to_sym)
227
+ end # end
228
+ EOS
229
+ end
230
+ end
231
+
232
+ # Create a new validator of the given klazz and push it onto the
233
+ # requested context for each of the attributes in the fields list
234
+ #
235
+ def add_validator_to_context(opts, fields, klazz)
236
+ fields.each do |field|
237
+ validator = klazz.new(field.to_sym, opts)
238
+ if opts[:context].is_a?(Symbol)
239
+ unless validators.context(opts[:context]).include?(validator)
240
+ validators.context(opts[:context]) << validator
241
+ create_context_instance_methods(opts[:context])
242
+ end
243
+ elsif opts[:context].is_a?(Array)
244
+ opts[:context].each do |c|
245
+ unless validators.context(c).include?(validator)
246
+ validators.context(c) << validator
247
+ create_context_instance_methods(c)
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ end # module ClassMethods
255
+ end # module Validation
256
+
257
+ end # module CouchRest