samlown-couchrest_extended_document 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +13 -1
- data/Rakefile +1 -1
- data/history.txt +19 -1
- data/lib/couchrest/extended_document.rb +14 -17
- data/lib/couchrest/mixins.rb +0 -1
- data/lib/couchrest/mixins/extended_attachments.rb +7 -5
- data/lib/couchrest/mixins/properties.rb +11 -3
- data/lib/couchrest/property.rb +1 -1
- data/lib/couchrest/support/couchrest.rb +0 -37
- data/lib/couchrest/typecast.rb +2 -2
- data/lib/couchrest/validation.rb +245 -0
- data/lib/couchrest/validation/validation_errors.rb +1 -1
- data/lib/couchrest/validation/validators/format_validator.rb +1 -1
- data/lib/couchrest/validation/validators/length_validator.rb +1 -1
- data/lib/couchrest_extended_document.rb +21 -0
- data/spec/couchrest/extended_doc_attachment_spec.rb +14 -1
- data/spec/couchrest/extended_doc_spec.rb +39 -0
- data/spec/fixtures/more/cat.rb +2 -2
- data/spec/spec_helper.rb +1 -1
- metadata +5 -3
data/README.md
CHANGED
@@ -11,7 +11,9 @@ Note: CouchRest only supports CouchDB 0.9.0 or newer.
|
|
11
11
|
|
12
12
|
## Usage
|
13
13
|
|
14
|
-
|
14
|
+
### General
|
15
|
+
|
16
|
+
require 'couchrest_extended_document'
|
15
17
|
|
16
18
|
class Cat < CouchRest::ExtendedDocument
|
17
19
|
|
@@ -19,6 +21,16 @@ Note: CouchRest only supports CouchDB 0.9.0 or newer.
|
|
19
21
|
|
20
22
|
end
|
21
23
|
|
24
|
+
### Rails
|
25
|
+
|
26
|
+
In your environment.rb file require the gem as follows:
|
27
|
+
|
28
|
+
Rails::Initializer.run do |config|
|
29
|
+
....
|
30
|
+
config.gem "couchrest_extended_document"
|
31
|
+
....
|
32
|
+
end
|
33
|
+
|
22
34
|
## Testing
|
23
35
|
|
24
36
|
The most complete documentation is the spec/ directory. To validate your
|
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require "rake/rdoctask"
|
3
|
-
require File.join(File.expand_path(File.dirname(__FILE__)),'lib','
|
3
|
+
require File.join(File.expand_path(File.dirname(__FILE__)),'lib','couchrest_extended_document')
|
4
4
|
|
5
5
|
begin
|
6
6
|
require 'spec/rake/spectask'
|
data/history.txt
CHANGED
@@ -4,11 +4,29 @@
|
|
4
4
|
|
5
5
|
* Minor enhancements
|
6
6
|
|
7
|
-
== 0.
|
7
|
+
== 1.0.3
|
8
|
+
|
9
|
+
* Minor enhancements
|
10
|
+
* Removed Validation by default, requires too many structure changes (FAIL)
|
11
|
+
* Added support for instantiation of documents read from database as couchrest-type provided (Sam Lown)
|
12
|
+
* Improved attachment handling for detecting file type (Sam Lown)
|
13
|
+
* Removing some monkey patches and relying on active_support for constantize and humanize (Sam Lown)
|
14
|
+
* Added support for setting type directly on property (Sam Lown)
|
15
|
+
|
16
|
+
|
17
|
+
== 1.0.2
|
18
|
+
|
19
|
+
* Minor enhancements
|
20
|
+
* Enable Validation by default and refactored location (Sam Lown)
|
21
|
+
|
22
|
+
== 1.0.0
|
8
23
|
|
9
24
|
* Major enhancements
|
10
25
|
* Separated ExtendedDocument from main CouchRest gem (Sam Lown)
|
11
26
|
|
27
|
+
* Minor enhancements
|
28
|
+
* active_support included by default
|
29
|
+
|
12
30
|
== 0.37
|
13
31
|
|
14
32
|
* Minor enhancements
|
@@ -1,22 +1,14 @@
|
|
1
|
-
|
2
|
-
require 'couchrest'
|
3
|
-
require 'active_support'
|
4
|
-
require 'mime/types'
|
5
|
-
require "enumerator"
|
1
|
+
|
6
2
|
require File.join(File.dirname(__FILE__), "property")
|
3
|
+
require File.join(File.dirname(__FILE__), "validation")
|
7
4
|
require File.join(File.dirname(__FILE__), 'mixins')
|
8
|
-
require File.join(File.dirname(__FILE__), 'casted_model')
|
9
|
-
|
10
|
-
# Monkey patches
|
11
|
-
require File.join(File.dirname(__FILE__), 'support', 'couchrest')
|
12
|
-
require File.join(File.dirname(__FILE__), 'support', 'rails') if defined?(Rails)
|
13
5
|
|
14
6
|
module CouchRest
|
15
7
|
|
16
8
|
# Same as CouchRest::Document but with properties and validations
|
17
9
|
class ExtendedDocument < Document
|
18
10
|
|
19
|
-
VERSION = "1.0.
|
11
|
+
VERSION = "1.0.3"
|
20
12
|
|
21
13
|
include CouchRest::Mixins::Callbacks
|
22
14
|
include CouchRest::Mixins::DocumentQueries
|
@@ -27,6 +19,9 @@ module CouchRest
|
|
27
19
|
include CouchRest::Mixins::Collection
|
28
20
|
include CouchRest::Mixins::AttributeProtection
|
29
21
|
|
22
|
+
# Including validation here does not work due to the way inheritance is handled.
|
23
|
+
#include CouchRest::Validation
|
24
|
+
|
30
25
|
def self.subclasses
|
31
26
|
@subclasses ||= []
|
32
27
|
end
|
@@ -54,17 +49,19 @@ module CouchRest
|
|
54
49
|
|
55
50
|
# Creates a new instance, bypassing attribute protection
|
56
51
|
#
|
52
|
+
#
|
57
53
|
# ==== Returns
|
58
54
|
# a document instance
|
59
|
-
def self.create_from_database(
|
60
|
-
|
55
|
+
def self.create_from_database(doc = {})
|
56
|
+
base = (doc['couchrest-type'].blank? || doc['couchrest-type'] == self.to_s) ? self : doc['couchrest-type'].constantize
|
57
|
+
base.new(doc, :directly_set_attributes => true)
|
61
58
|
end
|
62
59
|
|
63
|
-
def initialize(
|
60
|
+
def initialize(doc = {}, options = {})
|
64
61
|
apply_defaults # defined in CouchRest::Mixins::Properties
|
65
|
-
remove_protected_attributes(
|
66
|
-
directly_set_attributes(
|
67
|
-
super(
|
62
|
+
remove_protected_attributes(doc) unless options[:directly_set_attributes]
|
63
|
+
directly_set_attributes(doc) unless doc.nil?
|
64
|
+
super(doc)
|
68
65
|
cast_keys # defined in CouchRest::Mixins::Properties
|
69
66
|
unless self['_id'] && self['_rev']
|
70
67
|
self['couchrest-type'] = self.class.to_s
|
data/lib/couchrest/mixins.rb
CHANGED
@@ -5,7 +5,6 @@ require File.join(mixins_dir, 'properties')
|
|
5
5
|
require File.join(mixins_dir, 'document_queries')
|
6
6
|
require File.join(mixins_dir, 'views')
|
7
7
|
require File.join(mixins_dir, 'design_doc')
|
8
|
-
require File.join(mixins_dir, 'validation')
|
9
8
|
require File.join(mixins_dir, 'extended_attachments')
|
10
9
|
require File.join(mixins_dir, 'class_proxy')
|
11
10
|
require File.join(mixins_dir, 'collection')
|
@@ -2,7 +2,8 @@ module CouchRest
|
|
2
2
|
module Mixins
|
3
3
|
module ExtendedAttachments
|
4
4
|
|
5
|
-
#
|
5
|
+
# Add a file attachment to the current document. Expects
|
6
|
+
# :file and :name to be included in the arguments.
|
6
7
|
def create_attachment(args={})
|
7
8
|
raise ArgumentError unless args[:file] && args[:name]
|
8
9
|
return if has_attachment?(args[:name])
|
@@ -52,13 +53,14 @@ module CouchRest
|
|
52
53
|
|
53
54
|
private
|
54
55
|
|
55
|
-
def get_mime_type(
|
56
|
-
::MIME::Types.type_for(
|
57
|
-
|
56
|
+
def get_mime_type(path)
|
57
|
+
type = ::MIME::Types.type_for(path)
|
58
|
+
type.empty? ? nil : type.first.content_type
|
58
59
|
end
|
59
60
|
|
60
61
|
def set_attachment_attr(args)
|
61
|
-
content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file])
|
62
|
+
content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file].path)
|
63
|
+
content_type ||= (get_mime_type(args[:name]) || 'text/plain')
|
62
64
|
self['_attachments'][args[:name]] = {
|
63
65
|
'content_type' => content_type,
|
64
66
|
'data' => args[:file].read
|
@@ -82,10 +82,18 @@ module CouchRest
|
|
82
82
|
|
83
83
|
module ClassMethods
|
84
84
|
|
85
|
-
def property(name, options
|
85
|
+
def property(name, *options)
|
86
|
+
opts = { }
|
87
|
+
type = options.shift
|
88
|
+
if type.class != Hash
|
89
|
+
opts[:type] = type
|
90
|
+
opts.merge!(options.shift || {})
|
91
|
+
else
|
92
|
+
opts.update(type)
|
93
|
+
end
|
86
94
|
existing_property = self.properties.find{|p| p.name == name.to_s}
|
87
|
-
if existing_property.nil? || (existing_property.default !=
|
88
|
-
define_property(name,
|
95
|
+
if existing_property.nil? || (existing_property.default != opts[:default])
|
96
|
+
define_property(name, opts)
|
89
97
|
end
|
90
98
|
end
|
91
99
|
|
data/lib/couchrest/property.rb
CHANGED
@@ -1,43 +1,6 @@
|
|
1
1
|
|
2
2
|
module CouchRest
|
3
3
|
|
4
|
-
|
5
|
-
# The CouchRest module methods handle the basic JSON serialization
|
6
|
-
# and deserialization, as well as query parameters. The module also includes
|
7
|
-
# some helpers for tasks like instantiating a new Database or Server instance.
|
8
|
-
class << self
|
9
|
-
|
10
|
-
# extracted from Extlib
|
11
|
-
#
|
12
|
-
# Constantize tries to find a declared constant with the name specified
|
13
|
-
# in the string. It raises a NameError when the name is not in CamelCase
|
14
|
-
# or is not initialized.
|
15
|
-
#
|
16
|
-
# @example
|
17
|
-
# "Module".constantize #=> Module
|
18
|
-
# "Class".constantize #=> Class
|
19
|
-
def constantize(camel_cased_word)
|
20
|
-
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
|
21
|
-
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
|
22
|
-
end
|
23
|
-
|
24
|
-
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
25
|
-
end
|
26
|
-
|
27
|
-
# extracted from Extlib
|
28
|
-
#
|
29
|
-
# Capitalizes the first word and turns underscores into spaces and strips _id.
|
30
|
-
# Like titleize, this is meant for creating pretty output.
|
31
|
-
#
|
32
|
-
# @example
|
33
|
-
# "employee_salary" #=> "Employee salary"
|
34
|
-
# "author_id" #=> "Author"
|
35
|
-
def humanize(lower_case_and_underscored_word)
|
36
|
-
lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
4
|
class Database
|
42
5
|
|
43
6
|
alias :delete_old! :delete!
|
data/lib/couchrest/typecast.rb
CHANGED
@@ -28,7 +28,7 @@ module CouchRest
|
|
28
28
|
|
29
29
|
def typecast_value(value, klass, init_method)
|
30
30
|
return nil if value.nil?
|
31
|
-
klass =
|
31
|
+
klass = klass.constantize unless klass.is_a?(Class)
|
32
32
|
if value.instance_of?(klass) || klass == Object
|
33
33
|
value
|
34
34
|
elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass)
|
@@ -164,7 +164,7 @@ module CouchRest
|
|
164
164
|
|
165
165
|
# Typecast a value to a Class
|
166
166
|
def typecast_to_class(value)
|
167
|
-
|
167
|
+
value.to_s.constantize
|
168
168
|
rescue NameError
|
169
169
|
value
|
170
170
|
end
|
@@ -0,0 +1,245 @@
|
|
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
|
+
|
32
|
+
dir = File.join(Pathname(__FILE__).dirname.expand_path, 'validation')
|
33
|
+
|
34
|
+
require File.join(dir, 'validation_errors')
|
35
|
+
require File.join(dir, 'contextual_validators')
|
36
|
+
require File.join(dir, 'auto_validate')
|
37
|
+
|
38
|
+
require File.join(dir, 'validators', 'generic_validator')
|
39
|
+
require File.join(dir, 'validators', 'required_field_validator')
|
40
|
+
require File.join(dir, 'validators', 'absent_field_validator')
|
41
|
+
require File.join(dir, 'validators', 'format_validator')
|
42
|
+
require File.join(dir, 'validators', 'length_validator')
|
43
|
+
require File.join(dir, 'validators', 'numeric_validator')
|
44
|
+
require File.join(dir, 'validators', 'method_validator')
|
45
|
+
require File.join(dir, 'validators', 'confirmation_validator')
|
46
|
+
|
47
|
+
module CouchRest
|
48
|
+
module Validation
|
49
|
+
|
50
|
+
def self.included(base)
|
51
|
+
base.extlib_inheritable_accessor(:auto_validation)
|
52
|
+
base.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
53
|
+
# Callbacks
|
54
|
+
define_callbacks :validate
|
55
|
+
|
56
|
+
# Turn off auto validation by default
|
57
|
+
self.auto_validation ||= false
|
58
|
+
|
59
|
+
# Force the auto validation for the class properties
|
60
|
+
# This feature is still not fully ported over,
|
61
|
+
# test are lacking, so please use with caution
|
62
|
+
def self.auto_validate!
|
63
|
+
self.auto_validation = true
|
64
|
+
end
|
65
|
+
|
66
|
+
# share the validations with subclasses
|
67
|
+
def self.inherited(subklass)
|
68
|
+
self.validators.contexts.each do |k, v|
|
69
|
+
subklass.validators.contexts[k] = v.dup
|
70
|
+
end
|
71
|
+
super
|
72
|
+
end
|
73
|
+
EOS
|
74
|
+
|
75
|
+
base.extend(ClassMethods)
|
76
|
+
base.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
77
|
+
define_callbacks :validate
|
78
|
+
if method_defined?(:_run_save_callbacks)
|
79
|
+
set_callback :save, :before, :check_validations
|
80
|
+
end
|
81
|
+
EOS
|
82
|
+
base.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
83
|
+
def self.define_property(name, options={})
|
84
|
+
super
|
85
|
+
auto_generate_validations(properties.last) if properties && properties.size > 0
|
86
|
+
autovalidation_check = true
|
87
|
+
end
|
88
|
+
RUBY_EVAL
|
89
|
+
end
|
90
|
+
|
91
|
+
# Ensures the object is valid for the context provided, and otherwise
|
92
|
+
# throws :halt and returns false.
|
93
|
+
#
|
94
|
+
def check_validations(context = :default)
|
95
|
+
throw(:halt, false) unless context.nil? || valid?(context)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Return the ValidationErrors
|
99
|
+
#
|
100
|
+
def errors
|
101
|
+
@errors ||= ValidationErrors.new
|
102
|
+
end
|
103
|
+
|
104
|
+
# Mark this resource as validatable. When we validate associations of a
|
105
|
+
# resource we can check if they respond to validatable? before trying to
|
106
|
+
# recursivly validate them
|
107
|
+
#
|
108
|
+
def validatable?
|
109
|
+
true
|
110
|
+
end
|
111
|
+
|
112
|
+
# Alias for valid?(:default)
|
113
|
+
#
|
114
|
+
def valid_for_default?
|
115
|
+
valid?(:default)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Check if a resource is valid in a given context
|
119
|
+
#
|
120
|
+
def valid?(context = :default)
|
121
|
+
recursive_valid?(self, context, true)
|
122
|
+
end
|
123
|
+
|
124
|
+
# checking on casted objects
|
125
|
+
def validate_casted_arrays
|
126
|
+
result = true
|
127
|
+
array_casted_properties = self.class.properties.select { |property| property.casted && property.type.instance_of?(Array) }
|
128
|
+
array_casted_properties.each do |property|
|
129
|
+
casted_values = self.send(property.name)
|
130
|
+
next unless casted_values.is_a?(Array) && casted_values.first.respond_to?(:valid?)
|
131
|
+
casted_values.each do |value|
|
132
|
+
result = (result && value.valid?) if value.respond_to?(:valid?)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
result
|
136
|
+
end
|
137
|
+
|
138
|
+
# Do recursive validity checking
|
139
|
+
#
|
140
|
+
def recursive_valid?(target, context, state)
|
141
|
+
valid = state
|
142
|
+
target.each do |key, prop|
|
143
|
+
if prop.is_a?(Array)
|
144
|
+
prop.each do |item|
|
145
|
+
if item.validatable?
|
146
|
+
valid = recursive_valid?(item, context, valid) && valid
|
147
|
+
end
|
148
|
+
end
|
149
|
+
elsif prop.validatable?
|
150
|
+
valid = recursive_valid?(prop, context, valid) && valid
|
151
|
+
end
|
152
|
+
end
|
153
|
+
target._run_validate_callbacks do
|
154
|
+
target.class.validators.execute(context, target) && valid
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
def validation_property_value(name)
|
160
|
+
self.respond_to?(name, true) ? self.send(name) : nil
|
161
|
+
end
|
162
|
+
|
163
|
+
# Get the corresponding Object property, if it exists.
|
164
|
+
def validation_property(field_name)
|
165
|
+
properties.find{|p| p.name == field_name}
|
166
|
+
end
|
167
|
+
|
168
|
+
module ClassMethods
|
169
|
+
include CouchRest::Validation::ValidatesPresent
|
170
|
+
include CouchRest::Validation::ValidatesAbsent
|
171
|
+
include CouchRest::Validation::ValidatesIsConfirmed
|
172
|
+
# include CouchRest::Validation::ValidatesIsPrimitive
|
173
|
+
# include CouchRest::Validation::ValidatesIsAccepted
|
174
|
+
include CouchRest::Validation::ValidatesFormat
|
175
|
+
include CouchRest::Validation::ValidatesLength
|
176
|
+
# include CouchRest::Validation::ValidatesWithin
|
177
|
+
include CouchRest::Validation::ValidatesIsNumber
|
178
|
+
include CouchRest::Validation::ValidatesWithMethod
|
179
|
+
# include CouchRest::Validation::ValidatesWithBlock
|
180
|
+
# include CouchRest::Validation::ValidatesIsUnique
|
181
|
+
include CouchRest::Validation::AutoValidate
|
182
|
+
|
183
|
+
# Return the set of contextual validators or create a new one
|
184
|
+
#
|
185
|
+
def validators
|
186
|
+
@validations ||= ContextualValidators.new
|
187
|
+
end
|
188
|
+
|
189
|
+
# Clean up the argument list and return a opts hash, including the
|
190
|
+
# merging of any default opts. Set the context to default if none is
|
191
|
+
# provided. Also allow :context to be aliased to :on, :when & group
|
192
|
+
#
|
193
|
+
def opts_from_validator_args(args, defaults = nil)
|
194
|
+
opts = args.last.kind_of?(Hash) ? args.pop : {}
|
195
|
+
context = :default
|
196
|
+
context = opts[:context] if opts.has_key?(:context)
|
197
|
+
context = opts.delete(:on) if opts.has_key?(:on)
|
198
|
+
context = opts.delete(:when) if opts.has_key?(:when)
|
199
|
+
context = opts.delete(:group) if opts.has_key?(:group)
|
200
|
+
opts[:context] = context
|
201
|
+
opts.merge!(defaults) unless defaults.nil?
|
202
|
+
opts
|
203
|
+
end
|
204
|
+
|
205
|
+
# Given a new context create an instance method of
|
206
|
+
# valid_for_<context>? which simply calls valid?(context)
|
207
|
+
# if it does not already exist
|
208
|
+
#
|
209
|
+
def create_context_instance_methods(context)
|
210
|
+
name = "valid_for_#{context.to_s}?" # valid_for_signup?
|
211
|
+
if !self.instance_methods.include?(name)
|
212
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
213
|
+
def #{name} # def valid_for_signup?
|
214
|
+
valid?('#{context.to_s}'.to_sym) # valid?('signup'.to_sym)
|
215
|
+
end # end
|
216
|
+
EOS
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Create a new validator of the given klazz and push it onto the
|
221
|
+
# requested context for each of the attributes in the fields list
|
222
|
+
#
|
223
|
+
def add_validator_to_context(opts, fields, klazz)
|
224
|
+
fields.each do |field|
|
225
|
+
validator = klazz.new(field.to_sym, opts)
|
226
|
+
if opts[:context].is_a?(Symbol)
|
227
|
+
unless validators.context(opts[:context]).include?(validator)
|
228
|
+
validators.context(opts[:context]) << validator
|
229
|
+
create_context_instance_methods(opts[:context])
|
230
|
+
end
|
231
|
+
elsif opts[:context].is_a?(Array)
|
232
|
+
opts[:context].each do |c|
|
233
|
+
unless validators.context(c).include?(validator)
|
234
|
+
validators.context(c) << validator
|
235
|
+
create_context_instance_methods(c)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
end # module ClassMethods
|
243
|
+
end # module Validation
|
244
|
+
|
245
|
+
end # module CouchRest
|
@@ -64,7 +64,7 @@ module CouchRest
|
|
64
64
|
|
65
65
|
error_message = @options[:message] || ValidationErrors.default_error_message(:invalid, field_name)
|
66
66
|
|
67
|
-
field =
|
67
|
+
field = field_name.to_s.humanize
|
68
68
|
error_message = error_message.call(field, value) if error_message.respond_to?(:call)
|
69
69
|
|
70
70
|
add_error(target, error_message, field_name)
|
@@ -54,7 +54,7 @@ module CouchRest
|
|
54
54
|
|
55
55
|
# XXX: HACK seems hacky to do this on every validation, probably should
|
56
56
|
# do this elsewhere?
|
57
|
-
field =
|
57
|
+
field = field_name.to_s.humanize
|
58
58
|
min = @range ? @range.min : @min
|
59
59
|
max = @range ? @range.max : @max
|
60
60
|
equal = @equal
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
# require File.join(File.dirname(__FILE__), "couchrest", "extended_document")
|
3
|
+
|
4
|
+
gem 'samlown-couchrest'
|
5
|
+
|
6
|
+
require 'couchrest'
|
7
|
+
|
8
|
+
require 'active_support'
|
9
|
+
require 'mime/types'
|
10
|
+
require "enumerator"
|
11
|
+
|
12
|
+
# Monkey patches applied to couchrest
|
13
|
+
require File.join(File.dirname(__FILE__), 'couchrest', 'support', 'couchrest')
|
14
|
+
|
15
|
+
# Base libraries
|
16
|
+
require File.join(File.dirname(__FILE__), 'couchrest', 'extended_document')
|
17
|
+
require File.join(File.dirname(__FILE__), 'couchrest', 'casted_model')
|
18
|
+
|
19
|
+
# Add rails support *after* everything has loaded
|
20
|
+
require File.join(File.dirname(__FILE__), 'couchrest', 'support', 'rails') if defined?(Rails)
|
21
|
+
|
@@ -68,6 +68,19 @@ describe "ExtendedDocument attachments" do
|
|
68
68
|
@obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
|
69
69
|
@obj['_attachments'][@attachment_name]['content_type'].should == @content_type
|
70
70
|
end
|
71
|
+
|
72
|
+
it "should detect the content-type automatically" do
|
73
|
+
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
74
|
+
@obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should use name to detect the content-type automatically if no file" do
|
78
|
+
file = File.open(FIXTURE_PATH + '/attachments/couchdb.png')
|
79
|
+
file.stub!(:path).and_return("badfilname")
|
80
|
+
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
81
|
+
@obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
|
82
|
+
end
|
83
|
+
|
71
84
|
end
|
72
85
|
|
73
86
|
describe 'reading, updating, and deleting an attachment' do
|
@@ -96,7 +109,7 @@ describe "ExtendedDocument attachments" do
|
|
96
109
|
reloaded_obj.read_attachment(@attachment_name).should == file.read
|
97
110
|
end
|
98
111
|
|
99
|
-
it 'should
|
112
|
+
it 'should set the content-type if passed' do
|
100
113
|
file = File.open(FIXTURE_PATH + '/attachments/README')
|
101
114
|
@file.should_not == file
|
102
115
|
@obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
|
@@ -18,6 +18,14 @@ describe "ExtendedDocument" do
|
|
18
18
|
property :name
|
19
19
|
timestamps!
|
20
20
|
end
|
21
|
+
|
22
|
+
class WithSimplePropertyType < CouchRest::ExtendedDocument
|
23
|
+
use_database TEST_SERVER.default_database
|
24
|
+
property :name, String
|
25
|
+
property :preset, String, :default => 'none'
|
26
|
+
property :tags, [String]
|
27
|
+
timestamps!
|
28
|
+
end
|
21
29
|
|
22
30
|
class WithCallBacks < CouchRest::ExtendedDocument
|
23
31
|
include ::CouchRest::Validation
|
@@ -164,6 +172,25 @@ describe "ExtendedDocument" do
|
|
164
172
|
doc.run_after_save.should be_true
|
165
173
|
end
|
166
174
|
end
|
175
|
+
|
176
|
+
describe "creating a new document from database" do
|
177
|
+
|
178
|
+
it "should instantialize" do
|
179
|
+
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'couchrest-type' => 'Article', 'name' => 'my test'})
|
180
|
+
doc.class.should eql(Article)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should instantialize of same class if no couchrest-type included from DB" do
|
184
|
+
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'name' => 'my test'})
|
185
|
+
doc.class.should eql(Article)
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should instantialize document of different type" do
|
189
|
+
doc = Article.create_from_database({'_id' => 'testitem2', '_rev' => 123, 'couchrest-type' => 'WithCallBacks', 'name' => 'my test'})
|
190
|
+
doc.class.should eql(WithCallBacks)
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
167
194
|
|
168
195
|
describe "update attributes without saving" do
|
169
196
|
before(:each) do
|
@@ -258,6 +285,18 @@ describe "ExtendedDocument" do
|
|
258
285
|
obj.read_only_with_default.should == 'generic'
|
259
286
|
end
|
260
287
|
end
|
288
|
+
|
289
|
+
describe "simplified way of setting property types" do
|
290
|
+
it "should set defaults" do
|
291
|
+
obj = WithSimplePropertyType.new
|
292
|
+
obj.preset.should eql('none')
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should handle arrays" do
|
296
|
+
obj = WithSimplePropertyType.new(:tags => ['spec'])
|
297
|
+
obj.tags.should == ['spec']
|
298
|
+
end
|
299
|
+
end
|
261
300
|
|
262
301
|
describe "a doc with template values (CR::Model spec)" do
|
263
302
|
before(:all) do
|
data/spec/fixtures/more/cat.rb
CHANGED
@@ -15,8 +15,8 @@ class Cat < CouchRest::ExtendedDocument
|
|
15
15
|
use_database DB
|
16
16
|
|
17
17
|
property :name, :accessible => true
|
18
|
-
property :toys,
|
19
|
-
property :favorite_toy,
|
18
|
+
property :toys, [CatToy], :default => [], :accessible => true
|
19
|
+
property :favorite_toy, CatToy, :accessible => true
|
20
20
|
property :number
|
21
21
|
end
|
22
22
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "spec" # Satisfies Autotest and anyone else not using the Rake tasks
|
3
3
|
|
4
|
-
require File.join(File.dirname(__FILE__), '..','lib','
|
4
|
+
require File.join(File.dirname(__FILE__), '..','lib','couchrest_extended_document')
|
5
5
|
# check the following file to see how to use the spec'd features.
|
6
6
|
|
7
7
|
unless defined?(FIXTURE_PATH)
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 1.0.
|
8
|
+
- 3
|
9
|
+
version: 1.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- J. Chris Anderson
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2010-05-
|
20
|
+
date: 2010-05-13 00:00:00 +02:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- lib/couchrest/support/couchrest.rb
|
97
97
|
- lib/couchrest/support/rails.rb
|
98
98
|
- lib/couchrest/typecast.rb
|
99
|
+
- lib/couchrest/validation.rb
|
99
100
|
- lib/couchrest/validation/auto_validate.rb
|
100
101
|
- lib/couchrest/validation/contextual_validators.rb
|
101
102
|
- lib/couchrest/validation/validation_errors.rb
|
@@ -109,6 +110,7 @@ files:
|
|
109
110
|
- lib/couchrest/validation/validators/method_validator.rb
|
110
111
|
- lib/couchrest/validation/validators/numeric_validator.rb
|
111
112
|
- lib/couchrest/validation/validators/required_field_validator.rb
|
113
|
+
- lib/couchrest_extended_document.rb
|
112
114
|
- spec/couchrest/attribute_protection_spec.rb
|
113
115
|
- spec/couchrest/casted_extended_doc_spec.rb
|
114
116
|
- spec/couchrest/casted_model_spec.rb
|