jchris-couchrest 0.17.0 → 0.22

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/lib/couchrest.rb CHANGED
@@ -28,7 +28,7 @@ require 'couchrest/monkeypatches'
28
28
 
29
29
  # = CouchDB, close to the metal
30
30
  module CouchRest
31
- VERSION = '0.17.0' unless self.const_defined?("VERSION")
31
+ VERSION = '0.22' unless self.const_defined?("VERSION")
32
32
 
33
33
  autoload :Server, 'couchrest/core/server'
34
34
  autoload :Database, 'couchrest/core/database'
@@ -69,6 +69,18 @@ module CouchRest
69
69
  Object.module_eval("::#{$1}", __FILE__, __LINE__)
70
70
  end
71
71
 
72
+ # extracted from Extlib
73
+ #
74
+ # Capitalizes the first word and turns underscores into spaces and strips _id.
75
+ # Like titleize, this is meant for creating pretty output.
76
+ #
77
+ # @example
78
+ # "employee_salary" #=> "Employee salary"
79
+ # "author_id" #=> "Author"
80
+ def humanize(lower_case_and_underscored_word)
81
+ lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
82
+ end
83
+
72
84
  # todo, make this parse the url and instantiate a Server or Database instance
73
85
  # depending on the specificity.
74
86
  def new(*opts)
@@ -171,10 +183,6 @@ module CouchRest
171
183
  def copy uri, destination
172
184
  JSON.parse(RestClient.copy(uri, {'Destination' => destination}))
173
185
  end
174
-
175
- def move uri, destination
176
- JSON.parse(RestClient.move(uri, {'Destination' => destination}))
177
- end
178
186
 
179
187
  def paramify_url url, params = {}
180
188
  if params && !params.empty?
@@ -224,26 +224,6 @@ module CouchRest
224
224
  copy_doc(doc, dest)
225
225
  end
226
226
 
227
- # MOVE an existing document to a new id. If the destination id currently exists, a rev must be provided.
228
- # <tt>dest</tt> can take one of two forms if overwriting: "id_to_overwrite?rev=revision" or the actual doc
229
- # hash with a '_rev' key
230
- def move_doc(doc, dest)
231
- raise ArgumentError, "_id and _rev are required for moving" unless doc['_id'] && doc['_rev']
232
- slug = escape_docid(doc['_id'])
233
- destination = if dest.respond_to?(:has_key?) && dest['_id'] && dest['_rev']
234
- "#{dest['_id']}?rev=#{dest['_rev']}"
235
- else
236
- dest
237
- end
238
- CouchRest.move "#{@uri}/#{slug}?rev=#{doc['_rev']}", destination
239
- end
240
-
241
- ### DEPRECATION NOTICE
242
- def move(doc, dest)
243
- puts "CouchRest::Database's move method is being deprecated, please use move_doc instead"
244
- move_doc(doc, dest)
245
- end
246
-
247
227
  # Compact the database, removing old document revisions and optimizing space use.
248
228
  def compact!
249
229
  CouchRest.post "#{@uri}/_compact"
@@ -5,10 +5,10 @@ module CouchRest
5
5
  include CouchRest::Mixins::Attachments
6
6
 
7
7
  # def self.inherited(subklass)
8
- # subklass.send(:class_inheritable_accessor, :database)
8
+ # subklass.send(:extlib_inheritable_accessor, :database)
9
9
  # end
10
10
 
11
- class_inheritable_accessor :database
11
+ extlib_inheritable_accessor :database
12
12
  attr_accessor :database
13
13
 
14
14
  # override the CouchRest::Model-wide default_database
@@ -426,10 +426,10 @@ module CouchRest
426
426
  def define_callbacks(*symbols)
427
427
  terminator = symbols.pop if symbols.last.is_a?(String)
428
428
  symbols.each do |symbol|
429
- self.class_inheritable_accessor("_#{symbol}_terminator")
429
+ self.extlib_inheritable_accessor("_#{symbol}_terminator")
430
430
  self.send("_#{symbol}_terminator=", terminator)
431
431
  self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
432
- class_inheritable_accessor :_#{symbol}_callbacks
432
+ extlib_inheritable_accessor :_#{symbol}_callbacks
433
433
  self._#{symbol}_callbacks = CallbackChain.new(:#{symbol})
434
434
 
435
435
  def self.#{symbol}_callback(*filters, &blk)
@@ -480,4 +480,4 @@ module CouchRest
480
480
  end
481
481
  end
482
482
  end
483
- end
483
+ end
@@ -1,3 +1,4 @@
1
+ require 'time'
1
2
  require File.join(File.dirname(__FILE__), '..', 'more', 'property')
2
3
 
3
4
  module CouchRest
@@ -7,10 +8,10 @@ module CouchRest
7
8
  class IncludeError < StandardError; end
8
9
 
9
10
  def self.included(base)
10
- base.cattr_accessor(:properties)
11
- base.class_eval <<-EOS, __FILE__, __LINE__
12
- @@properties = []
13
- EOS
11
+ base.class_eval <<-EOS, __FILE__, __LINE__
12
+ extlib_inheritable_accessor(:properties)
13
+ self.properties ||= []
14
+ EOS
14
15
  base.extend(ClassMethods)
15
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?(:[]=))
16
17
  end
@@ -70,7 +71,10 @@ module CouchRest
70
71
  module ClassMethods
71
72
 
72
73
  def property(name, options={})
73
- define_property(name, options) unless self.properties.map{|p| p.name}.include?(name.to_s)
74
+ existing_property = self.properties.find{|p| p.name == name.to_s}
75
+ if existing_property.nil? || (existing_property.default != options[:default])
76
+ define_property(name, options)
77
+ end
74
78
  end
75
79
 
76
80
  protected
@@ -49,10 +49,10 @@ module CouchRest
49
49
  module Validation
50
50
 
51
51
  def self.included(base)
52
- base.cattr_accessor(:auto_validation)
52
+ base.extlib_inheritable_accessor(:auto_validation)
53
53
  base.class_eval <<-EOS, __FILE__, __LINE__
54
54
  # Turn off auto validation by default
55
- @@auto_validation = false
55
+ self.auto_validation ||= false
56
56
 
57
57
  # Force the auto validation for the class properties
58
58
  # This feature is still not fully ported over,
@@ -60,6 +60,11 @@ module CouchRest
60
60
  def self.auto_validate!
61
61
  self.auto_validation = true
62
62
  end
63
+
64
+ # share the validations with subclasses
65
+ def self.inherited(subklass)
66
+ subklass.instance_variable_set(:@validations, self.validators.dup)
67
+ end
63
68
  EOS
64
69
 
65
70
  base.extend(ClassMethods)
@@ -71,7 +76,7 @@ module CouchRest
71
76
  base.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
72
77
  def self.define_property(name, options={})
73
78
  super
74
- auto_generate_validations(properties.last)
79
+ auto_generate_validations(properties.last) if properties && properties.size > 0
75
80
  autovalidation_check = true
76
81
  end
77
82
  RUBY_EVAL
@@ -4,9 +4,9 @@ module CouchRest
4
4
 
5
5
  def self.included(base)
6
6
  base.extend(ClassMethods)
7
- base.send(:class_inheritable_accessor, :design_doc)
8
- base.send(:class_inheritable_accessor, :design_doc_slug_cache)
9
- base.send(:class_inheritable_accessor, :design_doc_fresh)
7
+ base.send(:extlib_inheritable_accessor, :design_doc)
8
+ base.send(:extlib_inheritable_accessor, :design_doc_slug_cache)
9
+ base.send(:extlib_inheritable_accessor, :design_doc_fresh)
10
10
  end
11
11
 
12
12
  module ClassMethods
@@ -10,7 +10,7 @@ class Time
10
10
  # in your application.)
11
11
 
12
12
  def to_json(options = nil)
13
- u = self.utc
13
+ u = self.getutc
14
14
  %("#{u.strftime("%Y/%m/%d %H:%M:%S +0000")}")
15
15
  end
16
16
 
@@ -1,11 +1,3 @@
1
- begin
2
- # still required for Time parsing and pluralization in the validation
3
- require 'extlib'
4
- rescue
5
- puts "CouchRest::ExtendedDocument still requires extlib (not for much longer). This is left out of the gemspec on purpose."
6
- raise
7
- end
8
-
9
1
  require 'mime/types'
10
2
  require File.join(File.dirname(__FILE__), "property")
11
3
  require File.join(File.dirname(__FILE__), '..', 'mixins', 'extended_document_mixins')
@@ -22,6 +14,11 @@ module CouchRest
22
14
 
23
15
  def self.inherited(subklass)
24
16
  subklass.send(:include, CouchRest::Mixins::Properties)
17
+ subklass.class_eval <<-EOS, __FILE__, __LINE__
18
+ def self.inherited(subklass)
19
+ subklass.properties = self.properties.dup
20
+ end
21
+ EOS
25
22
  end
26
23
 
27
24
  # Accessors
@@ -25,167 +25,152 @@
25
25
  # example, an array without those additions being shared with either their
26
26
  # parent, siblings, or children, which is unlike the regular class-level
27
27
  # attributes that are shared across the entire hierarchy.
28
- module CouchRest
29
- module ClassExtension
30
- def self.included(base)
31
- if CouchRest::ClassExtension::InstanceMethods.instance_methods.all? {|m| base.respond_to?(m)}
32
- # do nothing
33
- elsif CouchRest::ClassExtension::InstanceMethods.instance_methods.any? {|m| base.respond_to?(m)}
34
- raise RuntimeError, "Conflicting extentions to Class, work it out"
35
- else
36
- base.send(:include, CouchRest::ClassExtension::InstanceMethods)
37
- end
38
- end
39
-
40
- module InstanceMethods
41
- # Defines class-level and instance-level attribute reader.
42
- #
43
- # @param *syms<Array> Array of attributes to define reader for.
44
- # @return <Array[#to_s]> List of attributes that were made into cattr_readers
45
- #
46
- # @api public
47
- #
48
- # @todo Is this inconsistent in that it does not allow you to prevent
49
- # an instance_reader via :instance_reader => false
50
- def cattr_reader(*syms)
51
- syms.flatten.each do |sym|
52
- next if sym.is_a?(Hash)
53
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
54
- unless defined? @@#{sym}
55
- @@#{sym} = nil
56
- end
57
-
58
- def self.#{sym}
59
- @@#{sym}
60
- end
61
-
62
- def #{sym}
63
- @@#{sym}
64
- end
65
- RUBY
28
+ class Class
29
+ # Defines class-level and instance-level attribute reader.
30
+ #
31
+ # @param *syms<Array> Array of attributes to define reader for.
32
+ # @return <Array[#to_s]> List of attributes that were made into cattr_readers
33
+ #
34
+ # @api public
35
+ #
36
+ # @todo Is this inconsistent in that it does not allow you to prevent
37
+ # an instance_reader via :instance_reader => false
38
+ def cattr_reader(*syms)
39
+ syms.flatten.each do |sym|
40
+ next if sym.is_a?(Hash)
41
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
42
+ unless defined? @@#{sym}
43
+ @@#{sym} = nil
66
44
  end
67
- end
68
-
69
- # Defines class-level (and optionally instance-level) attribute writer.
70
- #
71
- # @param <Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to define writer for.
72
- # @option syms :instance_writer<Boolean> if true, instance-level attribute writer is defined.
73
- # @return <Array[#to_s]> List of attributes that were made into cattr_writers
74
- #
75
- # @api public
76
- def cattr_writer(*syms)
77
- options = syms.last.is_a?(Hash) ? syms.pop : {}
78
- syms.flatten.each do |sym|
79
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
80
- unless defined? @@#{sym}
81
- @@#{sym} = nil
82
- end
83
-
84
- def self.#{sym}=(obj)
85
- @@#{sym} = obj
86
- end
87
- RUBY
88
-
89
- unless options[:instance_writer] == false
90
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
91
- def #{sym}=(obj)
92
- @@#{sym} = obj
45
+
46
+ def self.#{sym}
47
+ @@#{sym}
48
+ end
49
+
50
+ def #{sym}
51
+ @@#{sym}
52
+ end
53
+ RUBY
93
54
  end
94
- RUBY
95
- end
55
+ end unless Class.respond_to?(:cattr_reader)
56
+
57
+ # Defines class-level (and optionally instance-level) attribute writer.
58
+ #
59
+ # @param <Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to define writer for.
60
+ # @option syms :instance_writer<Boolean> if true, instance-level attribute writer is defined.
61
+ # @return <Array[#to_s]> List of attributes that were made into cattr_writers
62
+ #
63
+ # @api public
64
+ def cattr_writer(*syms)
65
+ options = syms.last.is_a?(Hash) ? syms.pop : {}
66
+ syms.flatten.each do |sym|
67
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
68
+ unless defined? @@#{sym}
69
+ @@#{sym} = nil
96
70
  end
71
+
72
+ def self.#{sym}=(obj)
73
+ @@#{sym} = obj
74
+ end
75
+ RUBY
76
+
77
+ unless options[:instance_writer] == false
78
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
79
+ def #{sym}=(obj)
80
+ @@#{sym} = obj
81
+ end
82
+ RUBY
97
83
  end
98
-
99
- # Defines class-level (and optionally instance-level) attribute accessor.
100
- #
101
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to define accessor for.
102
- # @option syms :instance_writer<Boolean> if true, instance-level attribute writer is defined.
103
- # @return <Array[#to_s]> List of attributes that were made into accessors
104
- #
105
- # @api public
106
- def cattr_accessor(*syms)
107
- cattr_reader(*syms)
108
- cattr_writer(*syms)
109
- end
110
-
111
- # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
112
- # each subclass has a copy of parent's attribute.
113
- #
114
- # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
115
- # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
116
- #
117
- # @api public
118
- #
119
- # @todo Do we want to block instance_reader via :instance_reader => false
120
- # @todo It would be preferable that we do something with a Hash passed in
121
- # (error out or do the same as other methods above) instead of silently
122
- # moving on). In particular, this makes the return value of this function
123
- # less useful.
124
- def class_inheritable_reader(*ivars)
125
- instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
126
-
127
- ivars.each do |ivar|
128
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
129
- def self.#{ivar}
130
- return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
131
- ivar = superclass.#{ivar}
132
- return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
133
- @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) && !ivar.is_a?(Symbol) ? ivar.dup : ivar
134
84
  end
135
- RUBY
136
- unless instance_reader == false
137
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
138
- def #{ivar}
139
- self.class.#{ivar}
140
- end
141
- RUBY
142
- end
85
+ end unless Class.respond_to?(:cattr_writer)
86
+
87
+ # Defines class-level (and optionally instance-level) attribute accessor.
88
+ #
89
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to define accessor for.
90
+ # @option syms :instance_writer<Boolean> if true, instance-level attribute writer is defined.
91
+ # @return <Array[#to_s]> List of attributes that were made into accessors
92
+ #
93
+ # @api public
94
+ def cattr_accessor(*syms)
95
+ cattr_reader(*syms)
96
+ cattr_writer(*syms)
97
+ end unless Class.respond_to?(:cattr_accessor)
98
+
99
+ # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
100
+ # each subclass has a copy of parent's attribute.
101
+ #
102
+ # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
103
+ # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
104
+ #
105
+ # @api public
106
+ #
107
+ # @todo Do we want to block instance_reader via :instance_reader => false
108
+ # @todo It would be preferable that we do something with a Hash passed in
109
+ # (error out or do the same as other methods above) instead of silently
110
+ # moving on). In particular, this makes the return value of this function
111
+ # less useful.
112
+ def extlib_inheritable_reader(*ivars)
113
+ instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
114
+
115
+ ivars.each do |ivar|
116
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
117
+ def self.#{ivar}
118
+ return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
119
+ ivar = superclass.#{ivar}
120
+ return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
121
+ @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
143
122
  end
123
+ RUBY
124
+ unless instance_reader == false
125
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
126
+ def #{ivar}
127
+ self.class.#{ivar}
128
+ end
129
+ RUBY
144
130
  end
145
-
146
- # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
147
- # each subclass has a copy of parent's attribute.
148
- #
149
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
150
- # define inheritable writer for.
151
- # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
152
- # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
153
- #
154
- # @api public
155
- #
156
- # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
157
- # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
158
- def class_inheritable_writer(*ivars)
159
- instance_writer = ivars.pop[:instance_writer] if ivars.last.is_a?(Hash)
160
- ivars.each do |ivar|
161
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
162
- def self.#{ivar}=(obj)
163
- @#{ivar} = obj
164
131
  end
165
- RUBY
166
- unless instance_writer == false
167
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
168
- def #{ivar}=(obj) self.class.#{ivar} = obj end
169
- RUBY
170
- end
132
+ end unless Class.respond_to?(:extlib_inheritable_reader)
133
+
134
+ # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
135
+ # each subclass has a copy of parent's attribute.
136
+ #
137
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
138
+ # define inheritable writer for.
139
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
140
+ # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
141
+ #
142
+ # @api public
143
+ #
144
+ # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
145
+ # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
146
+ def extlib_inheritable_writer(*ivars)
147
+ instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
148
+ ivars.each do |ivar|
149
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
150
+ def self.#{ivar}=(obj)
151
+ @#{ivar} = obj
171
152
  end
172
- end
173
-
174
- # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
175
- # each subclass has a copy of parent's attribute.
176
- #
177
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
178
- # define inheritable accessor for.
179
- # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
180
- # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
181
- #
182
- # @api public
183
- def class_inheritable_accessor(*syms)
184
- class_inheritable_reader(*syms)
185
- class_inheritable_writer(*syms)
153
+ RUBY
154
+ unless instance_writer == false
155
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
156
+ def #{ivar}=(obj) self.class.#{ivar} = obj end
157
+ RUBY
186
158
  end
187
159
  end
188
- end
160
+ end unless Class.respond_to?(:extlib_inheritable_writer)
161
+
162
+ # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
163
+ # each subclass has a copy of parent's attribute.
164
+ #
165
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
166
+ # define inheritable accessor for.
167
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
168
+ # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
169
+ #
170
+ # @api public
171
+ def extlib_inheritable_accessor(*syms)
172
+ extlib_inheritable_reader(*syms)
173
+ extlib_inheritable_writer(*syms)
174
+ end unless Class.respond_to?(:extlib_inheritable_accessor)
189
175
  end
190
176
 
191
- Class.send(:include, CouchRest::ClassExtension)
@@ -60,7 +60,7 @@ module CouchRest
60
60
  cattr_writer :default_error_messages
61
61
 
62
62
  def self.default_error_message(key, field, *values)
63
- field = Extlib::Inflection.humanize(field)
63
+ field = CouchRest.humanize(field)
64
64
  @@default_error_messages[key] % [field, *values].flatten
65
65
  end
66
66
 
@@ -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 = Extlib::Inflection.humanize(field_name)
67
+ field = CouchRest.humanize(field_name)
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 = Extlib::Inflection.humanize(field_name)
57
+ field = CouchRest.humanize(field_name)
58
58
  min = @range ? @range.min : @min
59
59
  max = @range ? @range.max : @max
60
60
  equal = @equal
@@ -554,50 +554,6 @@ describe CouchRest::Database do
554
554
  end
555
555
  end
556
556
 
557
- describe "MOVE existing document" do
558
- before :each do
559
- @r = @db.save_doc({'artist' => 'Zappa', 'title' => 'Muffin Man'})
560
- @docid = 'tracks/zappa/muffin-man'
561
- @doc = @db.get(@r['id'])
562
- end
563
- describe "to a new location" do
564
- it "should work" do
565
- @db.move_doc @doc, @docid
566
- newdoc = @db.get(@docid)
567
- newdoc['artist'].should == 'Zappa'
568
- lambda {@db.get(@r['id'])}.should raise_error(RestClient::ResourceNotFound)
569
- end
570
- it "should fail without an _id or _rev" do
571
- lambda{@db.move({"not"=>"a real doc"})}.should raise_error(ArgumentError)
572
- lambda{@db.move({"_id"=>"not a real doc"})}.should raise_error(ArgumentError)
573
- end
574
- end
575
- describe "to an existing location" do
576
- before :each do
577
- @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
578
- end
579
- it "should fail without a rev" do
580
- @doc.delete("_rev")
581
- lambda{@db.move_doc @doc, @docid}.should raise_error(ArgumentError)
582
- lambda{@db.get(@r['id'])}.should_not raise_error
583
- end
584
- it "should succeed with a rev" do
585
- @to_be_overwritten = @db.get(@docid)
586
- @db.move_doc @doc, "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
587
- newdoc = @db.get(@docid)
588
- newdoc['artist'].should == 'Zappa'
589
- lambda {@db.get(@r['id'])}.should raise_error(RestClient::ResourceNotFound)
590
- end
591
- it "should succeed given the doc to overwrite" do
592
- @to_be_overwritten = @db.get(@docid)
593
- @db.move_doc @doc, @to_be_overwritten
594
- newdoc = @db.get(@docid)
595
- newdoc['artist'].should == 'Zappa'
596
- lambda {@db.get(@r['id'])}.should raise_error(RestClient::ResourceNotFound)
597
- end
598
- end
599
- end
600
-
601
557
 
602
558
  it "should list documents" do
603
559
  5.times do
@@ -199,51 +199,6 @@ describe CouchRest::Document do
199
199
  end
200
200
  end
201
201
  end
202
-
203
- describe "MOVE existing document" do
204
- before :each do
205
- @db = reset_test_db!
206
- @resp = @db.save_doc({'key' => 'value'})
207
- @docid = 'new-location'
208
- @doc = @db.get(@resp['id'])
209
- end
210
- describe "to a new location" do
211
- it "should work" do
212
- @doc.move @docid
213
- newdoc = @db.get(@docid)
214
- newdoc['key'].should == 'value'
215
- lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
216
- end
217
- it "should fail without a database" do
218
- lambda{CouchRest::Document.new({"not"=>"a real doc"}).move}.should raise_error(ArgumentError)
219
- lambda{CouchRest::Document.new({"_id"=>"not a real doc"}).move}.should raise_error(ArgumentError)
220
- end
221
- end
222
- describe "to an existing location" do
223
- before :each do
224
- @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
225
- end
226
- it "should fail without a rev" do
227
- @doc.delete("_rev")
228
- lambda{@doc.move @docid}.should raise_error(ArgumentError)
229
- lambda{@db.get(@resp['id'])}.should_not raise_error
230
- end
231
- it "should succeed with a rev" do
232
- @to_be_overwritten = @db.get(@docid)
233
- @doc.move "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
234
- newdoc = @db.get(@docid)
235
- newdoc['key'].should == 'value'
236
- lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
237
- end
238
- it "should succeed given the doc to overwrite" do
239
- @to_be_overwritten = @db.get(@docid)
240
- @doc.move @to_be_overwritten
241
- newdoc = @db.get(@docid)
242
- newdoc['key'].should == 'value'
243
- lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
244
- end
245
- end
246
- end
247
202
  end
248
203
 
249
204
  describe "dealing with attachments" do
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require File.join(FIXTURE_PATH, 'more', 'card')
3
+
4
+ # add a default value
5
+ Card.property :bg_color, :default => '#ccc'
6
+
7
+ class BusinessCard < Card
8
+ property :extension_code
9
+ property :job_title
10
+ end
11
+
12
+ class DesignBusinessCard < BusinessCard
13
+ property :bg_color, :default => '#eee'
14
+ end
15
+
16
+
17
+ describe "Subclassing an ExtendedDocument" do
18
+
19
+ before(:each) do
20
+ @card = BusinessCard.new
21
+ end
22
+
23
+ it "shouldn't messup the parent's properties" do
24
+ Card.properties.should_not == BusinessCard.properties
25
+ end
26
+
27
+ it "should share the same db default" do
28
+ @card.database.uri.should == Card.database.uri
29
+ end
30
+
31
+ it "should share the same autovalidation details" do
32
+ @card.auto_validation.should be_true
33
+ end
34
+
35
+ it "should have kept the validation details" do
36
+ @card.should_not be_valid
37
+ end
38
+
39
+ it "should have added the new validation details" do
40
+ validated_fields = @card.class.validators.contexts[:default].map{|v| v.field_name}
41
+ validated_fields.should include(:extension_code)
42
+ validated_fields.should include(:job_title)
43
+ end
44
+
45
+ it "should inherit default property values" do
46
+ @card.bg_color.should == '#ccc'
47
+ end
48
+
49
+ it "should be able to overwrite a default property" do
50
+ DesignBusinessCard.new.bg_color.should == '#eee'
51
+ end
52
+
53
+ end
54
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jchris-couchrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: "0.22"
5
5
  platform: ruby
6
6
  authors:
7
7
  - J. Chris Anderson
@@ -141,15 +141,34 @@ files:
141
141
  - spec/couchrest/more/casted_model_spec.rb
142
142
  - spec/couchrest/more/extended_doc_attachment_spec.rb
143
143
  - spec/couchrest/more/extended_doc_spec.rb
144
+ - spec/couchrest/more/extended_doc_subclass_spec.rb
144
145
  - spec/couchrest/more/extended_doc_view_spec.rb
145
146
  - spec/couchrest/more/property_spec.rb
146
- - spec/couchrest/support
147
- - spec/couchrest/support/class_spec.rb
148
147
  - spec/fixtures
149
148
  - spec/fixtures/attachments
150
149
  - spec/fixtures/attachments/couchdb.png
151
150
  - spec/fixtures/attachments/README
152
151
  - spec/fixtures/attachments/test.html
152
+ - spec/fixtures/couchapp
153
+ - spec/fixtures/couchapp/_attachments
154
+ - spec/fixtures/couchapp/_attachments/index.html
155
+ - spec/fixtures/couchapp/doc.json
156
+ - spec/fixtures/couchapp/foo
157
+ - spec/fixtures/couchapp/foo/bar.txt
158
+ - spec/fixtures/couchapp/foo/test.json
159
+ - spec/fixtures/couchapp/test.json
160
+ - spec/fixtures/couchapp/views
161
+ - spec/fixtures/couchapp/views/example-map.js
162
+ - spec/fixtures/couchapp/views/example-reduce.js
163
+ - spec/fixtures/couchapp-test
164
+ - spec/fixtures/couchapp-test/my-app
165
+ - spec/fixtures/couchapp-test/my-app/_attachments
166
+ - spec/fixtures/couchapp-test/my-app/_attachments/index.html
167
+ - spec/fixtures/couchapp-test/my-app/foo
168
+ - spec/fixtures/couchapp-test/my-app/foo/bar.txt
169
+ - spec/fixtures/couchapp-test/my-app/views
170
+ - spec/fixtures/couchapp-test/my-app/views/example-map.js
171
+ - spec/fixtures/couchapp-test/my-app/views/example-reduce.js
153
172
  - spec/fixtures/more
154
173
  - spec/fixtures/more/article.rb
155
174
  - spec/fixtures/more/card.rb
@@ -1,59 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
- require File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'couchrest', 'support', 'class')
3
-
4
- describe CouchRest::ClassExtension do
5
-
6
- before :all do
7
- class FullyDefinedClassExtensions
8
- def self.respond_to?(method)
9
- if CouchRest::ClassExtension::InstanceMethods.instance_methods.include?(method)
10
- true
11
- else
12
- super
13
- end
14
- end
15
- end
16
-
17
- class PartDefinedClassExtensions
18
- def self.respond_to?(method)
19
- methods = CouchRest::ClassExtension::InstanceMethods.instance_methods
20
- methods.delete('cattr_reader')
21
-
22
- if methods.include?(method)
23
- false
24
- else
25
- super
26
- end
27
- end
28
- end
29
-
30
- class NoClassExtensions
31
- def self.respond_to?(method)
32
- if CouchRest::ClassExtension::InstanceMethods.instance_methods.include?(method)
33
- false
34
- else
35
- super
36
- end
37
- end
38
- end
39
-
40
-
41
- end
42
-
43
- it "should not include InstanceMethods if the class extensions are already defined" do
44
- FullyDefinedClassExtensions.send(:include, CouchRest::ClassExtension)
45
- FullyDefinedClassExtensions.ancestors.should_not include(CouchRest::ClassExtension::InstanceMethods)
46
- end
47
-
48
- it "should raise RuntimeError if the class extensions are only partially defined" do
49
- lambda {
50
- PartDefinedClassExtensions.send(:include, CouchRest::ClassExtension)
51
- }.should raise_error(RuntimeError)
52
- end
53
-
54
- it "should include class extensions if they are not already defined" do
55
- NoClassExtensions.send(:include, CouchRest::ClassExtension)
56
- NoClassExtensions.ancestors.should include(CouchRest::ClassExtension::InstanceMethods)
57
- end
58
-
59
- end