couchobject 0.5.0 → 0.6.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.
Files changed (63) hide show
  1. data/History.txt +10 -0
  2. data/Manifest.txt +30 -6
  3. data/README.txt +580 -42
  4. data/TODO +2 -2
  5. data/config/hoe.rb +1 -1
  6. data/lib/couch_object.rb +7 -2
  7. data/lib/couch_object/database.rb +19 -34
  8. data/lib/couch_object/document.rb +13 -6
  9. data/lib/couch_object/error_classes.rb +110 -0
  10. data/lib/couch_object/persistable.rb +954 -36
  11. data/lib/couch_object/persistable/has_many_relations_array.rb +91 -0
  12. data/lib/couch_object/persistable/meta_classes.rb +568 -0
  13. data/lib/couch_object/persistable/overloaded_methods.rb +209 -0
  14. data/lib/couch_object/server.rb +1 -1
  15. data/lib/couch_object/utils.rb +44 -0
  16. data/lib/couch_object/version.rb +1 -1
  17. data/lib/couch_object/view.rb +129 -6
  18. data/script/console +0 -0
  19. data/script/destroy +0 -0
  20. data/script/generate +0 -0
  21. data/script/txt2html +0 -0
  22. data/spec/database_spec.rb +23 -31
  23. data/spec/database_spec.rb.orig +173 -0
  24. data/spec/document_spec.rb +21 -3
  25. data/spec/integration/database_integration_spec.rb +46 -15
  26. data/spec/integration/integration_helper.rb +3 -3
  27. data/spec/persistable/callback.rb +44 -0
  28. data/spec/persistable/callback_spec.rb +44 -0
  29. data/spec/persistable/cloning.rb +77 -0
  30. data/spec/persistable/cloning_spec.rb +77 -0
  31. data/spec/persistable/comparing_objects.rb +350 -0
  32. data/spec/persistable/comparing_objects_spec.rb +350 -0
  33. data/spec/persistable/deleting.rb +113 -0
  34. data/spec/persistable/deleting_spec.rb +113 -0
  35. data/spec/persistable/error_messages.rb +32 -0
  36. data/spec/persistable/error_messages_spec.rb +32 -0
  37. data/spec/persistable/loading.rb +339 -0
  38. data/spec/persistable/loading_spec.rb +339 -0
  39. data/spec/persistable/new_methods.rb +70 -0
  40. data/spec/persistable/new_methods_spec.rb +70 -0
  41. data/spec/persistable/persistable_helper.rb +194 -0
  42. data/spec/persistable/relations.rb +470 -0
  43. data/spec/persistable/relations_spec.rb +470 -0
  44. data/spec/persistable/saving.rb +137 -0
  45. data/spec/persistable/saving_spec.rb +137 -0
  46. data/spec/persistable/setting_storage_location.rb +65 -0
  47. data/spec/persistable/setting_storage_location_spec.rb +65 -0
  48. data/spec/persistable/timestamps.rb +76 -0
  49. data/spec/persistable/timestamps_spec.rb +76 -0
  50. data/spec/persistable/unsaved_changes.rb +211 -0
  51. data/spec/persistable/unsaved_changes_spec.rb +211 -0
  52. data/spec/server_spec.rb +5 -5
  53. data/spec/utils_spec.rb +60 -0
  54. data/spec/view_spec.rb +40 -7
  55. data/website/index.html +22 -7
  56. data/website/index.txt +13 -5
  57. metadata +93 -61
  58. data/bin/couch_ruby_view_requestor +0 -81
  59. data/lib/couch_object/model.rb +0 -5
  60. data/lib/couch_object/proc_condition.rb +0 -14
  61. data/spec/model_spec.rb +0 -5
  62. data/spec/persistable_spec.rb +0 -91
  63. data/spec/proc_condition_spec.rb +0 -26
@@ -0,0 +1,137 @@
1
+ require File.dirname(__FILE__) + '/persistable_helper.rb'
2
+
3
+ describe CouchObject::Persistable, "behaviour related to saving:" do
4
+ before(:each) do
5
+ @bike = Bike.new
6
+ @with_location = WithStorageLocation.new
7
+
8
+ @db = mock("mock db")
9
+
10
+ content = HTTPResponse.new(JSON.unparse({
11
+ "_id" => "123BAC",
12
+ "_rev" => "946B7D1C",
13
+ "class" => Bike,
14
+ "created_at" => Time.new,
15
+ "updated_at" => Time.new,
16
+ "attributes" => {
17
+ "wheels" => 3
18
+ }
19
+ }))
20
+
21
+ @empty_response = {}
22
+ @ok_response = {"ok" => true}
23
+ @document_response = CouchObject::Response.new(content)
24
+ end
25
+
26
+ it "should raise an error if the saving location is blank" do
27
+ @bike.set_location = ""
28
+ lambda{ @bike.save }.should \
29
+ raise_error(CouchObject::Errors::NoDatabaseLocationSet)
30
+ end
31
+
32
+ it "should raise an error if a updating conflict occurs." do
33
+ CouchObject::Database.should_receive(:open).exactly(4).and_return(@db)
34
+
35
+ @db.should_receive(:get).twice.
36
+ with("123BAC").and_return(@document_response)
37
+
38
+ error_from_server = HTTPResponse.
39
+ new(%{{"error":"not_found","reason":"missing"}})
40
+
41
+ error_response = CouchObject::Response.new(error_from_server)
42
+
43
+ bike_1 = Bike.get_by_id("123BAC", "foo")
44
+ bike_2 = Bike.get_by_id("123BAC", "foo")
45
+ bike_2.instance_variable_set("@id","1")
46
+
47
+ @db.should_receive(:put).once.with("123BAC",bike_1.to_json).
48
+ and_return(@document_response)
49
+ @db.should_receive(:put).once.with("1",bike_2.to_json).
50
+ and_return(error_response)
51
+
52
+ bike_1.save("foo_db")
53
+ lambda{ bike_2.save("foo_db") }.should \
54
+ raise_error(CouchObject::Errors::DatabaseSaveFailed)
55
+
56
+ end
57
+
58
+ it "should be able to save without a location argument if it has been previously saved" do
59
+ CouchObject::Database.should_receive(:open).and_return(@db)
60
+ @db.should_receive(:post).
61
+ with("", @bike.to_json).and_return(@document_response)
62
+
63
+ @bike.set_storage_location = "foo"
64
+ @bike.save
65
+ end
66
+
67
+ it "should return the doc id on successfull save" do
68
+ CouchObject::Database.should_receive(:open).and_return(@db)
69
+ @db.should_receive(:post).
70
+ with("", @bike.to_json).and_return(@document_response)
71
+ @bike.save("foo")[:id].should == "123BAC"
72
+ end
73
+
74
+ it "should return the doc revision on successfull save" do
75
+ CouchObject::Database.should_receive(:open).and_return(@db)
76
+ @db.should_receive(:post).
77
+ with("", @bike.to_json).and_return(@document_response)
78
+ @bike.save("foo")[:revision].should == "946B7D1C"
79
+ end
80
+
81
+ it "should assign the returned id to itself on successful save" do
82
+ CouchObject::Database.should_receive(:open).and_return(@db)
83
+ @db.should_receive(:post).
84
+ with("", @bike.to_json).and_return(@document_response)
85
+ @bike.save("foo")
86
+ @bike.id.should == "123BAC"
87
+ end
88
+
89
+ it "should assign the returned revision to itself on successful save" do
90
+ CouchObject::Database.should_receive(:open).and_return(@db)
91
+ @db.should_receive(:post).
92
+ with("", @bike.to_json).and_return(@document_response)
93
+ @bike.save("foo")
94
+ @bike.revision.should == "946B7D1C"
95
+ end
96
+
97
+ it "should know if itself is a unsaved (new) object" do
98
+ CouchObject::Database.should_receive(:open).twice.and_return(@db)
99
+ @db.should_receive(:post).
100
+ with("", @bike.to_json).and_return(@document_response)
101
+
102
+ @bike.new?.should == true
103
+ @bike.save("foo")
104
+ @bike.new?.should_not == true
105
+
106
+ @db.should_receive(:put).
107
+ with("123BAC", @bike.to_json).and_return(@document_response)
108
+
109
+ @bike.save
110
+ @bike.new?.should_not == true
111
+ end
112
+
113
+ it "classes with the storage location set by default should be able to save without supplying an uri" do
114
+ CouchObject::Database.should_receive(:open).and_return(@db)
115
+ @db.should_receive(:post).
116
+ with("", @with_location.to_json).and_return(@document_response)
117
+
118
+ response = @with_location.save
119
+ response.should be_a_kind_of(Hash)
120
+ response[:id].should_not == nil
121
+ response[:revision].should_not == nil
122
+ end
123
+
124
+ it "should be able to save a class that has no :to_couch method but variables" do
125
+ CouchObject::Database.should_receive(:open).and_return(@db)
126
+
127
+ motor_bike = MotorBike.new
128
+ motor_bike.set_location = "foo"
129
+
130
+ @db.should_receive(:post).
131
+ with("", motor_bike.to_json).and_return(@document_response)
132
+
133
+ response = motor_bike.save
134
+ response[:id].should_not == nil
135
+ response[:revision].should_not == nil
136
+ end
137
+ end
@@ -0,0 +1,137 @@
1
+ require File.dirname(__FILE__) + '/persistable_helper.rb'
2
+
3
+ describe CouchObject::Persistable, "behaviour related to saving:" do
4
+ before(:each) do
5
+ @bike = Bike.new
6
+ @with_location = WithStorageLocation.new
7
+
8
+ @db = mock("mock db")
9
+
10
+ content = HTTPResponse.new(JSON.unparse({
11
+ "_id" => "123BAC",
12
+ "_rev" => "946B7D1C",
13
+ "class" => Bike,
14
+ "created_at" => Time.new,
15
+ "updated_at" => Time.new,
16
+ "attributes" => {
17
+ "wheels" => 3
18
+ }
19
+ }))
20
+
21
+ @empty_response = {}
22
+ @ok_response = {"ok" => true}
23
+ @document_response = CouchObject::Response.new(content)
24
+ end
25
+
26
+ it "should raise an error if the saving location is blank" do
27
+ @bike.set_location = ""
28
+ lambda{ @bike.save }.should \
29
+ raise_error(CouchObject::Errors::NoDatabaseLocationSet)
30
+ end
31
+
32
+ it "should raise an error if a updating conflict occurs." do
33
+ CouchObject::Database.should_receive(:open).exactly(4).and_return(@db)
34
+
35
+ @db.should_receive(:get).twice.
36
+ with("123BAC").and_return(@document_response)
37
+
38
+ error_from_server = HTTPResponse.
39
+ new(%{{"error":"not_found","reason":"missing"}})
40
+
41
+ error_response = CouchObject::Response.new(error_from_server)
42
+
43
+ bike_1 = Bike.get_by_id("123BAC", "foo")
44
+ bike_2 = Bike.get_by_id("123BAC", "foo")
45
+ bike_2.instance_variable_set("@id","1")
46
+
47
+ @db.should_receive(:put).once.with("123BAC",bike_1.to_json).
48
+ and_return(@document_response)
49
+ @db.should_receive(:put).once.with("1",bike_2.to_json).
50
+ and_return(error_response)
51
+
52
+ bike_1.save("foo_db")
53
+ lambda{ bike_2.save("foo_db") }.should \
54
+ raise_error(CouchObject::Errors::DatabaseSaveFailed)
55
+
56
+ end
57
+
58
+ it "should be able to save without a location argument if it has been previously saved" do
59
+ CouchObject::Database.should_receive(:open).and_return(@db)
60
+ @db.should_receive(:post).
61
+ with("", @bike.to_json).and_return(@document_response)
62
+
63
+ @bike.set_storage_location = "foo"
64
+ @bike.save
65
+ end
66
+
67
+ it "should return the doc id on successfull save" do
68
+ CouchObject::Database.should_receive(:open).and_return(@db)
69
+ @db.should_receive(:post).
70
+ with("", @bike.to_json).and_return(@document_response)
71
+ @bike.save("foo")[:id].should == "123BAC"
72
+ end
73
+
74
+ it "should return the doc revision on successfull save" do
75
+ CouchObject::Database.should_receive(:open).and_return(@db)
76
+ @db.should_receive(:post).
77
+ with("", @bike.to_json).and_return(@document_response)
78
+ @bike.save("foo")[:revision].should == "946B7D1C"
79
+ end
80
+
81
+ it "should assign the returned id to itself on successful save" do
82
+ CouchObject::Database.should_receive(:open).and_return(@db)
83
+ @db.should_receive(:post).
84
+ with("", @bike.to_json).and_return(@document_response)
85
+ @bike.save("foo")
86
+ @bike.id.should == "123BAC"
87
+ end
88
+
89
+ it "should assign the returned revision to itself on successful save" do
90
+ CouchObject::Database.should_receive(:open).and_return(@db)
91
+ @db.should_receive(:post).
92
+ with("", @bike.to_json).and_return(@document_response)
93
+ @bike.save("foo")
94
+ @bike.revision.should == "946B7D1C"
95
+ end
96
+
97
+ it "should know if itself is a unsaved (new) object" do
98
+ CouchObject::Database.should_receive(:open).twice.and_return(@db)
99
+ @db.should_receive(:post).
100
+ with("", @bike.to_json).and_return(@document_response)
101
+
102
+ @bike.new?.should == true
103
+ @bike.save("foo")
104
+ @bike.new?.should_not == true
105
+
106
+ @db.should_receive(:put).
107
+ with("123BAC", @bike.to_json).and_return(@document_response)
108
+
109
+ @bike.save
110
+ @bike.new?.should_not == true
111
+ end
112
+
113
+ it "classes with the storage location set by default should be able to save without supplying an uri" do
114
+ CouchObject::Database.should_receive(:open).and_return(@db)
115
+ @db.should_receive(:post).
116
+ with("", @with_location.to_json).and_return(@document_response)
117
+
118
+ response = @with_location.save
119
+ response.should be_a_kind_of(Hash)
120
+ response[:id].should_not == nil
121
+ response[:revision].should_not == nil
122
+ end
123
+
124
+ it "should be able to save a class that has no :to_couch method but variables" do
125
+ CouchObject::Database.should_receive(:open).and_return(@db)
126
+
127
+ motor_bike = MotorBike.new
128
+ motor_bike.set_location = "foo"
129
+
130
+ @db.should_receive(:post).
131
+ with("", motor_bike.to_json).and_return(@document_response)
132
+
133
+ response = motor_bike.save
134
+ response[:id].should_not == nil
135
+ response[:revision].should_not == nil
136
+ end
137
+ end
@@ -0,0 +1,65 @@
1
+ require File.dirname(__FILE__) + '/persistable_helper.rb'
2
+
3
+ describe CouchObject::Persistable, "setting the storage location:" do
4
+ before(:each) do
5
+ @bike = Bike.new
6
+ @db = "http://localhost:5984/mydb"
7
+ @with_location = WithStorageLocation.new
8
+ @db = "http://localhost:5984/mydb"
9
+
10
+ content = HTTPResponse.new(JSON.unparse({
11
+ "_id" => "123BAC",
12
+ "_rev" => "946B7D1C",
13
+ }))
14
+
15
+ CouchObject::Response.stub!(:body).and_return(content)
16
+
17
+ @empty_response = {}
18
+ @ok_response = {"ok" => true}
19
+ @document_response = CouchObject::Response.new(content)
20
+ end
21
+
22
+ it "the storage location should be blank if not set at class level" do
23
+ @bike.location.should == nil
24
+ @bike.storage_location.should == nil
25
+ end
26
+
27
+ it "should be possible to change the storage location for instances" do
28
+ location = @bike.location
29
+ @bike.set_location = "foo"
30
+ @bike.location.should_not == location
31
+
32
+ location = @bike.storage_location
33
+ @bike.set_storage_location = "bar"
34
+ @bike.storage_location.should_not == location
35
+ end
36
+
37
+ it "setting the storage location to a blank string should make it nil" do
38
+ @bike.set_location = "foo"
39
+ @bike.set_location = ""
40
+ @bike.location.should == nil
41
+
42
+ @bike.set_storage_location = "foo"
43
+ @bike.set_storage_location = ""
44
+ @bike.location.should == nil
45
+ end
46
+
47
+ it "setting the location using one of the getters should raise an error" do
48
+ lambda{ @bike.location = "" }.should raise_error(NoMethodError)
49
+ lambda{ @bike.storage_location = "" }.should raise_error(NoMethodError)
50
+ end
51
+
52
+ it "classes with the storage location should have a location by default" do
53
+ @with_location.location.should == @db
54
+ end
55
+
56
+ it "classes with the storage location set by default should be able to change it" do
57
+ @with_location.set_location = "foo"
58
+ @with_location.location.should == "foo"
59
+ end
60
+
61
+ it "a base class should know it's storage location if it has been set by default" do
62
+ WithStorageLocation::location.should == @db
63
+ end
64
+ end
65
+
@@ -0,0 +1,65 @@
1
+ require File.dirname(__FILE__) + '/persistable_helper.rb'
2
+
3
+ describe CouchObject::Persistable, "setting the storage location:" do
4
+ before(:each) do
5
+ @bike = Bike.new
6
+ @db = "http://localhost:5984/mydb"
7
+ @with_location = WithStorageLocation.new
8
+ @db = "http://localhost:5984/mydb"
9
+
10
+ content = HTTPResponse.new(JSON.unparse({
11
+ "_id" => "123BAC",
12
+ "_rev" => "946B7D1C",
13
+ }))
14
+
15
+ CouchObject::Response.stub!(:body).and_return(content)
16
+
17
+ @empty_response = {}
18
+ @ok_response = {"ok" => true}
19
+ @document_response = CouchObject::Response.new(content)
20
+ end
21
+
22
+ it "the storage location should be blank if not set at class level" do
23
+ @bike.location.should == nil
24
+ @bike.storage_location.should == nil
25
+ end
26
+
27
+ it "should be possible to change the storage location for instances" do
28
+ location = @bike.location
29
+ @bike.set_location = "foo"
30
+ @bike.location.should_not == location
31
+
32
+ location = @bike.storage_location
33
+ @bike.set_storage_location = "bar"
34
+ @bike.storage_location.should_not == location
35
+ end
36
+
37
+ it "setting the storage location to a blank string should make it nil" do
38
+ @bike.set_location = "foo"
39
+ @bike.set_location = ""
40
+ @bike.location.should == nil
41
+
42
+ @bike.set_storage_location = "foo"
43
+ @bike.set_storage_location = ""
44
+ @bike.location.should == nil
45
+ end
46
+
47
+ it "setting the location using one of the getters should raise an error" do
48
+ lambda{ @bike.location = "" }.should raise_error(NoMethodError)
49
+ lambda{ @bike.storage_location = "" }.should raise_error(NoMethodError)
50
+ end
51
+
52
+ it "classes with the storage location should have a location by default" do
53
+ @with_location.location.should == @db
54
+ end
55
+
56
+ it "classes with the storage location set by default should be able to change it" do
57
+ @with_location.set_location = "foo"
58
+ @with_location.location.should == "foo"
59
+ end
60
+
61
+ it "a base class should know it's storage location if it has been set by default" do
62
+ WithStorageLocation::location.should == @db
63
+ end
64
+ end
65
+
@@ -0,0 +1,76 @@
1
+ require File.dirname(__FILE__) + '/persistable_helper.rb'
2
+
3
+ describe CouchObject::Persistable, "timestamp related actions:" do
4
+ before(:each) do
5
+ @bike = Bike.new
6
+ @timestampclass = WithTimeStamp.new
7
+
8
+ @db = mock("mock db")
9
+
10
+ content = HTTPResponse.new(JSON.unparse({
11
+ "_id" => "123BAC",
12
+ "_rev" => "946B7D1C",
13
+ "created_at" => Time.new,
14
+ "updated_at" => Time.new,
15
+ "class" => "WithTimeStamp",
16
+ "attributes" => {
17
+ "wheels" => 3
18
+ }
19
+ }))
20
+
21
+ CouchObject::Response.stub!(:body).and_return(content)
22
+
23
+ @empty_response = {}
24
+ @ok_response = {"ok" => true}
25
+ @document_response = CouchObject::Response.new(content)
26
+ end
27
+
28
+ it "timestamps should be nil for classes that don't include them" do
29
+ @bike.created_at.should == nil
30
+ @bike.updated_at.should == nil
31
+ end
32
+
33
+ it "timestamps should be set when saving an object" do
34
+ CouchObject::Database.should_receive(:open).and_return(@db)
35
+ timestampclass_json = @timestampclass.to_json
36
+
37
+ @timestampclass.stub!(:to_json).and_return(timestampclass_json)
38
+ @db.should_receive(:post).
39
+ with("", timestampclass_json).and_return(@document_response)
40
+
41
+ @timestampclass.save("foo")
42
+
43
+ @timestampclass.created_at.should_not == nil
44
+ @timestampclass.updated_at.should_not == nil
45
+ end
46
+
47
+ it "should update updated_at when saving an object again" do
48
+ CouchObject::Database.stub!(:open).and_return(@db)
49
+ timestampclass_json = @timestampclass.to_json
50
+
51
+ @timestampclass.stub!(:to_json).and_return(timestampclass_json)
52
+ @db.should_receive(:post).
53
+ with("", timestampclass_json).and_return(@document_response)
54
+ @db.should_receive(:put).
55
+ with("123BAC", timestampclass_json).and_return(@document_response)
56
+
57
+ @timestampclass.save("foo")
58
+ updated_at = @timestampclass.updated_at
59
+
60
+ @timestampclass.save
61
+
62
+ @timestampclass.updated_at.should_not == updated_at
63
+ end
64
+
65
+ it "loaded object should have their timestamps set" do
66
+ CouchObject::Database.should_receive(:open).and_return(@db)
67
+ @db.should_receive(:get).with("123BAC").and_return(@document_response)
68
+
69
+ timestampclass = WithTimeStamp.get_by_id("123BAC", "foo")
70
+
71
+ timestampclass.class.should == WithTimeStamp
72
+ timestampclass.created_at.should_not == nil
73
+ timestampclass.updated_at.should_not == nil
74
+ end
75
+ end
76
+