samlown-couchrest_extended_document 1.0.1 → 1.0.3
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.
- 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
|