activecouch 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README +42 -0
  3. data/Rakefile +31 -0
  4. data/VERSION +1 -0
  5. data/lib/active_couch.rb +18 -0
  6. data/lib/active_couch/associations.rb +1 -0
  7. data/lib/active_couch/associations/has_many_association.rb +35 -0
  8. data/lib/active_couch/attribute.rb +46 -0
  9. data/lib/active_couch/base.rb +458 -0
  10. data/lib/active_couch/callbacks.rb +81 -0
  11. data/lib/active_couch/connection.rb +155 -0
  12. data/lib/active_couch/errors.rb +17 -0
  13. data/lib/active_couch/migrations.rb +3 -0
  14. data/lib/active_couch/migrations/errors.rb +4 -0
  15. data/lib/active_couch/migrations/migration.rb +77 -0
  16. data/lib/active_couch/migrations/migrator.rb +53 -0
  17. data/lib/active_couch/support.rb +2 -0
  18. data/lib/active_couch/support/extensions.rb +92 -0
  19. data/lib/active_couch/support/inflections.rb +52 -0
  20. data/lib/active_couch/support/inflector.rb +280 -0
  21. data/spec/attribute/initialize_spec.rb +138 -0
  22. data/spec/base/after_delete_spec.rb +107 -0
  23. data/spec/base/after_save_spec.rb +99 -0
  24. data/spec/base/before_delete_spec.rb +106 -0
  25. data/spec/base/before_save_spec.rb +98 -0
  26. data/spec/base/create_spec.rb +27 -0
  27. data/spec/base/database_spec.rb +65 -0
  28. data/spec/base/delete_spec.rb +78 -0
  29. data/spec/base/find_spec.rb +165 -0
  30. data/spec/base/from_json_spec.rb +48 -0
  31. data/spec/base/has_many_spec.rb +81 -0
  32. data/spec/base/has_spec.rb +76 -0
  33. data/spec/base/id_spec.rb +22 -0
  34. data/spec/base/initialize_spec.rb +43 -0
  35. data/spec/base/module_spec.rb +18 -0
  36. data/spec/base/nested_class_spec.rb +19 -0
  37. data/spec/base/rev_spec.rb +16 -0
  38. data/spec/base/save_spec.rb +65 -0
  39. data/spec/base/site_spec.rb +41 -0
  40. data/spec/base/to_json_spec.rb +64 -0
  41. data/spec/connection/initialize_spec.rb +28 -0
  42. data/spec/has_many_association/initialize_spec.rb +33 -0
  43. data/spec/migration/define_spec.rb +29 -0
  44. data/spec/migration/include_attributes_spec.rb +30 -0
  45. data/spec/migration/view_js_spec.rb +46 -0
  46. data/spec/migration/with_filter_spec.rb +13 -0
  47. data/spec/migration/with_key_spec.rb +13 -0
  48. data/spec/migrator/create_database_spec.rb +48 -0
  49. data/spec/migrator/delete_database_spec.rb +46 -0
  50. data/spec/migrator/migrate_spec.rb +99 -0
  51. data/spec/spec_helper.rb +9 -0
  52. metadata +104 -0
@@ -0,0 +1,78 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe "ActiveCouch::Base #delete instance-level method" do
4
+ before(:each) do
5
+ class Person < ActiveCouch::Base
6
+ site 'http://localhost:5984/'
7
+ has :name
8
+ end
9
+ ActiveCouch::Migrator.create_database('http://localhost:5984/', 'people')
10
+ @person = Person.create(:name => 'McLovin')
11
+ end
12
+
13
+ after(:each) do
14
+ ActiveCouch::Migrator.delete_database('http://localhost:5984/', 'people')
15
+ end
16
+
17
+ it "should have an instance method called delete" do
18
+ @person.methods.include?('delete').should == true
19
+ end
20
+
21
+ it "should be able to delete itself from the CouchDB database and return true" do
22
+ @person.delete.should == true
23
+ @person.id.should == nil
24
+ @person.rev.should == nil
25
+ # Check whether document has actually been deleted
26
+ response = Net::HTTP.get_response URI.parse("http://localhost:5984/people/_all_docs/")
27
+ response.body.index('"total_rows":0').should_not == nil
28
+ end
29
+
30
+ it "should raise an error if the revision for the object is not set and is attempted to be deleted" do
31
+ p = Person.new(:name => 'McLovin')
32
+ lambda { p.delete }.should raise_error(ArgumentError, "You must specify a revision for the document to be deleted")
33
+ end
34
+
35
+ it "should raise an error if the id for the object is not set, but the revision is set and is attempted to be deleted" do
36
+ p = Person.new(:name => 'McLovin')
37
+ p.rev = '123'
38
+ lambda { p.delete }.should raise_error(ArgumentError, "You must specify an ID for the document to be deleted")
39
+ end
40
+ end
41
+
42
+ describe "ActiveCouch::Base #delete class-level method" do
43
+ before(:each) do
44
+ class Person < ActiveCouch::Base
45
+ site 'http://localhost:5984/'
46
+ has :name
47
+ end
48
+ ActiveCouch::Migrator.create_database('http://localhost:5984/', 'people')
49
+ @person = Person.create(:name => 'McLovin')
50
+ end
51
+
52
+ after(:each) do
53
+ ActiveCouch::Migrator.delete_database('http://localhost:5984/', 'people')
54
+ end
55
+
56
+ it "should have a class method called delete" do
57
+ Person.methods.include?('delete').should == true
58
+ end
59
+
60
+ it "should be able to delete a CouchDB document and return true after successful deletion" do
61
+ Person.delete(:id => @person.id, :rev => @person.rev).should == true
62
+ # Check whether document has actually been deleted
63
+ response = Net::HTTP.get_response URI.parse("http://localhost:5984/people/_all_docs/")
64
+ response.body.index('"total_rows":0').should_not == nil
65
+ end
66
+
67
+ it "should raise an error if the id is not specified in the options hash" do
68
+ lambda { Person.delete(:rev => 'abc') }.should raise_error(ArgumentError, "You must specify both an id and a rev for the document to be deleted")
69
+ end
70
+
71
+ it "should raise an error if the rev is not specified in the options hash" do
72
+ lambda { Person.delete(:id => 'abc') }.should raise_error(ArgumentError, "You must specify both an id and a rev for the document to be deleted")
73
+ end
74
+
75
+ it "should raise an error if a nil object is passed as a param to delete" do
76
+ lambda { Person.delete(nil) }.should raise_error(ArgumentError, "You must specify both an id and a rev for the document to be deleted")
77
+ end
78
+ end
@@ -0,0 +1,165 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe "ActiveCouch::Base #find method with just simple attributes" do
4
+ before(:each) do
5
+ # Define the model
6
+ class Person < ActiveCouch::Base
7
+ site 'http://localhost:5984'
8
+ has :name
9
+ end
10
+ # Define the migration
11
+ class ByName < ActiveCouch::Migration
12
+ define :for_db => 'people' do
13
+ with_key 'name'
14
+ end
15
+ end
16
+ # Create the database first
17
+ ActiveCouch::Migrator.create_database('http://localhost:5984', 'people')
18
+ # Create a view
19
+ ActiveCouch::Migrator.migrate('http://localhost:5984', ByName)
20
+ # Save an object
21
+ Person.new(:name => 'McLovin').save
22
+ end
23
+
24
+ after(:each) do
25
+ # Delete the database last
26
+ ActiveCouch::Migrator.delete_database('http://localhost:5984', 'people')
27
+ end
28
+
29
+ it "should respond to the find method" do
30
+ Person.should respond_to(:find)
31
+ end
32
+
33
+ it "should return an array with one Person object in it, when sent method find with parameter :all" do
34
+ people = Person.find(:all, :params => {:name => 'McLovin'})
35
+ people.class.should == Array
36
+ # Size of people
37
+ people.size.should == 1
38
+
39
+ people.first.class.should == Person
40
+ people.first.name.should == 'McLovin'
41
+ # Check if id and rev are set
42
+ people.first.id.should_not == nil
43
+ people.first.rev.should_not == nil
44
+ end
45
+
46
+ it "should return one Person object when sent method find with parameter :one" do
47
+ person = Person.find(:first, :params => {:name => 'McLovin'})
48
+ person.class.should == Person
49
+ person.name.should == 'McLovin'
50
+ # Check if id and rev are set
51
+ person.id.should_not == nil
52
+ person.rev.should_not == nil
53
+ end
54
+
55
+ it "should return an empty array when sent method find with parameter :all and is not able to find any" do
56
+ people = Person.find(:all, :params => {:name => 'Seth'})
57
+ people.class.should == Array
58
+ people.size.should == 0
59
+ end
60
+
61
+ it "should return a nil object when sent method find with parameter :first and is not able to find any" do
62
+ person = Person.find(:first, :params => {:name => 'Seth'})
63
+ person.should == nil
64
+ end
65
+ end
66
+
67
+ describe "ActiveCouch::Base #find method with multiple documents in the CouchDB database" do
68
+ before(:each) do
69
+ class Person < ActiveCouch::Base
70
+ site 'http://localhost:5984'
71
+
72
+ has :first_name
73
+ has :last_name
74
+ end
75
+
76
+ # Define the migration
77
+ class ByLastName < ActiveCouch::Migration
78
+ define :for_db => 'people' do
79
+ with_key 'last_name'
80
+ end
81
+ end
82
+ # Create the database first
83
+ ActiveCouch::Migrator.create_database('http://localhost:5984', 'people')
84
+ # Create a view
85
+ ActiveCouch::Migrator.migrate('http://localhost:5984', ByLastName)
86
+ # Save two objects
87
+ Person.create(:last_name => 'McLovin', :first_name => 'Seth')
88
+ Person.create(:last_name => 'McLovin', :first_name => 'Bob')
89
+ end
90
+
91
+ after(:each) do
92
+ # Delete the database last
93
+ ActiveCouch::Migrator.delete_database('http://localhost:5984', 'people')
94
+ end
95
+
96
+ it "should find all objects in the database when find method is sent the param :all" do
97
+ people = Person.find(:all, :params => {:last_name => 'McLovin'})
98
+ # Check if it is an array and if the size is 2
99
+ people.class.should == Array
100
+ people.size.should == 2
101
+ # The id's and rev's for all the objects must not be nil
102
+ people.each do |p|
103
+ p.id.should_not == nil
104
+ p.rev.should_not == nil
105
+ end
106
+ end
107
+
108
+ it "should find only the first object in the database when find method is sent with the param :first" do
109
+ people = Person.find(:first, :params => {:last_name => 'McLovin'})
110
+ # Check if this is a Person and if the size is 1
111
+ people.class.should == Person
112
+ end
113
+ end
114
+
115
+ describe "ActiveCouch::Base #find method with an object which has associations" do
116
+ before(:each) do
117
+ class Comment < ActiveCouch::Base
118
+ site 'http://localhost:5984'
119
+ has :body
120
+ end
121
+
122
+ class Blog < ActiveCouch::Base
123
+ site 'http://localhost:5984'
124
+ has :title
125
+ has_many :comments
126
+ end
127
+
128
+ # Define the migration
129
+ class ByTitle < ActiveCouch::Migration
130
+ define :for_db => 'blogs' do
131
+ with_key 'title'
132
+ end
133
+ end
134
+
135
+ # Create the database first
136
+ ActiveCouch::Migrator.create_database('http://localhost:5984', 'blogs')
137
+ # Create a view
138
+ ActiveCouch::Migrator.migrate('http://localhost:5984', ByTitle)
139
+ blog = Blog.new(:title => 'iPhone in Singapore')
140
+ # Associations
141
+ blog.add_comment(Comment.new(:body => 'soon plz'))
142
+ blog.add_comment(Comment.new(:body => 'ya rly!'))
143
+ # Save the blog
144
+ blog.save
145
+ end
146
+
147
+ after(:each) do
148
+ # Create the database first
149
+ ActiveCouch::Migrator.delete_database('http://localhost:5984', 'blogs')
150
+ end
151
+
152
+ it "should be able to retrieve the simple attributes" do
153
+ blog = Blog.find(:first, :params => {:title => 'iPhone in Singapore'})
154
+ blog.title.should == 'iPhone in Singapore'
155
+ end
156
+
157
+ it "should be able to retrieve associations" do
158
+ blog = Blog.find(:first, :params => {:title => 'iPhone in Singapore'})
159
+ blog.comments.size.should == 2
160
+ # Check whether the bodies of the comments exist
161
+ (blog.comments.inspect =~ /soon plz/).should_not == nil
162
+ (blog.comments.inspect =~ /ya rly!/).should_not == nil
163
+ end
164
+
165
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe "ActiveCouch::Base #from_json method, with many attributes" do
4
+ before(:each) do
5
+ class Hotel < ActiveCouch::Base
6
+ has :name, :which_is => :text, :with_default_value => "Swissotel The Stamford"
7
+ has :star_rating, :which_is => :decimal, :with_default_value => 5.0
8
+ has :rooms, :which_is => :number, :with_default_value => 100
9
+ end
10
+
11
+ class Hospital < ActiveCouch::Base
12
+ has :name
13
+ end
14
+
15
+ class CrazyPerson < ActiveCouch::Base
16
+ has :name, :which_is => :text, :with_default_value => "Crazed McLovin"
17
+ has_many :hospitals
18
+ end
19
+ end
20
+
21
+ it "should have the from_json method" do
22
+ Hotel.should respond_to(:from_json)
23
+ Hospital.should respond_to(:from_json)
24
+ CrazyPerson.should respond_to(:from_json)
25
+ end
26
+
27
+ it "should instantiate an object when sent the from_json method with valid json as a parameter" do
28
+ h = Hotel.from_json("{\"name\":\"Swissotel The Stamford\",\"rooms\":200,\"star_rating\":4.0}")
29
+ h.class.should == Hotel
30
+ # Check whether all attributes are set correctly
31
+ h.name.should == "Swissotel The Stamford"
32
+ h.rooms.should == 200
33
+ h.star_rating.should == 4.0
34
+ end
35
+
36
+ it "should instantiate an object when sent the from_json method with valid JSON (containing associations) as a parameter" do
37
+ crazy = CrazyPerson.from_json('{"name":"Crazed McLovin","hospitals":[{"name":"Crazy Hospital 1"},{"name":"Crazy Hospital 2"}]}')
38
+
39
+ crazy.name == "Crazed McLovin"
40
+ crazy.hospitals.size.should == 2
41
+
42
+ hospitals = crazy.hospitals.collect{|h| h.name }
43
+ hospitals.sort!
44
+
45
+ hospitals.first.should == 'Crazy Hospital 1'
46
+ hospitals.last.should == 'Crazy Hospital 2'
47
+ end
48
+ end
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe "A class which is a subclass of ActiveCouch::Base with a has_many association" do
4
+ before(:each) do
5
+ class Person < ActiveCouch::Base
6
+ has :name, :which_is => :text
7
+ end
8
+
9
+ class AgedPerson < ActiveCouch::Base
10
+ has :name
11
+ has :age, :which_is => :number, :with_default_value => 10
12
+ end
13
+
14
+ class Contact < ActiveCouch::Base
15
+ has_many :people
16
+ end
17
+
18
+ @c = Contact.new
19
+ @p1 = Person.new
20
+ @a1 = AgedPerson.new
21
+ end
22
+
23
+ it "should have an instance variable called associations which is a Hash with the key being :people" do
24
+ Contact.associations.class.should == Hash
25
+ Contact.associations.keys.should == [:people]
26
+ end
27
+
28
+ it "should have methods called people and add_person" do
29
+ @c.should respond_to(:people)
30
+ @c.should respond_to(:add_person)
31
+ end
32
+
33
+ it "should have a method called people which returns an empty array" do
34
+ @c.people.should == []
35
+ end
36
+
37
+ it "should be able to add a Person object to the association" do
38
+ @c.add_person(@p1)
39
+ @c.people.should == [@p1]
40
+ end
41
+
42
+ it "should raise an error when trying to add an object which is not of the association's type" do
43
+ lambda{ @c.add_person(@a1) }.should raise_error(ActiveCouch::InvalidCouchTypeError)
44
+ end
45
+ end
46
+
47
+ describe "An object instantiated from class which is a subclass of ActiveCouch::Base" do
48
+ before(:each) do
49
+ class Comment < ActiveCouch::Base
50
+ has :body
51
+ end
52
+
53
+ class Blog < ActiveCouch::Base
54
+ has :title
55
+ has_many :comments
56
+ end
57
+
58
+ @comment1 = Comment.new(:body => "I can haz redbull?")
59
+ @comment2 = Comment.new(:body => 'k thx bai')
60
+ @blog = Blog.new(:title => 'Lolcats Primer', :comments => [@comment1, @comment2])
61
+ @blog1 = Blog.new(:title => 'Lolcats Primer The Sequel', :comments => [{:body => 'can'}, {:body => 'haz'}])
62
+ end
63
+
64
+ it "should be able to initialize with a hash which contains descendents of ActiveCouch::Base" do
65
+ @comment1.body.should == "I can haz redbull?"
66
+ @comment2.body.should == "k thx bai"
67
+
68
+ @blog.title.should == 'Lolcats Primer'
69
+ @blog.comments.should == [@comment1, @comment2]
70
+ end
71
+
72
+ it "should be able to initialize from a hash which contains only Strings" do
73
+ @blog1.title.should == 'Lolcats Primer The Sequel'
74
+
75
+ comment_bodies = @blog1.comments.collect{|c| c.body }
76
+ comment_bodies.sort!
77
+
78
+ comment_bodies.first.should == 'can'
79
+ comment_bodies.last.should == 'haz'
80
+ end
81
+ end
@@ -0,0 +1,76 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe "A class which is a subclass of ActiveCouch::Base" do
4
+ before(:each) do
5
+ class Person < ActiveCouch::Base
6
+ has :name, :which_is => :text
7
+ end
8
+
9
+ @p = Person.new
10
+ end
11
+
12
+ it "should have a method called name which returns the value of the variable name" do
13
+ @p.should respond_to(:name)
14
+ @p.name.should == ""
15
+ end
16
+
17
+ it "should have a method called name= which should let you set the instance variable name" do
18
+ @p.should respond_to(:name=)
19
+ @p.name = "McLovin"
20
+ @p.name.should == "McLovin"
21
+ end
22
+ end
23
+
24
+ describe "A class which is a subclass of ActiveCouch::Base with a default value specified" do
25
+ before(:each) do
26
+ class NamedPerson < ActiveCouch::Base
27
+ has :name, :which_is => :text, :with_default_value => "McLovin"
28
+ end
29
+
30
+ @n = NamedPerson.new
31
+ end
32
+
33
+ it "should have a method called name which returns the value of the variable name" do
34
+ @n.should respond_to(:name)
35
+ @n.name.should == "McLovin"
36
+ end
37
+
38
+ it "should have a method called name= which should let you set the instance variable name" do
39
+ @n.should respond_to(:name=)
40
+ @n.name = "Seth"
41
+ @n.name.should == "Seth"
42
+ end
43
+ end
44
+
45
+ describe "A class which is a subclass of ActiveCouch::Base with a default numerical value specified" do
46
+ before(:each) do
47
+ class AgedPerson < ActiveCouch::Base
48
+ has :name
49
+ has :age, :which_is => :number, :with_default_value => 10
50
+ end
51
+
52
+ @a = AgedPerson.new
53
+ end
54
+
55
+ it "should have an instance variable called attributes which is a Hash with the keys being :name, :age" do
56
+ AgedPerson.attributes.class.should == Hash
57
+ AgedPerson.attributes.keys.index(:name).should_not == nil
58
+ AgedPerson.attributes.keys.index(:age).should_not == nil
59
+ end
60
+
61
+ it "should have methods called name and age which return the values of the variables name and age respectively" do
62
+ @a.should respond_to(:name)
63
+ @a.should respond_to(:age)
64
+
65
+ @a.name.should == ""
66
+ @a.age.should == 10
67
+ end
68
+
69
+ it "should have a method called name= which should let you set the instance variable name" do
70
+ @a.should respond_to(:name=)
71
+ @a.should respond_to(:age=)
72
+
73
+ @a.age = 15
74
+ @a.age.should == 15
75
+ end
76
+ end