davber_couch_potato 0.3.0
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/CHANGES.md +106 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.md +409 -0
- data/VERSION.yml +5 -0
- data/init.rb +3 -0
- data/lib/core_ext/date.rb +21 -0
- data/lib/core_ext/object.rb +5 -0
- data/lib/core_ext/string.rb +8 -0
- data/lib/core_ext/symbol.rb +15 -0
- data/lib/core_ext/time.rb +21 -0
- data/lib/couch_potato/database.rb +161 -0
- data/lib/couch_potato/persistence/active_model_compliance.rb +44 -0
- data/lib/couch_potato/persistence/attachments.rb +31 -0
- data/lib/couch_potato/persistence/callbacks.rb +62 -0
- data/lib/couch_potato/persistence/dirty_attributes.rb +56 -0
- data/lib/couch_potato/persistence/ghost_attributes.rb +22 -0
- data/lib/couch_potato/persistence/json.rb +46 -0
- data/lib/couch_potato/persistence/magic_timestamps.rb +20 -0
- data/lib/couch_potato/persistence/properties.rb +86 -0
- data/lib/couch_potato/persistence/simple_property.rb +72 -0
- data/lib/couch_potato/persistence/type_caster.rb +40 -0
- data/lib/couch_potato/persistence.rb +105 -0
- data/lib/couch_potato/railtie.rb +18 -0
- data/lib/couch_potato/rspec/matchers/json2.js +482 -0
- data/lib/couch_potato/rspec/matchers/list_as_matcher.rb +54 -0
- data/lib/couch_potato/rspec/matchers/map_to_matcher.rb +49 -0
- data/lib/couch_potato/rspec/matchers/print_r.js +60 -0
- data/lib/couch_potato/rspec/matchers/reduce_to_matcher.rb +50 -0
- data/lib/couch_potato/rspec/matchers.rb +39 -0
- data/lib/couch_potato/rspec/stub_db.rb +46 -0
- data/lib/couch_potato/rspec.rb +2 -0
- data/lib/couch_potato/validation/with_active_model.rb +27 -0
- data/lib/couch_potato/validation/with_validatable.rb +37 -0
- data/lib/couch_potato/validation.rb +16 -0
- data/lib/couch_potato/view/base_view_spec.rb +67 -0
- data/lib/couch_potato/view/custom_view_spec.rb +42 -0
- data/lib/couch_potato/view/custom_views.rb +52 -0
- data/lib/couch_potato/view/lists.rb +23 -0
- data/lib/couch_potato/view/model_view_spec.rb +75 -0
- data/lib/couch_potato/view/properties_view_spec.rb +47 -0
- data/lib/couch_potato/view/raw_view_spec.rb +25 -0
- data/lib/couch_potato/view/view_query.rb +78 -0
- data/lib/couch_potato.rb +79 -0
- data/rails/init.rb +4 -0
- data/rails/reload_classes.rb +47 -0
- data/spec/attachments_spec.rb +23 -0
- data/spec/callbacks_spec.rb +308 -0
- data/spec/create_spec.rb +34 -0
- data/spec/custom_view_spec.rb +239 -0
- data/spec/default_property_spec.rb +38 -0
- data/spec/destroy_spec.rb +29 -0
- data/spec/fixtures/address.rb +10 -0
- data/spec/fixtures/person.rb +6 -0
- data/spec/property_spec.rb +315 -0
- data/spec/rails_spec.rb +51 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/unit/active_model_compliance_spec.rb +98 -0
- data/spec/unit/attributes_spec.rb +125 -0
- data/spec/unit/base_view_spec_spec.rb +73 -0
- data/spec/unit/callbacks_spec.rb +72 -0
- data/spec/unit/couch_potato_spec.rb +39 -0
- data/spec/unit/create_spec.rb +58 -0
- data/spec/unit/custom_views_spec.rb +15 -0
- data/spec/unit/database_spec.rb +266 -0
- data/spec/unit/date_spec.rb +22 -0
- data/spec/unit/dirty_attributes_spec.rb +166 -0
- data/spec/unit/json_create_id_spec.rb +14 -0
- data/spec/unit/lists_spec.rb +20 -0
- data/spec/unit/model_view_spec_spec.rb +13 -0
- data/spec/unit/properties_view_spec_spec.rb +31 -0
- data/spec/unit/rspec_matchers_spec.rb +124 -0
- data/spec/unit/rspec_stub_db_spec.rb +35 -0
- data/spec/unit/string_spec.rb +7 -0
- data/spec/unit/time_spec.rb +22 -0
- data/spec/unit/validation_spec.rb +67 -0
- data/spec/unit/view_query_spec.rb +78 -0
- data/spec/update_spec.rb +40 -0
- data/spec/view_updates_spec.rb +28 -0
- metadata +205 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
module CouchPotato
|
2
|
+
module View
|
3
|
+
# Used to query views (and create them if they don't exist). Usually you won't have to use this class directly. Instead it is used internally by the CouchPotato::Database.view method.
|
4
|
+
class ViewQuery
|
5
|
+
def initialize(couchrest_database, design_document_name, view, list = nil)
|
6
|
+
@database = couchrest_database
|
7
|
+
@design_document_name = design_document_name
|
8
|
+
@view_name = view.keys[0]
|
9
|
+
@map_function = view.values[0][:map]
|
10
|
+
@reduce_function = view.values[0][:reduce]
|
11
|
+
if list
|
12
|
+
@list_function = list.values[0]
|
13
|
+
@list_name = list.keys[0]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def query_view!(parameters = {})
|
18
|
+
update_view unless view_has_been_updated?
|
19
|
+
begin
|
20
|
+
query_view parameters
|
21
|
+
rescue RestClient::ResourceNotFound
|
22
|
+
update_view
|
23
|
+
retry
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def update_view
|
30
|
+
design_doc = @database.get "_design/#{@design_document_name}" rescue nil
|
31
|
+
original_views = design_doc && design_doc['views'].dup
|
32
|
+
original_lists = design_doc && design_doc['lists'] && design_doc['lists'].dup
|
33
|
+
view_updated unless design_doc.nil?
|
34
|
+
design_doc ||= empty_design_document
|
35
|
+
design_doc['views'][@view_name.to_s] = view_functions
|
36
|
+
if @list_function
|
37
|
+
design_doc['lists'] ||= {}
|
38
|
+
design_doc['lists'][@list_name.to_s] = @list_function
|
39
|
+
end
|
40
|
+
@database.save_doc(design_doc) if original_views != design_doc['views'] || original_lists != design_doc['lists']
|
41
|
+
end
|
42
|
+
|
43
|
+
def view_functions
|
44
|
+
{'map' => @map_function, 'reduce' => @reduce_function}
|
45
|
+
end
|
46
|
+
|
47
|
+
def empty_design_document
|
48
|
+
{'views' => {}, 'lists' => {}, "_id" => "_design/#{@design_document_name}", "language" => "javascript"}
|
49
|
+
end
|
50
|
+
|
51
|
+
def view_has_been_updated?
|
52
|
+
updated_views[[@design_document_name, @view_name]]
|
53
|
+
end
|
54
|
+
|
55
|
+
def view_updated
|
56
|
+
updated_views[[@design_document_name, @view_name]] = true
|
57
|
+
end
|
58
|
+
|
59
|
+
def updated_views
|
60
|
+
@@updated_views ||= {}
|
61
|
+
@@updated_views
|
62
|
+
end
|
63
|
+
|
64
|
+
def query_view(parameters)
|
65
|
+
if @list_name
|
66
|
+
CouchRest.get CouchRest.paramify_url(CouchPotato.full_url_to_database + "/_design/#{@design_document_name}/_list/#{@list_name}/#{@view_name}", parameters)
|
67
|
+
else
|
68
|
+
@database.view view_url, parameters
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def view_url
|
73
|
+
"#{@design_document_name}/#{@view_name}"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/couch_potato.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'couchrest'
|
2
|
+
require 'json'
|
3
|
+
require 'json/add/core'
|
4
|
+
require 'json/add/rails'
|
5
|
+
|
6
|
+
require 'ostruct'
|
7
|
+
|
8
|
+
unless defined?(CouchPotato)
|
9
|
+
module CouchPotato
|
10
|
+
DEFAULT_TYPE_FIELD = 'ruby_class'
|
11
|
+
|
12
|
+
# The name of the type field of CouchDB documents
|
13
|
+
@@type_field = DEFAULT_TYPE_FIELD
|
14
|
+
# The function mapping classes to the corresponding CouchDB design document.
|
15
|
+
@@design_name_fun = lambda do |klass|
|
16
|
+
klass_name = klass.to_s
|
17
|
+
klass_name.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
18
|
+
klass_name.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
19
|
+
klass_name.tr!("-", "_")
|
20
|
+
klass_name.downcase
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get the type field name to use.
|
24
|
+
# NOTE: this is universal, so will transcend individual databases
|
25
|
+
def self.type_field
|
26
|
+
@@type_field
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.type_field= type_field
|
30
|
+
@@type_field = type_field
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the lambda to use for conversion from a class to the design document name
|
34
|
+
def self.design_name_fun
|
35
|
+
@@design_name_fun
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.design_name_fun= fun
|
39
|
+
@@design_name_fun = fun
|
40
|
+
end
|
41
|
+
|
42
|
+
Config = Struct.new(:database_name, :validation_framework).new
|
43
|
+
Config.validation_framework = :validatable # default to the validatable gem for validations
|
44
|
+
|
45
|
+
# Returns a database instance which you can then use to create objects and query views. You have to set the CouchPotato::Config.database_name before this works.
|
46
|
+
def self.database
|
47
|
+
@@__database ||= Database.new(self.couchrest_database)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the underlying CouchRest database object if you want low level access to your CouchDB. You have to set the CouchPotato::Config.database_name before this works.
|
51
|
+
def self.couchrest_database
|
52
|
+
@@__couchrest_database ||= CouchRest.database(full_url_to_database)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def self.full_url_to_database
|
58
|
+
raise('No Database configured. Set CouchPotato::Config.database_name') unless CouchPotato::Config.database_name
|
59
|
+
if CouchPotato::Config.database_name.match(%r{https?://})
|
60
|
+
CouchPotato::Config.database_name
|
61
|
+
else
|
62
|
+
"http://127.0.0.1:5984/#{CouchPotato::Config.database_name}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
JSON.create_id = CouchPotato.type_field
|
69
|
+
|
70
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
71
|
+
|
72
|
+
require 'core_ext/object'
|
73
|
+
require 'core_ext/time'
|
74
|
+
require 'core_ext/date'
|
75
|
+
require 'core_ext/string'
|
76
|
+
require 'core_ext/symbol'
|
77
|
+
require 'couch_potato/validation'
|
78
|
+
require 'couch_potato/persistence'
|
79
|
+
require 'couch_potato/railtie' if defined?(Rails)
|
data/rails/init.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module CouchPotato
|
2
|
+
|
3
|
+
module ClassReloading
|
4
|
+
private
|
5
|
+
|
6
|
+
def with_class_reloading(&block)
|
7
|
+
begin
|
8
|
+
yield
|
9
|
+
rescue ArgumentError => e
|
10
|
+
if(name = e.message.scan(/(can't find const|undefined class\/module) ([\w\:]+)/).first[1])
|
11
|
+
eval name.gsub(/\:+$/, '')
|
12
|
+
retry
|
13
|
+
else
|
14
|
+
raise e
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
View::ViewQuery.class_eval do
|
21
|
+
include ClassReloading
|
22
|
+
|
23
|
+
def query_view_with_class_reloading(*args)
|
24
|
+
with_class_reloading do
|
25
|
+
query_view_without_class_reloading(*args)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
alias_method :query_view_without_class_reloading, :query_view
|
30
|
+
alias_method :query_view, :query_view_with_class_reloading
|
31
|
+
end
|
32
|
+
|
33
|
+
Database.class_eval do
|
34
|
+
include ClassReloading
|
35
|
+
|
36
|
+
def load_document_with_class_reloading(*args)
|
37
|
+
with_class_reloading do
|
38
|
+
load_document_without_class_reloading *args
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
alias_method :load_document_without_class_reloading, :load_document
|
43
|
+
alias_method :load_document, :load_document_with_class_reloading
|
44
|
+
alias_method :load, :load_document
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CouchPotato, 'attachments' do
|
4
|
+
it "should persist an attachment" do
|
5
|
+
comment = Comment.new :title => 'nil'
|
6
|
+
comment._attachments['body'] = {'data' => 'a useful comment', 'content_type' => 'text/plain'}
|
7
|
+
CouchPotato.database.save! comment
|
8
|
+
CouchPotato.couchrest_database.fetch_attachment(comment.to_hash, 'body').to_s.should == 'a useful comment'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should give me information about the attachments of a document" do
|
12
|
+
comment = Comment.new :title => 'nil'
|
13
|
+
comment._attachments = {'body' => {'data' => 'a useful comment', 'content_type' => 'text/plain'}}
|
14
|
+
CouchPotato.database.save! comment
|
15
|
+
comment_reloaded = CouchPotato.database.load comment.id
|
16
|
+
comment_reloaded._attachments["body"].should include({"content_type" => "text/plain", "stub" => true, "length" => 16})
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have an empty array for a new object" do
|
20
|
+
Comment.new._attachments.should == {}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class CallbackRecorder
|
4
|
+
include CouchPotato::Persistence
|
5
|
+
|
6
|
+
property :required_property
|
7
|
+
|
8
|
+
validates_presence_of :required_property
|
9
|
+
|
10
|
+
[:before_validation, :before_validation_on_create,
|
11
|
+
:before_validation_on_save, :before_validation_on_update,
|
12
|
+
:before_save, :before_create, :before_create,
|
13
|
+
:after_save, :after_create, :after_create,
|
14
|
+
:before_update, :after_update,
|
15
|
+
:before_destroy, :after_destroy
|
16
|
+
].each do |callback|
|
17
|
+
define_method callback do
|
18
|
+
callbacks << callback
|
19
|
+
end
|
20
|
+
self.send callback, callback
|
21
|
+
end
|
22
|
+
|
23
|
+
view :all, :key => :required_property
|
24
|
+
|
25
|
+
attr_accessor :lambda_works
|
26
|
+
before_create lambda {|model| model.lambda_works = true }
|
27
|
+
|
28
|
+
def callbacks
|
29
|
+
@callbacks ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def method_callback_with_argument(db)
|
35
|
+
db.view CallbackRecorder.all
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "multiple callbacks at once" do
|
41
|
+
|
42
|
+
class Monkey
|
43
|
+
include CouchPotato::Persistence
|
44
|
+
attr_accessor :eaten_banana, :eaten_apple
|
45
|
+
|
46
|
+
before_create :eat_apple, :eat_banana
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def eat_banana
|
51
|
+
self.eaten_banana = true
|
52
|
+
end
|
53
|
+
|
54
|
+
def eat_apple
|
55
|
+
self.eaten_apple = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should run all callback methods given to the callback method call" do
|
60
|
+
monkey = Monkey.new
|
61
|
+
monkey.run_callbacks :before_create
|
62
|
+
monkey.eaten_banana.should be_true
|
63
|
+
monkey.eaten_apple.should be_true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'create callbacks' do
|
68
|
+
|
69
|
+
before(:each) do
|
70
|
+
@recorder = CallbackRecorder.new
|
71
|
+
couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :view => {'rows' => []}, :info => nil
|
72
|
+
@db = CouchPotato::Database.new(couchrest_database)
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "successful create" do
|
76
|
+
before(:each) do
|
77
|
+
@recorder.required_property = 1
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should call before_validation" do
|
81
|
+
@recorder.valid?
|
82
|
+
@recorder.callbacks.should include(:before_validation)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should call before_validation_on_create" do
|
86
|
+
@db.save_document! @recorder
|
87
|
+
@recorder.callbacks.should include(:before_validation_on_create)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should call before_validation_on_save" do
|
91
|
+
@db.save_document! @recorder
|
92
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should call before_save" do
|
96
|
+
@db.save_document! @recorder
|
97
|
+
@recorder.callbacks.should include(:before_save)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should call after_save" do
|
101
|
+
@db.save_document! @recorder
|
102
|
+
@recorder.callbacks.should include(:after_save)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should call before_create" do
|
106
|
+
@db.save_document! @recorder
|
107
|
+
@recorder.callbacks.should include(:before_create)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should call after_create" do
|
111
|
+
@db.save_document! @recorder
|
112
|
+
@recorder.callbacks.should include(:after_create)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "failed create" do
|
118
|
+
|
119
|
+
it "should call before_validation" do
|
120
|
+
@recorder.valid?
|
121
|
+
@recorder.callbacks.should include(:before_validation)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should call before_validation_on_create" do
|
125
|
+
@db.save_document @recorder
|
126
|
+
@recorder.callbacks.should include(:before_validation_on_create)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should call before_validation_on_save" do
|
130
|
+
@db.save_document @recorder
|
131
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should not call before_save" do
|
135
|
+
@db.save_document @recorder
|
136
|
+
@recorder.callbacks.should_not include(:before_save)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should not call after_save" do
|
140
|
+
@db.save_document @recorder
|
141
|
+
@recorder.callbacks.should_not include(:after_save)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should not call before_create" do
|
145
|
+
@db.save_document @recorder
|
146
|
+
@recorder.callbacks.should_not include(:before_create)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not call after_create" do
|
150
|
+
@db.save_document @recorder
|
151
|
+
@recorder.callbacks.should_not include(:after_create)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "update callbacks" do
|
157
|
+
|
158
|
+
before(:each) do
|
159
|
+
@recorder = CallbackRecorder.new :required_property => 1
|
160
|
+
|
161
|
+
couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :view => {'rows' => []}, :info => nil
|
162
|
+
@db = CouchPotato::Database.new(couchrest_database)
|
163
|
+
@db.save_document! @recorder
|
164
|
+
|
165
|
+
@recorder.required_property = 2
|
166
|
+
@recorder.callbacks.clear
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "successful update" do
|
170
|
+
|
171
|
+
before(:each) do
|
172
|
+
@db.save_document! @recorder
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should call before_validation" do
|
176
|
+
@recorder.callbacks.should include(:before_validation)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should call before_validation_on_update" do
|
180
|
+
@recorder.callbacks.should include(:before_validation_on_update)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should call before_validation_on_save" do
|
184
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should call before_save" do
|
188
|
+
@recorder.callbacks.should include(:before_save)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should call after_save" do
|
192
|
+
@recorder.callbacks.should include(:after_save)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should call before_update" do
|
196
|
+
@recorder.callbacks.should include(:before_update)
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should call after_update" do
|
200
|
+
@recorder.callbacks.should include(:after_update)
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "failed update" do
|
206
|
+
|
207
|
+
before(:each) do
|
208
|
+
@recorder.required_property = nil
|
209
|
+
@db.save_document @recorder
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should call before_validation" do
|
213
|
+
@recorder.callbacks.should include(:before_validation)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should call before_validation_on_update" do
|
217
|
+
@recorder.callbacks.should include(:before_validation_on_update)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should call before_validation_on_save" do
|
221
|
+
@recorder.callbacks.should include(:before_validation_on_save)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should not call before_save" do
|
225
|
+
@recorder.callbacks.should_not include(:before_save)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should not call after_save" do
|
229
|
+
@recorder.callbacks.should_not include(:after_save)
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should not call before_update" do
|
233
|
+
@recorder.callbacks.should_not include(:before_update)
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should not call after_update" do
|
237
|
+
@recorder.callbacks.should_not include(:after_update)
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "destroy callbacks" do
|
245
|
+
|
246
|
+
before(:each) do
|
247
|
+
@recorder = CallbackRecorder.new :required_property => 1
|
248
|
+
couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :delete_doc => nil, :view => {'rows' => []}, :info => nil
|
249
|
+
@db = CouchPotato::Database.new(couchrest_database)
|
250
|
+
@db.save_document! @recorder
|
251
|
+
|
252
|
+
@recorder.callbacks.clear
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should call before_destroy" do
|
256
|
+
@db.destroy_document @recorder
|
257
|
+
@recorder.callbacks.should include(:before_destroy)
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should call after_destroy" do
|
261
|
+
@db.destroy_document @recorder
|
262
|
+
@recorder.callbacks.should include(:after_destroy)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe "lambda callbacks" do
|
267
|
+
it "should run the lambda" do
|
268
|
+
recorder = CallbackRecorder.new
|
269
|
+
recorder.run_callbacks :before_create
|
270
|
+
recorder.lambda_works.should be_true
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe "validation callbacks" do
|
275
|
+
class ValidatedUser
|
276
|
+
include CouchPotato::Persistence
|
277
|
+
|
278
|
+
property :name
|
279
|
+
before_validation :check_name
|
280
|
+
validates_presence_of :name
|
281
|
+
|
282
|
+
def check_name
|
283
|
+
errors.add(:name, 'should be Paul') unless name == "Paul"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should keep error messages set in custom before_validation filters" do
|
288
|
+
user = ValidatedUser.new(:name => "john")
|
289
|
+
user.valid?.should == false
|
290
|
+
user.errors.on(:name).should == "should be Paul"
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should combine the errors from validations and callbacks" do
|
294
|
+
user = ValidatedUser.new(:name => nil)
|
295
|
+
user.valid?.should == false
|
296
|
+
user.errors.on(:name).any? {|msg| msg =~ /can't be (empty|blank)/ }.should == true
|
297
|
+
user.errors.on(:name).any? {|msg| msg == "should be Paul" }.should == true
|
298
|
+
user.errors.on(:name).size.should == 2
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should clear the errors on subsequent calls to valid?" do
|
302
|
+
user = ValidatedUser.new(:name => nil)
|
303
|
+
user.valid?.should == false
|
304
|
+
user.name = 'Paul'
|
305
|
+
user.valid?.should == true
|
306
|
+
user.errors.on(:name).should == nil
|
307
|
+
end
|
308
|
+
end
|
data/spec/create_spec.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "create" do
|
4
|
+
before(:all) do
|
5
|
+
recreate_db
|
6
|
+
end
|
7
|
+
describe "succeeds" do
|
8
|
+
it "should store the class" do
|
9
|
+
@comment = Comment.new :title => 'my_title'
|
10
|
+
CouchPotato.database.save_document! @comment
|
11
|
+
CouchPotato.couchrest_database.get(@comment.id).send(JSON.create_id).should == 'Comment'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should persist a given created_at" do
|
15
|
+
@comment = Comment.new :created_at => Time.parse('2010-01-02 12:34:48 +0000'), :title => '-'
|
16
|
+
CouchPotato.database.save_document! @comment
|
17
|
+
CouchPotato.couchrest_database.get(@comment.id).created_at.should == Time.parse('2010-01-02 12:34:48 +0000')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should persist a given updated_at" do
|
21
|
+
@comment = Comment.new :updated_at => Time.parse('2010-01-02 12:34:48 +0000'), :title => '-'
|
22
|
+
CouchPotato.database.save_document! @comment
|
23
|
+
CouchPotato.couchrest_database.get(@comment.id).updated_at.should == Time.parse('2010-01-02 12:34:48 +0000')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
describe "fails" do
|
27
|
+
it "should not store anything" do
|
28
|
+
@comment = Comment.new
|
29
|
+
CouchPotato.database.save_document @comment
|
30
|
+
CouchPotato.couchrest_database.documents['rows'].should be_empty
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|