jchris-couchrest 0.17.0 → 0.22

Sign up to get free protection for your applications and to get access to all the features.
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