aqua 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/Aqua.gemspec +121 -0
  4. data/LICENCE_COUCHREST +176 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +105 -0
  7. data/Rakefile +83 -0
  8. data/VERSION +1 -0
  9. data/lib/aqua.rb +101 -0
  10. data/lib/aqua/object/config.rb +43 -0
  11. data/lib/aqua/object/extensions/ar_convert.rb +0 -0
  12. data/lib/aqua/object/extensions/ar_style.rb +0 -0
  13. data/lib/aqua/object/extensions/property.rb +0 -0
  14. data/lib/aqua/object/extensions/validation.rb +0 -0
  15. data/lib/aqua/object/pack.rb +306 -0
  16. data/lib/aqua/object/query.rb +18 -0
  17. data/lib/aqua/object/stub.rb +122 -0
  18. data/lib/aqua/object/tank.rb +54 -0
  19. data/lib/aqua/object/unpack.rb +253 -0
  20. data/lib/aqua/store/couch_db/attachments.rb +183 -0
  21. data/lib/aqua/store/couch_db/couch_db.rb +151 -0
  22. data/lib/aqua/store/couch_db/database.rb +186 -0
  23. data/lib/aqua/store/couch_db/design_document.rb +57 -0
  24. data/lib/aqua/store/couch_db/http_client/adapter/rest_client.rb +53 -0
  25. data/lib/aqua/store/couch_db/http_client/rest_api.rb +62 -0
  26. data/lib/aqua/store/couch_db/server.rb +103 -0
  27. data/lib/aqua/store/couch_db/storage_methods.rb +405 -0
  28. data/lib/aqua/store/storage.rb +59 -0
  29. data/lib/aqua/support/initializers.rb +216 -0
  30. data/lib/aqua/support/mash.rb +144 -0
  31. data/lib/aqua/support/set.rb +23 -0
  32. data/lib/aqua/support/string_extensions.rb +121 -0
  33. data/spec/aqua_spec.rb +19 -0
  34. data/spec/object/config_spec.rb +58 -0
  35. data/spec/object/object_fixtures/array_udder.rb +5 -0
  36. data/spec/object/object_fixtures/canned_hash.rb +5 -0
  37. data/spec/object/object_fixtures/gerbilmiester.rb +18 -0
  38. data/spec/object/object_fixtures/grounded.rb +13 -0
  39. data/spec/object/object_fixtures/log.rb +19 -0
  40. data/spec/object/object_fixtures/persistent.rb +12 -0
  41. data/spec/object/object_fixtures/sugar.rb +4 -0
  42. data/spec/object/object_fixtures/user.rb +38 -0
  43. data/spec/object/pack_spec.rb +607 -0
  44. data/spec/object/query_spec.rb +27 -0
  45. data/spec/object/stub_spec.rb +51 -0
  46. data/spec/object/tank_spec.rb +61 -0
  47. data/spec/object/unpack_spec.rb +361 -0
  48. data/spec/spec.opts +3 -0
  49. data/spec/spec_helper.rb +16 -0
  50. data/spec/store/couchdb/attachments_spec.rb +164 -0
  51. data/spec/store/couchdb/couch_db_spec.rb +104 -0
  52. data/spec/store/couchdb/database_spec.rb +161 -0
  53. data/spec/store/couchdb/design_document_spec.rb +43 -0
  54. data/spec/store/couchdb/fixtures_and_data/document_fixture.rb +3 -0
  55. data/spec/store/couchdb/fixtures_and_data/image_attach.png +0 -0
  56. data/spec/store/couchdb/server_spec.rb +96 -0
  57. data/spec/store/couchdb/storage_methods_spec.rb +408 -0
  58. data/utils/code_statistics.rb +134 -0
  59. data/utils/console +11 -0
  60. metadata +136 -0
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format specdoc
3
+ --loadby mtime
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'aqua'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+
8
+ def require_fixtures
9
+ Dir[ File.dirname(__FILE__) + "/object/object_fixtures/**/*.rb" ].each do |file|
10
+ require file
11
+ end
12
+ end
13
+
14
+
15
+ Spec::Runner.configure do |config|
16
+ end
@@ -0,0 +1,164 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ Aqua.set_storage_engine('CouchDB') # to initialize the Aqua::Store namespace
4
+ require File.dirname(__FILE__) + '/fixtures_and_data/document_fixture' # Document ... a Mash with the collection of methods
5
+
6
+ # Conveniences for typing with tests ...
7
+ CouchDB = Aqua::Store::CouchDB unless defined?( CouchDB )
8
+ Attachments = CouchDB::Attachments unless defined?( Attachments )
9
+
10
+ describe CouchDB::Attachments do
11
+ before(:each) do
12
+ Aqua::Storage.database.delete_all
13
+ @doc = Document.new(:id => 'attachments_doc')
14
+ @attachments = Attachments.new( @doc )
15
+ @file = File.new( File.dirname( __FILE__ ) + '/fixtures_and_data/image_attach.png' )
16
+ end
17
+
18
+ describe 'initialization' do
19
+ it 'should initialize with a document uri' do
20
+ lambda{ Attachments.new }.should raise_error( ArgumentError )
21
+ lambda{ Attachments.new( @doc )}.should_not raise_error( ArgumentError )
22
+ end
23
+
24
+ it 'should initialize with an optional hash' do
25
+ lambda{ Attachments.new( @doc, {:my_file => @file})}.should_not raise_error( ArgumentError )
26
+ end
27
+
28
+ it 'when initializing with a hash, it should check that each key is a string and each value is a file' do
29
+ lambda{ Attachments.new( @doc, { 1 => @file }) }.should raise_error( ArgumentError )
30
+ lambda{ Attachments.new( @doc, {:my_file => 1}) }.should raise_error( ArgumentError )
31
+ end
32
+
33
+ it 'document should be an object reference to the original document, not a dup' do
34
+ @attachments.document.should === @doc
35
+ end
36
+ end
37
+
38
+ describe 'attachment_uri' do
39
+ it 'should raise an error if the document has no id' do
40
+ attachments = Attachments.new( Document.new )
41
+ attachments.add( :my_file, @file )
42
+ lambda{ attachments.uri_for( :my_file ) }.should raise_error( ArgumentError )
43
+ end
44
+
45
+ it 'should not include revision information if the document is new' do
46
+ @attachments.add( :my_file, @file )
47
+ @attachments.uri_for( :my_file ).should_not include( '?rev=')
48
+ end
49
+
50
+ it 'should include revision information if the document has been saved' do
51
+ @doc.save!
52
+ @attachments.add( :my_file, @file )
53
+ @attachments.uri_for( :my_file ).should include( '?rev=')
54
+ end
55
+
56
+ it 'should construct a valid attachment uri' do
57
+ @attachments.add(:my_file, @file )
58
+ @attachments.uri_for( :my_file ).should == "http://127.0.0.1:5984/aqua/attachments_doc/my_file"
59
+ end
60
+
61
+ it 'should construct a get attachment uri without the revision information' do
62
+ @doc.save!
63
+ @attachments.add( :my_file, @file )
64
+ @attachments.uri_for( :my_file, false ).should_not include( '?rev=')
65
+ end
66
+ end
67
+
68
+ describe 'adding attachments' do
69
+ it 'should have a method #add that takes a name and a file' do
70
+ @attachments.should respond_to( :add )
71
+ lambda{ @attachments.add }.should raise_error( ArgumentError )
72
+ lambda{ @attachments.add( :my_file ) }.should raise_error( ArgumentError )
73
+ lambda{ @attachments.add( :my_file, :not_a_file ) }.should raise_error( ArgumentError )
74
+ lambda{ @attachments.add( [], @file ) }.should raise_error( ArgumentError )
75
+ lambda{ @attachments.add( :my_file, @file ) }.should_not raise_error( ArgumentError )
76
+ end
77
+
78
+ it 'should add a valid hash to the attachments container' do
79
+ @attachments.add( :my_file, @file )
80
+ @attachments[:my_file].should == @file
81
+ end
82
+
83
+ it 'should save the attachment to the database' do
84
+ lambda{ @attachments.add!( :my_file, @file ) }.should_not raise_error
85
+ lambda{ CouchDB.get( @attachments.uri_for(:my_file) ) }.should_not raise_error
86
+ end
87
+
88
+ it 'should have the right mime-type after addition to database' do
89
+ @attachments.add!( :my_file, @file )
90
+ attach_hash = CouchDB.get( @attachments.uri_for(:my_file) )
91
+ attach_hash['content_type'].should == 'image/png'
92
+ end
93
+ end
94
+
95
+ describe 'removing attachments' do
96
+ it '#delete should delete an attachment from the collection' do
97
+ @attachments.add( :my_file, @file )
98
+ @attachments.delete( :my_file ).should == @file
99
+ @attachments[:my_file].should be_nil
100
+ end
101
+
102
+ it '#delete! should remove an attachment from the collection and database' do
103
+ @attachments.add!( :my_file, @file )
104
+ @attachments.delete!( :my_file )
105
+ lambda{ CouchDB.get( @attachments.uri_for(:my_file) ) }.should raise_error #( Aqua::ObjectNotFound )
106
+ end
107
+ end
108
+
109
+ describe 'retrieving attachments' do
110
+ it 'should return a file if found locally' do
111
+ @attachments.add!( :my_file, @file )
112
+ @attachments.should_not_receive(:get!)
113
+ @attachments.get(:my_file).should == @file
114
+ end
115
+
116
+ it 'should request a file from the database when not found locally' do
117
+ @attachments.add!( :my_file, @file )
118
+ @attachments.delete( :my_file ) # just deletes the local reference
119
+ @attachments.should_receive(:get!)
120
+ @attachments.get(:my_file)
121
+ end
122
+
123
+ it 'should return a Tempfile from the database' do
124
+ @attachments.add!( :my_file, @file )
125
+ @attachments.delete( :my_file ) # just deletes the local reference
126
+ @attachments.get(:my_file).class.should == Tempfile
127
+ end
128
+
129
+ it 'should have the same data as the original file' do
130
+ @attachments.add!( :my_file, @file )
131
+ file = @attachments.get!(:my_file)
132
+ file.read.should == @file.read
133
+ end
134
+
135
+ it 'should stream an attachment' do
136
+ @attachments.add!( :my_file, @file )
137
+ data = @attachments.get!( :my_file, true )
138
+ data.should_not be_nil
139
+ data.should_not be_empty
140
+ data.should == @file.read
141
+ end
142
+ end
143
+
144
+ describe 'packing all files' do
145
+ before(:each) do
146
+ @attachments.add( :my_file, @file )
147
+ @attachments.add( 'dup.png', @file )
148
+ @pack = @attachments.pack
149
+ end
150
+
151
+ it 'should pack all the added files' do
152
+ @pack.keys.sort.should == ['dup.png', 'my_file']
153
+ end
154
+
155
+ it 'should have correct keys for each attachment' do
156
+ @pack['dup.png'].keys.sort.should include( 'content_type', 'data' )
157
+ end
158
+
159
+ it 'should have the correct mime type' do
160
+ @pack['dup.png']['content_type'].should == 'image/png'
161
+ end
162
+ end
163
+
164
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ Aqua.set_storage_engine('CouchDB') # to initialize the Aqua::Store namespace
4
+ CouchDB = Aqua::Store::CouchDB unless defined?( CouchDB )
5
+ describe CouchDB do
6
+ describe 'http_client setup' do
7
+ describe 'autoloading' do
8
+ it 'should not raise an error loading the default adapter' do
9
+ lambda{ CouchDB.set_http_adapter }.should_not raise_error
10
+ end
11
+
12
+ it 'should add rest methods to the Aqua module' do
13
+ CouchDB.set_http_adapter
14
+ CouchDB.should respond_to(:get)
15
+ end
16
+ end
17
+
18
+ describe 'manual loading of an alternate library' do
19
+ # TODO: when there is an alternate library
20
+ end
21
+ end
22
+
23
+ describe 'servers' do
24
+ before(:all) do
25
+ CouchDB.servers.delete(:all)
26
+ end
27
+
28
+ it 'should #clear_servers' do
29
+ CouchDB.clear_servers
30
+ CouchDB.servers.should == {}
31
+ end
32
+
33
+ it '#servers should return an empty hash by default' do
34
+ CouchDB.servers.should == {}
35
+ end
36
+
37
+ it 'should create a default server if no argument is passed' do
38
+ server = CouchDB.server
39
+ server.should_not be_nil
40
+ CouchDB.servers.should_not be_empty
41
+ CouchDB.servers[:aqua].should == server
42
+ server.namespace.should == 'aqua'
43
+ end
44
+
45
+ it 'should add servers when a symbol is requested that is not found as a servers key' do
46
+ server = CouchDB.server(:users)
47
+ CouchDB.servers.size.should == 2
48
+ CouchDB.servers[:users].should == server
49
+ server.namespace.should == 'users'
50
+ end
51
+
52
+ it 'should not duplicate servers' do
53
+ CouchDB.server(:users)
54
+ CouchDB.servers.size.should == 2
55
+ CouchDB.server
56
+ CouchDB.servers.size.should == 2
57
+ end
58
+
59
+ it 'should list the servers in use' do
60
+ CouchDB.server(:noodle)
61
+ CouchDB.servers.size.should == 3
62
+ CouchDB.servers.each do |key, server|
63
+ server.class.should == Aqua::Store::CouchDB::Server
64
+ end
65
+ end
66
+
67
+ it 'should allow the addition of customized servers' do
68
+ new_host = 'http://newhost.com:8888'
69
+ CouchDB.servers[:custom] = CouchDB::Server.new( :server => new_host )
70
+ CouchDB.servers.size.should == 4
71
+ CouchDB.servers[:custom].uri.should == new_host
72
+ end
73
+ end
74
+
75
+ describe 'text helper methods' do
76
+ describe 'escaping names' do
77
+ it 'should escape :: module/class separators with a double underscore __' do
78
+ string = CouchDB.escape('not::kosher')
79
+ string.should == 'not__kosher'
80
+ end
81
+
82
+ it 'should remove non alpha-numeric, hyphen, underscores from a string' do
83
+ string = CouchDB.escape('&not_!kosher*%')
84
+ string.should == 'not_kosher'
85
+ end
86
+ end
87
+
88
+ describe 'paramify_url' do
89
+ it 'should build a query filled url from a base url and a params hash' do
90
+ url = CouchDB.paramify_url( 'http://localhost:5984', {:gerbil => true, :keys => 'you_know_it'} )
91
+ url.should match(/\?/)
92
+ url.should match(/&/)
93
+ url.should match(/keys=you_know_it/)
94
+ url.should match(/gerbil=true/)
95
+ end
96
+ end
97
+ end
98
+
99
+ describe 'database strategies' do
100
+ # TODO: figure this out
101
+ end
102
+
103
+ end
104
+
@@ -0,0 +1,161 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ Aqua.set_storage_engine('CouchDB') # to initialize the Aqua::Store namespace
4
+ # Conveniences for typing with tests ...
5
+ CouchDB = Aqua::Store::CouchDB unless defined?( CouchDB )
6
+ Database = CouchDB::Database unless defined?( Database )
7
+ Server = CouchDB::Server unless defined?( Server)
8
+
9
+ describe 'Aqua::Store::CouchDB::Database' do
10
+ describe 'initialization' do
11
+ describe 'name' do
12
+ it 'should not require name for initialization' do
13
+ lambda{ Database.new }.should_not raise_error( ArgumentError )
14
+ end
15
+
16
+ it 'should escape the name, when one is provided' do
17
+ db = Database.new('&not::kosher*%')
18
+ db.name.should == 'not__kosher'
19
+ end
20
+ end
21
+
22
+ describe 'server' do
23
+ it 'should default to CouchDB\'s default server if no server option is provided' do
24
+ db = Database.new
25
+ db.server.should_not be_nil
26
+ db.server.class.should == Aqua::Store::CouchDB::Server
27
+ db.server.uri.should == 'http://127.0.0.1:5984'
28
+ db.server.namespace.should == 'aqua'
29
+ end
30
+
31
+ it 'a custom server held in CouchDB can be used' do
32
+ new_host = 'http://newhost.com:8888'
33
+ CouchDB.servers[:customized] = CouchDB::Server.new( :server => new_host )
34
+ db = Database.new('things', :server => :customized )
35
+ db.server.uri.should == new_host
36
+ end
37
+ end
38
+
39
+ describe 'uri' do
40
+ it 'should use the server namespace as the path when no name is provided' do
41
+ db = Database.new
42
+ db.name.should == nil
43
+ db.uri.should == "http://127.0.0.1:5984/aqua"
44
+ end
45
+
46
+ it 'should use the default server namespace and the name in the path when a name is provided but server info is not' do
47
+ db = Database.new('things')
48
+ db.name.should == 'things'
49
+ db.uri.should == 'http://127.0.0.1:5984/aqua_things'
50
+ end
51
+
52
+ it 'should use the server namespace provided and the name in the path when a name and server symbol are provided' do
53
+ db = Database.new('things', :server => :not_so_aqua )
54
+ db.uri.should == 'http://127.0.0.1:5984/not_so_aqua_things'
55
+ end
56
+
57
+ it 'should user a custome database\'s namespace along with the name in a path if both are provided' do
58
+ server = Server.new(:namespace => 'different')
59
+ db = Database.new('things', :server => server )
60
+ db.uri.should == 'http://127.0.0.1:5984/different_things'
61
+ end
62
+ end
63
+ end
64
+
65
+ describe 'create' do
66
+ before(:each) do
67
+ CouchDB.delete( Database.new('things').uri ) rescue nil
68
+ end
69
+
70
+ it 'should create a couchdb database for this instance if it doesn\'t yet exist' do
71
+ db = Database.create('things')
72
+ db.should be_exists
73
+ end
74
+
75
+ it 'create should not return false if the database already exists' do
76
+ db = Database.create('things')
77
+ db.should_not be( false )
78
+ end
79
+
80
+ it 'create should return false if an HTTP error occurs' do
81
+ CouchDB.should_receive(:put).and_raise( CouchDB::RequestFailed )
82
+ db = Database.create('things')
83
+ db.should == false
84
+ end
85
+
86
+ it 'create! should create and return a couchdb database if it doesn\'t yet exist' do
87
+ Database.new('things').should_not be_exists
88
+ db = Database.create!('things')
89
+ db.should be_exists
90
+ end
91
+
92
+ it 'create! should not raise an error if the database already exists' do
93
+ Database.create('things')
94
+ lambda{ Database.create!('things') }.should_not raise_error
95
+ end
96
+
97
+ it 'create should raise an error if an HTTP error occurs' do
98
+ CouchDB.should_receive(:put).and_raise( CouchDB::RequestFailed )
99
+ lambda{ Database.create!('things') }.should raise_error
100
+ end
101
+ end
102
+
103
+ describe 'misc managment stuff' do
104
+ before(:each) do
105
+ CouchDB.delete( Database.new('things').uri ) rescue nil
106
+ end
107
+
108
+ it '#exists? should be false if the database doesn\'t yet exist in CouchDB land' do
109
+ db = Database.new('things')
110
+ db.should_not be_exists
111
+ end
112
+
113
+ it '#exists? should be true if the database does exist in CouchDB land' do
114
+ db = Database.create('things')
115
+ db.should be_exists
116
+ end
117
+
118
+ it '#info raise an error if the database doesn\'t exist' do
119
+ db = Database.new('things')
120
+ db.delete
121
+ lambda{ db.info }.should raise_error( CouchDB::ResourceNotFound )
122
+ end
123
+
124
+ it '#info should provide a hash of detail if it exists' do
125
+ db = Database.create('things')
126
+ info = db.info
127
+ info.class.should == Hash
128
+ info['db_name'].should == 'aqua_things'
129
+ end
130
+ end
131
+
132
+ describe 'deleting' do
133
+ it 'should #delete itself' do
134
+ db = Database.create('things')
135
+ db.should be_exists
136
+ db.delete
137
+ db.should_not be_exist
138
+ end
139
+
140
+ it '#delete should return nil if it doesn\'t exist' do
141
+ db = Database.new('things')
142
+ db.should_not be_exists
143
+ lambda{ db.delete }.should_not raise_error
144
+ db.delete.should be_nil
145
+ end
146
+
147
+ it 'should #delete! itself' do
148
+ db = Database.create('things')
149
+ db.should be_exists
150
+ db.delete!
151
+ db.should_not be_exist
152
+ end
153
+
154
+ it '#delete! should raise an error if the database doesn\'t exist' do
155
+ db = Database.new('things')
156
+ db.should_not be_exists
157
+ lambda{ db.delete! }.should raise_error
158
+ end
159
+ end
160
+
161
+ end