andrewtimberlake-couch_potato 0.2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/MIT-LICENSE.txt +19 -0
  2. data/README.md +279 -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 +19 -0
  8. data/lib/core_ext/symbol.rb +15 -0
  9. data/lib/core_ext/time.rb +11 -0
  10. data/lib/couch_potato.rb +40 -0
  11. data/lib/couch_potato/database.rb +105 -0
  12. data/lib/couch_potato/persistence.rb +96 -0
  13. data/lib/couch_potato/persistence/belongs_to_property.rb +58 -0
  14. data/lib/couch_potato/persistence/callbacks.rb +60 -0
  15. data/lib/couch_potato/persistence/dirty_attributes.rb +27 -0
  16. data/lib/couch_potato/persistence/json.rb +46 -0
  17. data/lib/couch_potato/persistence/magic_timestamps.rb +13 -0
  18. data/lib/couch_potato/persistence/properties.rb +57 -0
  19. data/lib/couch_potato/persistence/simple_property.rb +83 -0
  20. data/lib/couch_potato/persistence/validation.rb +18 -0
  21. data/lib/couch_potato/view/base_view_spec.rb +24 -0
  22. data/lib/couch_potato/view/custom_view_spec.rb +27 -0
  23. data/lib/couch_potato/view/custom_views.rb +44 -0
  24. data/lib/couch_potato/view/model_view_spec.rb +63 -0
  25. data/lib/couch_potato/view/properties_view_spec.rb +39 -0
  26. data/lib/couch_potato/view/raw_view_spec.rb +25 -0
  27. data/lib/couch_potato/view/view_query.rb +44 -0
  28. data/rails/init.rb +7 -0
  29. data/spec/callbacks_spec.rb +271 -0
  30. data/spec/create_spec.rb +22 -0
  31. data/spec/custom_view_spec.rb +134 -0
  32. data/spec/destroy_spec.rb +29 -0
  33. data/spec/fixtures/address.rb +9 -0
  34. data/spec/fixtures/person.rb +6 -0
  35. data/spec/property_spec.rb +83 -0
  36. data/spec/spec.opts +4 -0
  37. data/spec/spec_helper.rb +31 -0
  38. data/spec/unit/attributes_spec.rb +26 -0
  39. data/spec/unit/callbacks_spec.rb +33 -0
  40. data/spec/unit/create_spec.rb +58 -0
  41. data/spec/unit/customs_views_spec.rb +15 -0
  42. data/spec/unit/database_spec.rb +38 -0
  43. data/spec/unit/dirty_attributes_spec.rb +113 -0
  44. data/spec/unit/string_spec.rb +13 -0
  45. data/spec/unit/view_query_spec.rb +9 -0
  46. data/spec/update_spec.rb +40 -0
  47. metadata +144 -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.map(&: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).map(&: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).map(&: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).map(&: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).map(&: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).map(&: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,9 @@
1
+ class Address
2
+ include CouchPotato::Persistence
3
+
4
+ property :street
5
+ property :city
6
+ property :state
7
+ property :zip
8
+ property :country
9
+ end
@@ -0,0 +1,6 @@
1
+ class Person
2
+ include CouchPotato::Persistence
3
+
4
+ property :name
5
+ property :ship_address, :type => Address
6
+ end
@@ -0,0 +1,83 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.join(File.dirname(__FILE__), 'fixtures', 'address')
3
+ require File.join(File.dirname(__FILE__), 'fixtures', 'person')
4
+
5
+ class Watch
6
+ include CouchPotato::Persistence
7
+
8
+ property :time, :type => Time
9
+ end
10
+
11
+
12
+ describe 'properties' do
13
+ before(:all) do
14
+ recreate_db
15
+ end
16
+
17
+ it "should return the property names" do
18
+ Comment.property_names.should == [:created_at, :updated_at, :title, :commenter]
19
+ end
20
+
21
+ it "should persist a string" do
22
+ c = Comment.new :title => 'my title'
23
+ CouchPotato.database.save_document! c
24
+ c = CouchPotato.database.load_document c.id
25
+ c.title.should == 'my title'
26
+ end
27
+
28
+ it "should persist a number" do
29
+ c = Comment.new :title => 3
30
+ CouchPotato.database.save_document! c
31
+ c = CouchPotato.database.load_document c.id
32
+ c.title.should == 3
33
+ end
34
+
35
+ it "should persist a hash" do
36
+ c = Comment.new :title => {'key' => 'value'}
37
+ CouchPotato.database.save_document! c
38
+ c = CouchPotato.database.load_document c.id
39
+ c.title.should == {'key' => 'value'}
40
+ end
41
+
42
+ it "should persist a Time object" do
43
+ w = Watch.new :time => Time.now
44
+ CouchPotato.database.save_document! w
45
+ w = CouchPotato.database.load_document w.id
46
+ w.time.year.should == Time.now.year
47
+ end
48
+
49
+ it "should persist an object" do
50
+ p = Person.new :name => 'Bob'
51
+ a = Address.new :city => 'Denver'
52
+ p.ship_address = a
53
+ CouchPotato.database.save_document! p
54
+ p = CouchPotato.database.load_document p.id
55
+ p.ship_address.should === a
56
+ end
57
+
58
+ it "should persist null for a null " do
59
+ p = Person.new :name => 'Bob'
60
+ p.ship_address = nil
61
+ CouchPotato.database.save_document! p
62
+ p = CouchPotato.database.load_document p.id
63
+ p.ship_address.should be_nil
64
+ end
65
+
66
+ describe "predicate" do
67
+ it "should return true if property set" do
68
+ Comment.new(:title => 'title').title?.should be_true
69
+ end
70
+
71
+ it "should return false if property nil" do
72
+ Comment.new.title?.should be_false
73
+ end
74
+
75
+ it "should return false if property false" do
76
+ Comment.new(:title => false).title?.should be_false
77
+ end
78
+
79
+ it "should return false if property blank" do
80
+ Comment.new(:title => '').title?.should be_false
81
+ end
82
+ end
83
+ 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://127.0.0.1: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,33 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class Tree
4
+ include CouchPotato::Persistence
5
+ before_validation :water!
6
+ before_validation lambda {|tree| tree.root_count += 1 }
7
+
8
+ property :leaf_count
9
+ property :root_count
10
+
11
+ def water!
12
+ self.leaf_count += 1
13
+ end
14
+ end
15
+
16
+
17
+ describe 'before_validation callback' do
18
+ before :each do
19
+ @tree = Tree.new(:leaf_count => 1, :root_count => 1)
20
+ end
21
+
22
+ it "should call water! when validated" do
23
+ @tree.leaf_count.should == 1
24
+ @tree.should be_valid
25
+ @tree.leaf_count.should == 2
26
+ end
27
+
28
+ it "should call lambda when validated" do
29
+ @tree.root_count.should == 1
30
+ @tree.should be_valid
31
+ @tree.root_count.should == 2
32
+ end
33
+ end
@@ -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