aqua 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +2 -1
  2. data/Aqua.gemspec +14 -11
  3. data/Rakefile +1 -1
  4. data/VERSION +1 -1
  5. data/lib/aqua.rb +5 -7
  6. data/lib/aqua/object/config.rb +2 -3
  7. data/lib/aqua/object/initializers.rb +309 -0
  8. data/lib/aqua/object/pack.rb +56 -132
  9. data/lib/aqua/object/query.rb +30 -2
  10. data/lib/aqua/object/stub.rb +60 -95
  11. data/lib/aqua/object/tank.rb +1 -0
  12. data/lib/aqua/object/translator.rb +313 -0
  13. data/lib/aqua/object/unpack.rb +26 -227
  14. data/lib/aqua/store/couch_db/couch_db.rb +1 -0
  15. data/lib/aqua/store/couch_db/database.rb +1 -1
  16. data/lib/aqua/store/couch_db/design_document.rb +126 -2
  17. data/lib/aqua/store/couch_db/result_set.rb +36 -0
  18. data/lib/aqua/store/couch_db/storage_methods.rb +182 -17
  19. data/lib/aqua/store/storage.rb +4 -48
  20. data/lib/aqua/support/mash.rb +2 -3
  21. data/lib/aqua/support/set.rb +4 -16
  22. data/spec/object/object_fixtures/array_udder.rb +1 -1
  23. data/spec/object/object_fixtures/persistent.rb +0 -2
  24. data/spec/object/pack_spec.rb +137 -517
  25. data/spec/object/query_spec.rb +36 -6
  26. data/spec/object/stub_spec.rb +10 -9
  27. data/spec/object/translator_packing_spec.rb +402 -0
  28. data/spec/object/translator_unpacking_spec.rb +262 -0
  29. data/spec/object/unpack_spec.rb +162 -320
  30. data/spec/spec_helper.rb +18 -0
  31. data/spec/store/couchdb/design_document_spec.rb +148 -7
  32. data/spec/store/couchdb/result_set_spec.rb +95 -0
  33. data/spec/store/couchdb/storage_methods_spec.rb +150 -10
  34. metadata +13 -9
  35. data/lib/aqua/support/initializers.rb +0 -216
  36. data/spec/object/object_fixtures/grounded.rb +0 -13
  37. data/spec/object/object_fixtures/sugar.rb +0 -4
data/.gitignore CHANGED
@@ -4,4 +4,5 @@ coverage
4
4
  rdoc
5
5
  pkg
6
6
  .yardoc
7
- doc/*
7
+ doc/*
8
+ aqua-*.gem
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{aqua}
8
- s.version = "0.1.6"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kane Baccigalupi"]
12
- s.date = %q{2009-10-08}
13
- s.description = %q{Even with ORMs like ActiveRecord, DataMapper which ease the pain of relational data storage, considerable developer effort goes into wrangling Ruby objects into their databases. Document-oriented databases have made it possible to store nested data structures that easily map to Ruby objects. Aqua (http://github.com/baccigalupi/aqua) is a new Ruby library that aims to painlessly persists objects, allowing developers to focus more on object oriented code and less on storage. Currently Aqua is in pre-alpha testing, with the following big things left to implement: A data query DSL and implementation; Support of all objects in the Standard Library; Class and code storage to allow the sharing and persistence of classes with their data.}
12
+ s.date = %q{2009-11-18}
13
+ s.description = %q{A Ruby Object Database ... just add water (and CouchDB). Even with ORMs like ActiveRecord, DataMapper which ease the pain of relational data storage, considerable developer effort goes into wrangling Ruby objects into their databases. Document-oriented databases have made it possible to store nested data structures that easily map to Ruby objects. Aqua (http://github.com/baccigalupi/aqua) is a new Ruby library that aims to painlessly persists objects, allowing developers to focus more on object oriented code and less on storage. Currently Aqua is in pre-alpha testing, with the following big things left to implement: A data query DSL and implementation; Support of all objects in the Standard Library; Class and code storage to allow the sharing and persistence of classes with their data. }
14
14
  s.email = %q{baccigalupi@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
@@ -31,10 +31,12 @@ Gem::Specification.new do |s|
31
31
  "lib/aqua/object/extensions/ar_style.rb",
32
32
  "lib/aqua/object/extensions/property.rb",
33
33
  "lib/aqua/object/extensions/validation.rb",
34
+ "lib/aqua/object/initializers.rb",
34
35
  "lib/aqua/object/pack.rb",
35
36
  "lib/aqua/object/query.rb",
36
37
  "lib/aqua/object/stub.rb",
37
38
  "lib/aqua/object/tank.rb",
39
+ "lib/aqua/object/translator.rb",
38
40
  "lib/aqua/object/unpack.rb",
39
41
  "lib/aqua/store/couch_db/attachments.rb",
40
42
  "lib/aqua/store/couch_db/couch_db.rb",
@@ -42,10 +44,10 @@ Gem::Specification.new do |s|
42
44
  "lib/aqua/store/couch_db/design_document.rb",
43
45
  "lib/aqua/store/couch_db/http_client/adapter/rest_client.rb",
44
46
  "lib/aqua/store/couch_db/http_client/rest_api.rb",
47
+ "lib/aqua/store/couch_db/result_set.rb",
45
48
  "lib/aqua/store/couch_db/server.rb",
46
49
  "lib/aqua/store/couch_db/storage_methods.rb",
47
50
  "lib/aqua/store/storage.rb",
48
- "lib/aqua/support/initializers.rb",
49
51
  "lib/aqua/support/mash.rb",
50
52
  "lib/aqua/support/set.rb",
51
53
  "lib/aqua/support/string_extensions.rb",
@@ -54,15 +56,15 @@ Gem::Specification.new do |s|
54
56
  "spec/object/object_fixtures/array_udder.rb",
55
57
  "spec/object/object_fixtures/canned_hash.rb",
56
58
  "spec/object/object_fixtures/gerbilmiester.rb",
57
- "spec/object/object_fixtures/grounded.rb",
58
59
  "spec/object/object_fixtures/log.rb",
59
60
  "spec/object/object_fixtures/persistent.rb",
60
- "spec/object/object_fixtures/sugar.rb",
61
61
  "spec/object/object_fixtures/user.rb",
62
62
  "spec/object/pack_spec.rb",
63
63
  "spec/object/query_spec.rb",
64
64
  "spec/object/stub_spec.rb",
65
65
  "spec/object/tank_spec.rb",
66
+ "spec/object/translator_packing_spec.rb",
67
+ "spec/object/translator_unpacking_spec.rb",
66
68
  "spec/object/unpack_spec.rb",
67
69
  "spec/spec.opts",
68
70
  "spec/spec_helper.rb",
@@ -72,16 +74,16 @@ Gem::Specification.new do |s|
72
74
  "spec/store/couchdb/design_document_spec.rb",
73
75
  "spec/store/couchdb/fixtures_and_data/document_fixture.rb",
74
76
  "spec/store/couchdb/fixtures_and_data/image_attach.png",
77
+ "spec/store/couchdb/result_set_spec.rb",
75
78
  "spec/store/couchdb/server_spec.rb",
76
79
  "spec/store/couchdb/storage_methods_spec.rb",
77
80
  "utils/code_statistics.rb",
78
81
  "utils/console"
79
82
  ]
80
- s.has_rdoc = true
81
83
  s.homepage = %q{http://github.com/baccigalupi/aqua}
82
84
  s.rdoc_options = ["--charset=UTF-8"]
83
85
  s.require_paths = ["lib"]
84
- s.rubygems_version = %q{1.3.1}
86
+ s.rubygems_version = %q{1.3.5}
85
87
  s.summary = %q{Aqua: A Ruby Object Database ... just add water (and CouchDB)}
86
88
  s.test_files = [
87
89
  "spec/aqua_spec.rb",
@@ -89,15 +91,15 @@ Gem::Specification.new do |s|
89
91
  "spec/object/object_fixtures/array_udder.rb",
90
92
  "spec/object/object_fixtures/canned_hash.rb",
91
93
  "spec/object/object_fixtures/gerbilmiester.rb",
92
- "spec/object/object_fixtures/grounded.rb",
93
94
  "spec/object/object_fixtures/log.rb",
94
95
  "spec/object/object_fixtures/persistent.rb",
95
- "spec/object/object_fixtures/sugar.rb",
96
96
  "spec/object/object_fixtures/user.rb",
97
97
  "spec/object/pack_spec.rb",
98
98
  "spec/object/query_spec.rb",
99
99
  "spec/object/stub_spec.rb",
100
100
  "spec/object/tank_spec.rb",
101
+ "spec/object/translator_packing_spec.rb",
102
+ "spec/object/translator_unpacking_spec.rb",
101
103
  "spec/object/unpack_spec.rb",
102
104
  "spec/spec_helper.rb",
103
105
  "spec/store/couchdb/attachments_spec.rb",
@@ -105,13 +107,14 @@ Gem::Specification.new do |s|
105
107
  "spec/store/couchdb/database_spec.rb",
106
108
  "spec/store/couchdb/design_document_spec.rb",
107
109
  "spec/store/couchdb/fixtures_and_data/document_fixture.rb",
110
+ "spec/store/couchdb/result_set_spec.rb",
108
111
  "spec/store/couchdb/server_spec.rb",
109
112
  "spec/store/couchdb/storage_methods_spec.rb"
110
113
  ]
111
114
 
112
115
  if s.respond_to? :specification_version then
113
116
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
114
- s.specification_version = 2
117
+ s.specification_version = 3
115
118
 
116
119
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
117
120
  else
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ begin
7
7
  Jeweler::Tasks.new do |gem|
8
8
  gem.name = "aqua"
9
9
  gem.summary = %Q{Aqua: A Ruby Object Database ... just add water (and CouchDB)}
10
- gem.description = %Q{Even with ORMs like ActiveRecord, DataMapper which ease the pain of relational data storage, considerable developer effort goes into wrangling Ruby objects into their databases. Document-oriented databases have made it possible to store nested data structures that easily map to Ruby objects. Aqua (http://github.com/baccigalupi/aqua) is a new Ruby library that aims to painlessly persists objects, allowing developers to focus more on object oriented code and less on storage. Currently Aqua is in pre-alpha testing, with the following big things left to implement: A data query DSL and implementation; Support of all objects in the Standard Library; Class and code storage to allow the sharing and persistence of classes with their data. }
10
+ gem.description = %Q{A Ruby Object Database ... just add water (and CouchDB). Even with ORMs like ActiveRecord, DataMapper which ease the pain of relational data storage, considerable developer effort goes into wrangling Ruby objects into their databases. Document-oriented databases have made it possible to store nested data structures that easily map to Ruby objects. Aqua (http://github.com/baccigalupi/aqua) is a new Ruby library that aims to painlessly persists objects, allowing developers to focus more on object oriented code and less on storage. Currently Aqua is in pre-alpha testing, with the following big things left to implement: A data query DSL and implementation; Support of all objects in the Standard Library; Class and code storage to allow the sharing and persistence of classes with their data. }
11
11
  gem.email = "baccigalupi@gmail.com"
12
12
  gem.homepage = "http://github.com/baccigalupi/aqua"
13
13
  gem.authors = ["Kane Baccigalupi"]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.6
1
+ 0.2.0
@@ -1,8 +1,8 @@
1
1
  # DEPENDENCIES -------------------------------------
2
2
  # require gems
3
3
  require 'rubygems'
4
- require 'ruby2ruby'
5
4
  require 'mime/types'
5
+
6
6
  # Pick your json poison. Just make sure that in adds the JSON constant
7
7
  unless defined?(JSON)
8
8
  begin
@@ -11,10 +11,9 @@ unless defined?(JSON)
11
11
  raise LoadError, "JSON constant not found. Please install a JSON library"
12
12
  end
13
13
  end
14
- # There is also a dependency on the http_client of your choosing. Currently only ...
15
- # require 'rest_client'
16
- # It is required when a libarary is configured. If the library is not configured then it will
17
- # automatically load the default: rest_client
14
+
15
+ # This is temporary until someone comes along creating another http_client library adapter.
16
+ require 'rest_client'
18
17
 
19
18
  # standard libraries
20
19
  require 'cgi'
@@ -31,8 +30,7 @@ require 'aqua/support/string_extensions'
31
30
  require 'aqua/store/storage'
32
31
  # object methods
33
32
  require 'aqua/object/tank'
34
- # a little more monkey patching for object packaging
35
- require 'aqua/support/initializers'
33
+ require 'aqua/object/initializers'
36
34
 
37
35
 
38
36
  # LIBRARY SETUP -----------------------------------
@@ -5,10 +5,9 @@ module Aqua::Config
5
5
  # for class methods will loose database and other class specific storage options
6
6
  klass.class_eval "
7
7
  class Storage < Aqua::Storage
8
- def self.parent_class
9
- '#{klass}'
10
- end
11
8
  end
9
+
10
+ Storage.parent_class = '#{klass}'
12
11
  "
13
12
 
14
13
  klass.class_eval do
@@ -0,0 +1,309 @@
1
+ # AQUA INITIALIZATION
2
+ # Some object store state in a fundamental way, not in instance variables, that needs to be initialized.
3
+ # Examples: Array, Numeric types, Hashes, Time ...
4
+ # You can make any object requiring this initialization savable to aqua by
5
+ # * including the Aqua::To module and extending the Aqua::From module
6
+ # * building your own methods for #to_aqua, #to_aqua_init, MyClass.aqua_init
7
+ # See set.rb in this file for more an example
8
+ module Aqua
9
+ module Initializers
10
+ def self.included( klass )
11
+ klass.class_eval do
12
+ include InstanceMethods
13
+ extend ClassMethods
14
+
15
+ unless methods.include?( :hide_attributes )
16
+ include Aqua::Pack::HiddenAttributes
17
+ end
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ def to_aqua( path = '' )
23
+ rat = Aqua::Translator::Rat.new( { 'class' => to_aqua_class } )
24
+
25
+ init_rat = to_aqua_init( path )
26
+ rat.hord(init_rat, 'init')
27
+
28
+ ivar_rat = _pack_instance_vars( path )
29
+ rat.eat( ivar_rat ) if ivar_rat && ivar_rat.pack['ivars'] && !ivar_rat.pack['ivars'].empty?
30
+
31
+ rat
32
+ end
33
+
34
+ def to_aqua_class
35
+ self.class.to_s
36
+ end
37
+
38
+ def _pack_instance_vars( path )
39
+ rat = Aqua::Translator::Rat.new
40
+ ivar_rat = Translator.pack_ivars( self )
41
+ ivar_rat.pack.empty? ? rat : rat.hord( ivar_rat, 'ivars' )
42
+ end
43
+
44
+ def to_aqua_init( path )
45
+ Aqua::Translator::Rat.new( self.to_s )
46
+ end
47
+ end # InstanceMethods
48
+
49
+ module ClassMethods
50
+ end # ClassMethods
51
+
52
+ end # Initializers
53
+
54
+ end
55
+
56
+ [ TrueClass, FalseClass, Symbol, Time, Date, Fixnum, Bignum, Float, Rational, Hash, Array, OpenStruct, Range, File, Tempfile, String, NilClass].each do |klass|
57
+ klass.class_eval { include Aqua::Initializers }
58
+ end
59
+
60
+ class String
61
+ def from_aqua( path='')
62
+ self
63
+ end
64
+
65
+ def to_aqua( path='' )
66
+ Aqua::Translator::Rat.new( self )
67
+ end
68
+ end
69
+
70
+ class TrueClass
71
+ def from_aqua( path='')
72
+ true
73
+ end
74
+
75
+ def to_aqua( path='')
76
+ Aqua::Translator::Rat.new( true )
77
+ end
78
+ end
79
+
80
+ class FalseClass
81
+ def from_aqua( path='')
82
+ false
83
+ end
84
+
85
+ def to_aqua( path='' )
86
+ Aqua::Translator::Rat.new( false )
87
+ end
88
+ end
89
+
90
+ class NilClass
91
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
92
+ nil
93
+ end
94
+ end
95
+
96
+ class Symbol
97
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
98
+ init.to_sym
99
+ end
100
+
101
+ def _pack_instance_vars( path='')
102
+ nil
103
+ end
104
+ end
105
+
106
+ class Date
107
+ hide_attributes :sg, :of, :ajd
108
+
109
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
110
+ parse( init )
111
+ end
112
+
113
+ def _pack_instance_vars( path='')
114
+ nil
115
+ end
116
+ end
117
+
118
+ class Time
119
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
120
+ parse( init )
121
+ end
122
+ end
123
+
124
+ class Fixnum
125
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
126
+ init.to_i
127
+ end
128
+ end
129
+
130
+ class Bignum
131
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
132
+ init.to_i
133
+ end
134
+ end
135
+
136
+ class Float
137
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
138
+ init.to_f
139
+ end
140
+ end
141
+
142
+ class Rational
143
+ def to_aqua_init( path='')
144
+ Aqua::Translator::Rat.new( self.to_s.match(/(\d*)\/(\d*)/).to_a.slice(1,2) )
145
+ end
146
+
147
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
148
+ Rational( init[0].to_i, init[1].to_i )
149
+ end
150
+
151
+ def _pack_instance_vars( path='')
152
+ nil
153
+ end
154
+ end
155
+
156
+ class Range
157
+ # todo: make this work for non int objects, time, date, etc ...
158
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
159
+ eval( init )
160
+ end
161
+ end
162
+
163
+ class Array
164
+ def to_aqua_init( path = '' )
165
+ rat = Aqua::Translator::Rat.new([])
166
+ self.each_with_index do |obj, index|
167
+ local_path = path + "[#{index}]"
168
+ obj_rat = Aqua::Translator.pack_object( obj, local_path )
169
+ rat.eat( obj_rat )
170
+ end
171
+ rat
172
+ end
173
+
174
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
175
+ # todo: make opts opts.path follow the path through the base object
176
+ array_init = init.map{ |obj| Aqua::Translator.unpack_object(obj, opts) }
177
+ # new is neccessary to make sure array derivatives maintain their class
178
+ # without having to override aqua_init!
179
+ self == Array ? array_init : new( array_init )
180
+ end
181
+ end
182
+
183
+
184
+ class Hash
185
+ def to_aqua_init( path='')
186
+ rat = Aqua::Translator::Rat.new
187
+ self.each do |raw_key, value|
188
+ key_class = raw_key.class
189
+ if key_class == String
190
+ key = raw_key
191
+ else # key is an object
192
+ index = aqua_next_object_index( rat.pack )
193
+ key = self.class.aqua_object_key_index( index )
194
+ key_rat = Aqua::Translator.pack_object( raw_key, path+"['#{self.class.aqua_key_register}'][#{index}]")
195
+ rat.hord( key_rat, [self.class.aqua_key_register, index] )
196
+ end
197
+ obj_rat = Aqua::Translator.pack_object( value, path+"['#{key}']" )
198
+ rat.hord( obj_rat, key )
199
+ end
200
+ rat
201
+ end
202
+
203
+ def self.aqua_key_register
204
+ "#{aqua_key_register_prefix}KEYS".freeze
205
+ end
206
+
207
+ def self.aqua_key_register_prefix
208
+ "/_OBJECT_"
209
+ end
210
+
211
+ def self.aqua_object_key_index( index )
212
+ "#{aqua_key_register_prefix}#{index}"
213
+ end
214
+
215
+ def aqua_next_object_index( hash )
216
+ hash[self.class.aqua_key_register] ||= []
217
+ hash[self.class.aqua_key_register].size
218
+ end
219
+
220
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
221
+ unpacked = {}
222
+ init.each do |key, value|
223
+ unless key == aqua_key_register
224
+ if key.match(/^#{aqua_key_register_prefix}(\d*)$/)
225
+ index = $1.to_i
226
+ key = Aqua::Translator.unpack_object( init[aqua_key_register][index], opts )
227
+ end
228
+ opts.path += "[#{key}]"
229
+ value = Aqua::Translator.unpack_object( value, opts )
230
+ unpacked[ key ] = value
231
+ end
232
+ end
233
+ self == Hash ? unpacked : new( unpacked )
234
+ end
235
+ end
236
+
237
+ class OpenStruct
238
+ hide_attributes :table
239
+
240
+ def to_aqua_init( path='' )
241
+ instance_variable_get("@table").to_aqua_init( path )
242
+ end
243
+
244
+ def self.aqua_init( init, opts=Aqua::Translator::Opts.new )
245
+ init = Hash.aqua_init( init, opts )
246
+ new( init )
247
+ end
248
+ end
249
+
250
+ module Aqua
251
+ module FileInitializations
252
+ def to_aqua( opts=Aqua::Translator::Opts.new )
253
+ rat = Aqua::Translator::Rat.new(
254
+ {
255
+ 'class' => to_aqua_class,
256
+ 'init' => {
257
+ 'id' => filename,
258
+ 'methods' => {
259
+ 'content_type' => content_type,
260
+ 'content_length' => content_length
261
+ }
262
+ }
263
+ }, {}, [self]
264
+ )
265
+
266
+ ivar_rat = _pack_instance_vars( path )
267
+ rat.eat( ivar_rat ) if ivar_rat && ivar_rat.pack['ivars'] && !ivar_rat.pack['ivars'].empty?
268
+
269
+ rat
270
+ end
271
+
272
+ def content_length
273
+ if len = stat.size
274
+ rat = Aqua::Translator.pack_object( len )
275
+ rat.pack
276
+ else
277
+ ''
278
+ end
279
+ end
280
+
281
+ def content_type
282
+ mime = MIME::Types.type_for( self.path )
283
+ mime && mime.first ? mime.first.to_s : ''
284
+ end
285
+
286
+ def to_aqua_class
287
+ 'Aqua::FileStub'
288
+ end
289
+
290
+ def filename
291
+ path.match(/([^\/]*)\z/).to_s
292
+ end
293
+
294
+ end # FileInitializations
295
+ end # Aqua
296
+
297
+ class File
298
+ include Aqua::FileInitializations
299
+ end
300
+
301
+ class Tempfile
302
+ include Aqua::FileInitializations
303
+
304
+ hide_attributes :clean_proc, :data, :tmpname, :tmpfile, :_dc_obj
305
+
306
+ def filename
307
+ path.match(/([^\/]*)\.\d*\.\d*\z/).captures.first
308
+ end
309
+ end