activecouch 0.1.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 (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