thefool808-couch_potato 0.2.7

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.
Files changed (42) hide show
  1. data/MIT-LICENSE.txt +19 -0
  2. data/README.md +269 -0
  3. data/VERSION.yml +4 -0
  4. data/init.rb +3 -0
  5. data/lib/core_ext/date.rb +10 -0
  6. data/lib/core_ext/object.rb +5 -0
  7. data/lib/core_ext/string.rb +15 -0
  8. data/lib/core_ext/time.rb +11 -0
  9. data/lib/couch_potato.rb +41 -0
  10. data/lib/couch_potato/database.rb +96 -0
  11. data/lib/couch_potato/persistence.rb +94 -0
  12. data/lib/couch_potato/persistence/belongs_to_property.rb +58 -0
  13. data/lib/couch_potato/persistence/callbacks.rb +96 -0
  14. data/lib/couch_potato/persistence/dirty_attributes.rb +27 -0
  15. data/lib/couch_potato/persistence/json.rb +45 -0
  16. data/lib/couch_potato/persistence/magic_timestamps.rb +13 -0
  17. data/lib/couch_potato/persistence/properties.rb +56 -0
  18. data/lib/couch_potato/persistence/simple_property.rb +77 -0
  19. data/lib/couch_potato/view/base_view_spec.rb +24 -0
  20. data/lib/couch_potato/view/custom_view_spec.rb +27 -0
  21. data/lib/couch_potato/view/custom_views.rb +44 -0
  22. data/lib/couch_potato/view/model_view_spec.rb +63 -0
  23. data/lib/couch_potato/view/properties_view_spec.rb +39 -0
  24. data/lib/couch_potato/view/raw_view_spec.rb +25 -0
  25. data/lib/couch_potato/view/view_query.rb +44 -0
  26. data/rails/init.rb +7 -0
  27. data/spec/callbacks_spec.rb +271 -0
  28. data/spec/create_spec.rb +22 -0
  29. data/spec/custom_view_spec.rb +134 -0
  30. data/spec/destroy_spec.rb +29 -0
  31. data/spec/property_spec.rb +64 -0
  32. data/spec/spec.opts +4 -0
  33. data/spec/spec_helper.rb +31 -0
  34. data/spec/unit/attributes_spec.rb +26 -0
  35. data/spec/unit/create_spec.rb +58 -0
  36. data/spec/unit/customs_views_spec.rb +15 -0
  37. data/spec/unit/database_spec.rb +18 -0
  38. data/spec/unit/dirty_attributes_spec.rb +113 -0
  39. data/spec/unit/string_spec.rb +13 -0
  40. data/spec/unit/view_query_spec.rb +9 -0
  41. data/spec/update_spec.rb +40 -0
  42. metadata +135 -0
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/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)['ruby_class'].should == 'Comment'
12
+ end
13
+ end
14
+ describe "fails" do
15
+ it "should not store anything" do
16
+ @comment = Comment.new
17
+ CouchPotato.database.save_document @comment
18
+ CouchPotato.couchrest_database.documents['rows'].should be_empty
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,134 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class Build
4
+ include CouchPotato::Persistence
5
+
6
+ property :state
7
+ property :time
8
+
9
+ view :timeline, :key => :time
10
+ view :count, :key => :time, :reduce => true
11
+ view :minimal_timeline, :key => :time, :properties => [:state], :type => :properties
12
+ view :key_array_timeline, :key => [:time, :state]
13
+ view :custom_timeline, :map => "function(doc) { emit(doc._id, {state: 'custom_' + doc.state}); }", :type => :custom
14
+ view :custom_timeline_returns_docs, :map => "function(doc) { emit(doc._id, null); }", :include_docs => true, :type => :custom
15
+ view :raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}"
16
+ view :filtered_raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}", :results_filter => lambda{|res| res['rows'].map{|row| row['value']}}
17
+ view :with_view_options, :group => true, :key => :time
18
+ end
19
+
20
+ describe 'view' do
21
+ before(:each) do
22
+ recreate_db
23
+ end
24
+
25
+ it "should return instances of the class" do
26
+ CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
27
+ results = CouchPotato.database.view(Build.timeline)
28
+ results.collect{|res| res.class}.should == [Build]
29
+ end
30
+
31
+ it "should pass the view options to the view query" do
32
+ query = mock 'query'
33
+ CouchPotato::View::ViewQuery.stub!(:new).and_return(query)
34
+ query.should_receive(:query_view!).with(hash_including(:key => 1)).and_return('rows' => [])
35
+ CouchPotato.database.view Build.timeline(:key => 1)
36
+ end
37
+
38
+ it "should not return documents that don't have a matching ruby_class" do
39
+ CouchPotato.couchrest_database.save_doc({:time => 'x'})
40
+ CouchPotato.database.view(Build.timeline).should == []
41
+ end
42
+
43
+ it "should count documents" do
44
+ CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
45
+ CouchPotato.database.view(Build.count(:reduce => true)).should == 1
46
+ end
47
+
48
+ it "should count zero documents" do
49
+ CouchPotato.database.view(Build.count(:reduce => true)).should == 0
50
+ end
51
+
52
+ describe "properties defined" do
53
+ it "should assign the configured properties" do
54
+ CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')
55
+ CouchPotato.database.view(Build.minimal_timeline).first.state.should == 'success'
56
+ end
57
+
58
+ it "should not assign the properties not configured" do
59
+ CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')
60
+ CouchPotato.database.view(Build.minimal_timeline).first.time.should be_nil
61
+ end
62
+
63
+ it "should assign the id even if it is not configured" do
64
+ id = CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')['id']
65
+ CouchPotato.database.view(Build.minimal_timeline).first._id.should == id
66
+ end
67
+ end
68
+
69
+ describe "no properties defined" do
70
+ it "should assign all properties to the objects by default" do
71
+ id = CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', :ruby_class => 'Build'})['id']
72
+ result = CouchPotato.database.view(Build.timeline).first
73
+ result.state.should == 'success'
74
+ result.time.should == '2008-01-01'
75
+ result._id.should == id
76
+ end
77
+ end
78
+
79
+ describe "map function given" do
80
+ it "should still return instances of the class" do
81
+ CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
82
+ CouchPotato.database.view(Build.custom_timeline).collect{|res| res.class}.should == [Build]
83
+ end
84
+
85
+ it "should assign the properties from the value" do
86
+ CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
87
+ CouchPotato.database.view(Build.custom_timeline).collect{|res| res.state}.should == ['custom_success']
88
+ end
89
+
90
+ it "should leave the other properties blank" do
91
+ CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
92
+ CouchPotato.database.view(Build.custom_timeline).collect{|res| res.time}.should == [nil]
93
+ end
94
+
95
+ describe "that returns null documents" do
96
+ it "should return instances of the class" do
97
+ CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
98
+ CouchPotato.database.view(Build.custom_timeline_returns_docs).collect{|res| res.class}.should == [Build]
99
+ end
100
+
101
+ it "should assign the properties from the value" do
102
+ CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
103
+ CouchPotato.database.view(Build.custom_timeline_returns_docs).collect{|res| res.state}.should == ['success']
104
+ end
105
+ end
106
+ end
107
+
108
+ describe "with array as key" do
109
+ it "should create a map function with the composite key" do
110
+ CouchPotato::View::ViewQuery.should_receive(:new).with(anything, anything, anything, string_matching(/emit\(\[doc\['time'\], doc\['state'\]\]/), anything).and_return(stub('view query').as_null_object)
111
+ CouchPotato.database.view Build.key_array_timeline
112
+ end
113
+ end
114
+
115
+ describe "raw view" do
116
+ it "should return the raw data" do
117
+ CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
118
+ CouchPotato.database.view(Build.raw)['rows'][0]['value'].should == 'success'
119
+ end
120
+
121
+ it "should return filtred raw data" do
122
+ CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
123
+ CouchPotato.database.view(Build.filtered_raw).should == ['success']
124
+ end
125
+
126
+ it "should pass view options declared in the view declaration to the query" do
127
+ view_query = mock 'view_query'
128
+ CouchPotato::View::ViewQuery.stub!(:new).and_return(view_query)
129
+ view_query.should_receive(:query_view!).with(hash_including(:group => true)).and_return({'rows' => []})
130
+ CouchPotato.database.view(Build.with_view_options)
131
+ end
132
+ end
133
+
134
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'destroy' do
4
+ before(:all) do
5
+ recreate_db
6
+ end
7
+
8
+ before(:each) do
9
+ @comment = Comment.new :title => 'title'
10
+ CouchPotato.database.save_document! @comment
11
+ @comment_id = @comment.id
12
+ CouchPotato.database.destroy_document @comment
13
+ end
14
+
15
+ it "should unset the id" do
16
+ @comment._id.should be_nil
17
+ end
18
+
19
+ it "should unset the revision" do
20
+ @comment._rev.should be_nil
21
+ end
22
+
23
+ it "should remove the document from the database" do
24
+ lambda {
25
+ CouchPotato.couchrest_database.get(@comment_id).should
26
+ }.should raise_error(RestClient::ResourceNotFound)
27
+ end
28
+
29
+ end
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class Watch
4
+ include CouchPotato::Persistence
5
+
6
+ property :time, :type => Time
7
+ end
8
+
9
+
10
+ describe 'properties' do
11
+ before(:all) do
12
+ recreate_db
13
+ end
14
+
15
+ it "should return the property names" do
16
+ Comment.property_names.should == [:created_at, :updated_at, :title, :commenter]
17
+ end
18
+
19
+ it "should persist a string" do
20
+ c = Comment.new :title => 'my title'
21
+ CouchPotato.database.save_document! c
22
+ c = CouchPotato.database.load_document c.id
23
+ c.title.should == 'my title'
24
+ end
25
+
26
+ it "should persist a number" do
27
+ c = Comment.new :title => 3
28
+ CouchPotato.database.save_document! c
29
+ c = CouchPotato.database.load_document c.id
30
+ c.title.should == 3
31
+ end
32
+
33
+ it "should persist a hash" do
34
+ c = Comment.new :title => {'key' => 'value'}
35
+ CouchPotato.database.save_document! c
36
+ c = CouchPotato.database.load_document c.id
37
+ c.title.should == {'key' => 'value'}
38
+ end
39
+
40
+ it "should persist a Time object" do
41
+ w = Watch.new :time => Time.now
42
+ CouchPotato.database.save_document! w
43
+ w = CouchPotato.database.load_document w.id
44
+ w.time.year.should == Time.now.year
45
+ end
46
+
47
+ describe "predicate" do
48
+ it "should return true if property set" do
49
+ Comment.new(:title => 'title').title?.should be_true
50
+ end
51
+
52
+ it "should return false if property nil" do
53
+ Comment.new.title?.should be_false
54
+ end
55
+
56
+ it "should return false if property false" do
57
+ Comment.new(:title => false).title?.should be_false
58
+ end
59
+
60
+ it "should return false if property blank" do
61
+ Comment.new(:title => '').title?.should be_false
62
+ end
63
+ end
64
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,31 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
5
+
6
+ require 'couch_potato'
7
+
8
+ CouchPotato::Config.database_name = 'couch_potato_test'
9
+ CouchPotato::Config.database_server = 'http://192.168.1.48:5984/'
10
+
11
+
12
+ class Comment
13
+ include CouchPotato::Persistence
14
+
15
+ validates_presence_of :title
16
+
17
+ property :title
18
+ belongs_to :commenter
19
+ end
20
+
21
+ def recreate_db
22
+ CouchPotato.couchrest_database.delete! rescue nil
23
+ CouchPotato.couchrest_database.server.create_db CouchPotato::Config.database_name
24
+ end
25
+ recreate_db
26
+
27
+ Spec::Matchers.define :string_matching do |regex|
28
+ match do |string|
29
+ string =~ regex
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class Plant
4
+ include CouchPotato::Persistence
5
+ property :leaf_count
6
+ end
7
+
8
+ describe "attributes" do
9
+
10
+ describe 'attributes=' do
11
+ it "should assign the attributes" do
12
+ plant = Plant.new
13
+ plant.attributes = {:leaf_count => 1}
14
+ plant.leaf_count.should == 1
15
+ end
16
+ end
17
+
18
+ describe "attributes" do
19
+ it "should return the attributes" do
20
+ plant = Plant.new(:leaf_count => 1)
21
+ plant.attributes.should == {:leaf_count => 1, :created_at => nil, :updated_at => nil}
22
+ end
23
+ end
24
+
25
+ end
26
+
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "create" do
4
+
5
+ describe "succeeds" do
6
+ before(:each) do
7
+ @comment = Comment.new :title => 'my_title'
8
+ CouchPotato::Database.new(stub('database', :save_doc => {'rev' => '123', 'id' => '456'}, :info => nil)).save_document!(@comment)
9
+ end
10
+
11
+ it "should assign the id" do
12
+ @comment._id.should == '456'
13
+ end
14
+
15
+ it "should assign the revision" do
16
+ @comment._rev.should == '123'
17
+ end
18
+
19
+ it "should set created at" do
20
+ @comment.created_at.should >= Time.now - 10
21
+ end
22
+
23
+ it "should set updated at" do
24
+ @comment.updated_at.should >= Time.now - 10
25
+ end
26
+ end
27
+
28
+ describe "fails" do
29
+ before(:each) do
30
+ @comment = Comment.new
31
+ CouchPotato::Database.new(stub('database', :info => nil)).save_document(@comment)
32
+ end
33
+
34
+ it "should not assign an id" do
35
+ @comment._id.should be_nil
36
+ end
37
+
38
+ it "should not assign a revision" do
39
+ @comment._rev.should be_nil
40
+ end
41
+
42
+ it "should not set created at" do
43
+ @comment.created_at.should be_nil
44
+ end
45
+
46
+ it "should set updated at" do
47
+ @comment.updated_at.should be_nil
48
+ end
49
+
50
+ describe "with bank" do
51
+ it "should raise an exception" do
52
+ lambda {
53
+ @comment.save!
54
+ }.should raise_error
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe CouchPotato::View::CustomViews do
4
+
5
+ class MyViewSpec; end
6
+ class ModelWithView
7
+ include CouchPotato::Persistence
8
+ view :all, :type => MyViewSpec
9
+ end
10
+
11
+ it "should use a custom viewspec class" do
12
+ MyViewSpec.should_receive(:new)
13
+ ModelWithView.all
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe CouchPotato::Database, 'new' do
4
+ it "should raise an exception if the database doesn't exist" do
5
+ lambda {
6
+ CouchPotato::Database.new CouchRest.database('couch_potato_invalid')
7
+ }.should raise_error('Database \'couch_potato_invalid\' does not exist.')
8
+ end
9
+ end
10
+
11
+ describe CouchPotato::Database, 'load' do
12
+ it "should raise an exception if nil given" do
13
+ db = CouchPotato::Database.new(stub('couchrest db', :info => nil))
14
+ lambda {
15
+ db.load nil
16
+ }.should raise_error("Can't load a document without an id (got nil)")
17
+ end
18
+ end
@@ -0,0 +1,113 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class Plate
4
+ include CouchPotato::Persistence
5
+
6
+ property :food
7
+ end
8
+
9
+ describe 'dirty attribute tracking' do
10
+ before(:each) do
11
+ @couchrest_db = stub('database', :save_doc => {'id' => '1', 'rev' => '2'}, :info => nil)
12
+ @db = CouchPotato::Database.new(@couchrest_db)
13
+ end
14
+
15
+ describe "save" do
16
+ it "should not save when nothing dirty" do
17
+ plate = Plate.new :food => 'sushi'
18
+ @db.save_document!(plate)
19
+ @couchrest_db.should_not_receive(:save_doc)
20
+ @db.save_document(plate)
21
+ end
22
+
23
+ it "should return true when not dirty" do
24
+ plate = Plate.new :food => 'sushi'
25
+ @db.save_document!(plate)
26
+ @db.save_document(plate).should be_true
27
+ end
28
+
29
+ it "should save when there are dirty attributes" do
30
+ plate = Plate.new :food => 'sushi'
31
+ @db.save_document!(plate)
32
+ plate.food = 'burger'
33
+ @couchrest_db.should_receive(:save_doc)
34
+ @db.save_document(plate)
35
+ end
36
+ end
37
+
38
+ describe "newly created object" do
39
+
40
+ before(:each) do
41
+ @plate = Plate.new :food => 'sushi'
42
+ end
43
+
44
+ describe "access old values" do
45
+ it "should return the old value" do
46
+ @plate.food = 'burger'
47
+ @plate.food_was.should == 'sushi'
48
+ end
49
+ end
50
+
51
+ describe "check for dirty" do
52
+ it "should return true if attribute changed" do
53
+ @plate.food = 'burger'
54
+ @plate.should be_food_changed
55
+ end
56
+
57
+ it "should return false if attribute not changed" do
58
+ @plate.should_not be_food_changed
59
+ end
60
+
61
+ it "should return false if attribute forced not changed" do
62
+ @plate.food = 'burger'
63
+ @plate.food_not_changed
64
+ @plate.should_not be_food_changed
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "object loaded from database" do
70
+ before(:each) do
71
+ couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}, :info => nil)
72
+ @plate = CouchPotato::Database.new(couchrest_db).load_document '1'
73
+ end
74
+
75
+ describe "access old values" do
76
+ it "should return the old value" do
77
+ @plate.food = 'burger'
78
+ @plate.food_was.should == 'sushi'
79
+ end
80
+ end
81
+
82
+ describe "check for dirty" do
83
+ it "should return true if attribute changed" do
84
+ @plate.food = 'burger'
85
+ @plate.should be_food_changed
86
+ end
87
+
88
+ it "should return true if array attribute changed" do
89
+ couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => ['sushi'], 'ruby_class' => 'Plate'}, :info => nil)
90
+ plate = CouchPotato::Database.new(couchrest_db).load_document '1'
91
+ plate.food << 'burger'
92
+ plate.should be_food_changed
93
+ end
94
+
95
+ it "should return false if attribute not changed" do
96
+ @plate.should_not be_food_changed
97
+ end
98
+ end
99
+ end
100
+
101
+
102
+ describe "after save" do
103
+ it "should reset all attributes to not dirty" do
104
+ couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}, :info => nil, :save_doc => {})
105
+ db = CouchPotato::Database.new(couchrest_db)
106
+ @plate = db.load_document '1'
107
+ @plate.food = 'burger'
108
+ db.save! @plate
109
+ @plate.should_not be_food_changed
110
+ end
111
+ end
112
+
113
+ end