oz-couchrest 0.29

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 (95) hide show
  1. data/LICENSE +176 -0
  2. data/README.md +95 -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/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 +326 -0
  20. data/lib/couchrest/core/design.rb +91 -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 +112 -0
  32. data/lib/couchrest/mixins/collection.rb +222 -0
  33. data/lib/couchrest/mixins/design_doc.rb +114 -0
  34. data/lib/couchrest/mixins/document_queries.rb +53 -0
  35. data/lib/couchrest/mixins/extended_attachments.rb +74 -0
  36. data/lib/couchrest/mixins/extended_document_mixins.rb +8 -0
  37. data/lib/couchrest/mixins/properties.rb +125 -0
  38. data/lib/couchrest/mixins/validation.rb +257 -0
  39. data/lib/couchrest/mixins/views.rb +211 -0
  40. data/lib/couchrest/monkeypatches.rb +112 -0
  41. data/lib/couchrest/more/casted_model.rb +29 -0
  42. data/lib/couchrest/more/extended_document.rb +232 -0
  43. data/lib/couchrest/more/property.rb +40 -0
  44. data/lib/couchrest/support/blank.rb +42 -0
  45. data/lib/couchrest/support/class.rb +176 -0
  46. data/lib/couchrest/support/rails.rb +35 -0
  47. data/lib/couchrest/validation/auto_validate.rb +161 -0
  48. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  49. data/lib/couchrest/validation/validation_errors.rb +118 -0
  50. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  51. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  52. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  53. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  54. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  55. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  56. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  57. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  58. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  59. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  60. data/spec/couchrest/core/couchrest_spec.rb +201 -0
  61. data/spec/couchrest/core/database_spec.rb +700 -0
  62. data/spec/couchrest/core/design_spec.rb +138 -0
  63. data/spec/couchrest/core/document_spec.rb +267 -0
  64. data/spec/couchrest/core/server_spec.rb +35 -0
  65. data/spec/couchrest/helpers/pager_spec.rb +122 -0
  66. data/spec/couchrest/helpers/streamer_spec.rb +23 -0
  67. data/spec/couchrest/more/casted_extended_doc_spec.rb +75 -0
  68. data/spec/couchrest/more/casted_model_spec.rb +177 -0
  69. data/spec/couchrest/more/extended_doc_attachment_spec.rb +135 -0
  70. data/spec/couchrest/more/extended_doc_spec.rb +563 -0
  71. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  72. data/spec/couchrest/more/extended_doc_view_spec.rb +414 -0
  73. data/spec/couchrest/more/property_spec.rb +146 -0
  74. data/spec/fixtures/attachments/README +3 -0
  75. data/spec/fixtures/attachments/couchdb.png +0 -0
  76. data/spec/fixtures/attachments/test.html +11 -0
  77. data/spec/fixtures/more/article.rb +34 -0
  78. data/spec/fixtures/more/card.rb +22 -0
  79. data/spec/fixtures/more/cat.rb +18 -0
  80. data/spec/fixtures/more/course.rb +14 -0
  81. data/spec/fixtures/more/event.rb +6 -0
  82. data/spec/fixtures/more/invoice.rb +17 -0
  83. data/spec/fixtures/more/person.rb +8 -0
  84. data/spec/fixtures/more/question.rb +6 -0
  85. data/spec/fixtures/more/service.rb +12 -0
  86. data/spec/fixtures/views/lib.js +3 -0
  87. data/spec/fixtures/views/test_view/lib.js +3 -0
  88. data/spec/fixtures/views/test_view/only-map.js +4 -0
  89. data/spec/fixtures/views/test_view/test-map.js +3 -0
  90. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  91. data/spec/spec.opts +6 -0
  92. data/spec/spec_helper.rb +37 -0
  93. data/utils/remap.rb +27 -0
  94. data/utils/subset.rb +30 -0
  95. metadata +194 -0
@@ -0,0 +1,53 @@
1
+ module CouchRest
2
+ module Mixins
3
+ module DocumentQueries
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ # Load all documents that have the "couchrest-type" field equal to the
12
+ # name of the current class. Take the standard set of
13
+ # CouchRest::Database#view options.
14
+ def all(opts = {}, &block)
15
+ view(:all, {:reduce => false}.merge(opts), &block)
16
+ end
17
+
18
+ # Returns the number of documents that have the "couchrest-type" field
19
+ # equal to the name of the current class. Takes the standard set of
20
+ # CouchRest::Database#view options
21
+ def count(opts = {}, &block)
22
+ result = all({:reduce => true}.merge(opts), &block)['rows']
23
+ return 0 if result.empty?
24
+ result.first['value']
25
+ end
26
+
27
+ # Load the first document that have the "couchrest-type" field equal to
28
+ # the name of the current class.
29
+ #
30
+ # ==== Returns
31
+ # Object:: The first object instance available
32
+ # or
33
+ # Nil:: if no instances available
34
+ #
35
+ # ==== Parameters
36
+ # opts<Hash>::
37
+ # View options, see <tt>CouchRest::Database#view</tt> options for more info.
38
+ def first(opts = {})
39
+ first_instance = self.all(opts.merge!(:limit => 1))
40
+ first_instance.empty? ? nil : first_instance.first
41
+ end
42
+
43
+ # Load a document from the database by id
44
+ def get(id, db = database)
45
+ doc = db.get id
46
+ new(doc)
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -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,125 @@
1
+ require 'time'
2
+ require File.join(File.dirname(__FILE__), '..', 'more', 'property')
3
+
4
+ module CouchRest
5
+ module Mixins
6
+ module Properties
7
+
8
+ class IncludeError < StandardError; end
9
+
10
+ def self.included(base)
11
+ base.class_eval <<-EOS, __FILE__, __LINE__
12
+ extlib_inheritable_accessor(:properties) unless self.respond_to?(:properties)
13
+ self.properties ||= []
14
+ EOS
15
+ base.extend(ClassMethods)
16
+ 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?(:[]=))
17
+ end
18
+
19
+ def apply_defaults
20
+ return if self.respond_to?(:new_document?) && (new_document? == false)
21
+ return unless self.class.respond_to?(:properties)
22
+ return if self.class.properties.empty?
23
+ # TODO: cache the default object
24
+ self.class.properties.each do |property|
25
+ key = property.name.to_s
26
+ # let's make sure we have a default
27
+ unless property.default.nil?
28
+ if property.default.class == Proc
29
+ self[key] = property.default.call
30
+ else
31
+ self[key] = Marshal.load(Marshal.dump(property.default))
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def cast_keys
38
+ return unless self.class.properties
39
+ self.class.properties.each do |property|
40
+ next unless property.casted
41
+ key = self.has_key?(property.name) ? property.name : property.name.to_sym
42
+ # Don't cast the property unless it has a value
43
+ next unless self[key]
44
+ target = property.type
45
+ if target.is_a?(Array)
46
+ klass = ::CouchRest.constantize(target[0])
47
+ self[property.name] = self[key].collect do |value|
48
+ # Auto parse Time objects
49
+ obj = ( (property.init_method == 'new') && klass == Time) ? Time.parse(value) : klass.send(property.init_method, value)
50
+ obj.casted_by = self if obj.respond_to?(:casted_by)
51
+ obj
52
+ end
53
+ else
54
+ # Auto parse Time objects
55
+ self[property.name] = if ((property.init_method == 'new') && target == 'Time')
56
+ self[key].is_a?(String) ? Time.parse(self[key].dup) : self[key]
57
+ else
58
+ # Let people use :send as a Time parse arg
59
+ klass = ::CouchRest.constantize(target)
60
+ klass.send(property.init_method, self[key].dup)
61
+ end
62
+ self[property.name].casted_by = self if self[property.name].respond_to?(:casted_by)
63
+ end
64
+ end
65
+ end
66
+
67
+ module ClassMethods
68
+
69
+ def property(name, options={})
70
+ existing_property = self.properties.find{|p| p.name == name.to_s}
71
+ if existing_property.nil? || (existing_property.default != options[:default])
72
+ define_property(name, options)
73
+ end
74
+ end
75
+
76
+ protected
77
+
78
+ # This is not a thread safe operation, if you have to set new properties at runtime
79
+ # make sure to use a mutex.
80
+ def define_property(name, options={})
81
+ # check if this property is going to casted
82
+ options[:casted] = options[:cast_as] ? options[:cast_as] : false
83
+ property = CouchRest::Property.new(name, (options.delete(:cast_as) || options.delete(:type)), options)
84
+ create_property_getter(property)
85
+ create_property_setter(property) unless property.read_only == true
86
+ properties << property
87
+ end
88
+
89
+ # defines the getter for the property (and optional aliases)
90
+ def create_property_getter(property)
91
+ # meth = property.name
92
+ class_eval <<-EOS, __FILE__, __LINE__
93
+ def #{property.name}
94
+ self['#{property.name}']
95
+ end
96
+ EOS
97
+
98
+ if property.alias
99
+ class_eval <<-EOS, __FILE__, __LINE__
100
+ alias #{property.alias.to_sym} #{property.name.to_sym}
101
+ EOS
102
+ end
103
+ end
104
+
105
+ # defines the setter for the property (and optional aliases)
106
+ def create_property_setter(property)
107
+ meth = property.name
108
+ class_eval <<-EOS
109
+ def #{meth}=(value)
110
+ self['#{meth}'] = value
111
+ end
112
+ EOS
113
+
114
+ if property.alias
115
+ class_eval <<-EOS
116
+ alias #{property.alias.to_sym}= #{meth.to_sym}=
117
+ EOS
118
+ end
119
+ end
120
+
121
+ end # module ClassMethods
122
+
123
+ end
124
+ end
125
+ 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