aqua 0.1.6 → 0.2.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.
- data/.gitignore +2 -1
- data/Aqua.gemspec +14 -11
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/aqua.rb +5 -7
- data/lib/aqua/object/config.rb +2 -3
- data/lib/aqua/object/initializers.rb +309 -0
- data/lib/aqua/object/pack.rb +56 -132
- data/lib/aqua/object/query.rb +30 -2
- data/lib/aqua/object/stub.rb +60 -95
- data/lib/aqua/object/tank.rb +1 -0
- data/lib/aqua/object/translator.rb +313 -0
- data/lib/aqua/object/unpack.rb +26 -227
- data/lib/aqua/store/couch_db/couch_db.rb +1 -0
- data/lib/aqua/store/couch_db/database.rb +1 -1
- data/lib/aqua/store/couch_db/design_document.rb +126 -2
- data/lib/aqua/store/couch_db/result_set.rb +36 -0
- data/lib/aqua/store/couch_db/storage_methods.rb +182 -17
- data/lib/aqua/store/storage.rb +4 -48
- data/lib/aqua/support/mash.rb +2 -3
- data/lib/aqua/support/set.rb +4 -16
- data/spec/object/object_fixtures/array_udder.rb +1 -1
- data/spec/object/object_fixtures/persistent.rb +0 -2
- data/spec/object/pack_spec.rb +137 -517
- data/spec/object/query_spec.rb +36 -6
- data/spec/object/stub_spec.rb +10 -9
- data/spec/object/translator_packing_spec.rb +402 -0
- data/spec/object/translator_unpacking_spec.rb +262 -0
- data/spec/object/unpack_spec.rb +162 -320
- data/spec/spec_helper.rb +18 -0
- data/spec/store/couchdb/design_document_spec.rb +148 -7
- data/spec/store/couchdb/result_set_spec.rb +95 -0
- data/spec/store/couchdb/storage_methods_spec.rb +150 -10
- metadata +13 -9
- data/lib/aqua/support/initializers.rb +0 -216
- data/spec/object/object_fixtures/grounded.rb +0 -13
- data/spec/object/object_fixtures/sugar.rb +0 -4
data/spec/object/query_spec.rb
CHANGED
@@ -15,13 +15,43 @@ describe Aqua::Query do
|
|
15
15
|
:log => @log,
|
16
16
|
:password => 'my secret!'
|
17
17
|
)
|
18
|
-
@user.commit!
|
18
|
+
@user.commit!
|
19
|
+
|
20
|
+
@user_2 = User.new(
|
21
|
+
:username => 'B',
|
22
|
+
:name => ['Burny', 'Tierney'],
|
23
|
+
:dob => Date.parse('12/28/1921'),
|
24
|
+
:created_at => Time.now + 3600,
|
25
|
+
:log => Log.new,
|
26
|
+
:password => 'my secret!'
|
27
|
+
)
|
28
|
+
@user_2.commit!
|
29
|
+
|
19
30
|
end
|
20
31
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
32
|
+
it 'should be have a class method for #index_on' do
|
33
|
+
User.should respond_to(:index_on)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should create indexes on the storage class' do
|
37
|
+
User.index_on(:created_at)
|
38
|
+
User::Storage.indexes.should include('created_at')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should query on a time' do
|
42
|
+
User.index_on(:created_at)
|
43
|
+
users = User.query( :created_at, :equals => @time )
|
44
|
+
users.size.should == 1
|
45
|
+
users.first.username.should == 'kane'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should find all records with an attribute' do
|
49
|
+
User.index_on(:created_at)
|
50
|
+
users = User.query( :created_at )
|
51
|
+
users.size.should == 2
|
52
|
+
users.first.username.should == 'kane'
|
53
|
+
users.last.username.should == 'B'
|
54
|
+
end
|
55
|
+
|
26
56
|
end
|
27
57
|
|
data/spec/object/stub_spec.rb
CHANGED
@@ -18,22 +18,23 @@ describe Aqua::Stub do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
describe 'initialization' do
|
21
|
-
it 'should initialize delegate
|
22
|
-
delegate = @stub.instance_eval( "__getobj__" )
|
23
|
-
delegate.class.should == Aqua::TempStub
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'should initialize the delegate_id' do
|
21
|
+
it 'should initialize the delegate id' do
|
27
22
|
@stub.instance_eval('delegate_id').should == 'my_great_id'
|
28
23
|
end
|
29
24
|
|
30
|
-
it 'should initialize the
|
25
|
+
it 'should initialize the delegate class' do
|
31
26
|
@stub.instance_eval('delegate_class').should == 'Gerbilmiester'
|
32
|
-
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# This stuff is just scoped out for future use. I would like to have a stub know where it exists
|
30
|
+
# in its parent object and be able to replace itself instead of loading a delegate.
|
31
|
+
it 'should have a parent object'
|
32
|
+
it 'should have a path from parent to self'
|
33
33
|
end
|
34
34
|
|
35
35
|
describe 'delegation' do
|
36
|
-
it 'should return correct values for initialized methods' do
|
36
|
+
it 'should return correct values for initialized methods' do
|
37
|
+
Gerbilmiester.should_not_receive(:load)
|
37
38
|
@stub.gerbil.should == true
|
38
39
|
@stub.bacon.should == 'chunky'
|
39
40
|
end
|
@@ -0,0 +1,402 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require_fixtures
|
3
|
+
require File.dirname(__FILE__) + "/../../lib/aqua/support/set"
|
4
|
+
|
5
|
+
Aqua.set_storage_engine('CouchDB') # to initialize CouchDB
|
6
|
+
CouchDB = Aqua::Store::CouchDB unless defined?( CouchDB )
|
7
|
+
Translator = Aqua::Translator unless defined?( Translator )
|
8
|
+
Rat = Aqua::Translator::Rat unless defined?( Rat )
|
9
|
+
|
10
|
+
describe Translator, 'packing' do
|
11
|
+
before(:each) do
|
12
|
+
User.configure_aqua( :embed => {:stub => :username } )
|
13
|
+
@user = User.new(:username => 'Kane')
|
14
|
+
@user_init = {"class"=>"Aqua::Stub", "init"=>{ "methods"=>{"username"=>"Kane"}, "class"=>"User", "id"=>"" }}
|
15
|
+
@file = File.new(File.dirname(__FILE__) + '/../store/couchdb/fixtures_and_data/image_attach.png')
|
16
|
+
@file_pack = {
|
17
|
+
'class' => 'Aqua::FileStub',
|
18
|
+
'init' => {
|
19
|
+
'id' => 'image_attach.png',
|
20
|
+
"methods"=>{
|
21
|
+
"content_type" => 'image/png',
|
22
|
+
"content_length" => {"class"=>"Fixnum", "init"=>"26551"}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
@tempfile = Tempfile.new('temp.txt')
|
27
|
+
@tempfile.write('I am a tempfile!')
|
28
|
+
@tempfile.rewind
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'instances' do
|
32
|
+
it 'should be itialized with the base object' do
|
33
|
+
pending
|
34
|
+
@user._packer.base.should == @user
|
35
|
+
end
|
36
|
+
it 'should have externals'
|
37
|
+
it 'should have attachments'
|
38
|
+
end
|
39
|
+
|
40
|
+
def pack( obj )
|
41
|
+
Translator.pack_object( obj )
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'class methods should pack' do
|
45
|
+
it 'string' do
|
46
|
+
pack('string').should == Rat.new("string")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'times' do
|
50
|
+
time = Time.parse("12/23/69")
|
51
|
+
pack(time).should == Rat.new( {"class" => "Time", "init" => time.to_s} )
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'dates' do
|
55
|
+
date = Date.parse("12/23/69")
|
56
|
+
pack(date).should == Rat.new( {"class" => "Date", "init" => date.to_s} )
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'true' do
|
60
|
+
pack( true ).should == Rat.new( true )
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'false' do
|
64
|
+
pack( false ).should == Rat.new( false )
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'Symbols' do
|
68
|
+
pack( :symbol ).should == Rat.new( {"class" => "Symbol", "init" => "symbol"} )
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'Fixnums' do
|
72
|
+
pack( 1234 ).should == Rat.new( {"class" => "Fixnum", 'init' => '1234'} )
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'Bignums' do
|
76
|
+
pack( 12345678901234567890 ).should ==
|
77
|
+
Rat.new( { "class" => 'Bignum', 'init' => '12345678901234567890' } )
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'Floats' do
|
81
|
+
pack( 1.681 ).should == Rat.new( { "class" => 'Float', 'init' => '1.681' } )
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'Rationals' do
|
85
|
+
pack( Rational( 1, 17 ) ).should == Rat.new( { "class" => 'Rational', 'init' => ['1','17'] } )
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'Ranges' do
|
89
|
+
pack( 1..3 ).should == Rat.new( { "class" => 'Range', 'init' => '1..3' } )
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'arrays of string' do
|
93
|
+
pack( ['one', 'two'] ).should == Rat.new( {"class" => 'Array', 'init' => ['one', 'two'] } )
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'mixed arrays' do
|
97
|
+
pack( [1, :two] ).should ==
|
98
|
+
Rat.new({"class" => 'Array', 'init' => [{"class"=>"Fixnum", "init"=>"1"}, {"class"=>"Symbol", "init"=>"two"} ]})
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'arrays with externals' do
|
102
|
+
user = User.new(:username => 'Kane')
|
103
|
+
pack( [user, 1] ).should == Rat.new(
|
104
|
+
{
|
105
|
+
'class' => 'Array',
|
106
|
+
'init' => [
|
107
|
+
@user_init,
|
108
|
+
{"class"=>"Fixnum", "init"=>"1"}
|
109
|
+
]
|
110
|
+
}, { user => '[0]'}
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'externals with an array of stubbed methods' do
|
115
|
+
User.configure_aqua( :embed => {:stub => [:username, :name] } )
|
116
|
+
user = User.new(
|
117
|
+
:username => 'Kane',
|
118
|
+
:name => ['Kane', 'Baccigalupi']
|
119
|
+
)
|
120
|
+
pack( [user] ).should == Rat.new(
|
121
|
+
{
|
122
|
+
"class" => 'Array',
|
123
|
+
"init" => [
|
124
|
+
"class"=>"Aqua::Stub",
|
125
|
+
"init"=>{
|
126
|
+
"methods"=>{"username"=>"Kane", 'name'=>{"class"=>"Array", "init"=>["Kane", "Baccigalupi"]}},
|
127
|
+
"class"=>"User", "id"=>""
|
128
|
+
}
|
129
|
+
]
|
130
|
+
},
|
131
|
+
{ user => '[0]'}
|
132
|
+
)
|
133
|
+
User.configure_aqua( :embed => {:stub => :username } )
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
it 'arrays with deeply nested externals' do
|
138
|
+
user = User.new(:username => 'Kane')
|
139
|
+
nested_pack = pack( ['layer 1', ['layer 2', ['layer 3', user ] ] ] )
|
140
|
+
nested_pack.should == Rat.new(
|
141
|
+
{
|
142
|
+
'class' => 'Array',
|
143
|
+
'init' => [ 'layer 1',
|
144
|
+
{
|
145
|
+
'class' => 'Array',
|
146
|
+
'init' => [ 'layer 2',
|
147
|
+
{
|
148
|
+
'class' => 'Array',
|
149
|
+
'init' => [ 'layer 3', @user_init ]
|
150
|
+
}
|
151
|
+
]
|
152
|
+
}
|
153
|
+
]
|
154
|
+
},
|
155
|
+
{user => '[1][1][1]'}
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'array derivatives' do
|
160
|
+
array_derivative = ArrayUdder.new
|
161
|
+
array_derivative[0] = 'zero index'
|
162
|
+
array_derivative.udder # initializes an ivar
|
163
|
+
pack( array_derivative ).should == Rat.new(
|
164
|
+
{
|
165
|
+
'class' => "ArrayUdder",
|
166
|
+
'init' => ['zero index'],
|
167
|
+
"ivars"=>{"@udder"=>"Squeeze out some array milk"}
|
168
|
+
}
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
it 'hashes' do
|
174
|
+
pack({'1' => 'one'}).should == Rat.new( {'class' => 'Hash', 'init' => {'1' => 'one'}} )
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'hashes with externals' do
|
178
|
+
user = User.new(:username => 'Kane')
|
179
|
+
pack({'user' => user}).should == Rat.new(
|
180
|
+
{'class' => 'Hash', 'init' => {
|
181
|
+
'user' => @user_init
|
182
|
+
}},
|
183
|
+
{user => "['user']"}
|
184
|
+
)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'hashes with object keys' do
|
188
|
+
pack({1 => 'one'}).should == Rat.new(
|
189
|
+
{'class' => 'Hash', 'init' => {
|
190
|
+
'/_OBJECT_0' => 'one',
|
191
|
+
'/_OBJECT_KEYS' => [{"class"=>"Fixnum", "init"=>"1"}]
|
192
|
+
} }
|
193
|
+
)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'hashes with externals as object keys' do
|
197
|
+
user = User.new(:username => 'Kane')
|
198
|
+
pack({ user => 'user'}).should == Rat.new(
|
199
|
+
{ 'class' => 'Hash', 'init' => {
|
200
|
+
'/_OBJECT_0' => 'user',
|
201
|
+
'/_OBJECT_KEYS' => [@user_init]
|
202
|
+
}},
|
203
|
+
{ user => "['/_OBJECT_KEYS'][0]" }
|
204
|
+
)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'open structs' do
|
208
|
+
# open structs store keys as symbols internally, as such there is the object keys below ...
|
209
|
+
user = User.new(:username => 'Kane')
|
210
|
+
struct = OpenStruct.new( :user => user )
|
211
|
+
pack( struct ).should == Rat.new(
|
212
|
+
{ 'class' => 'OpenStruct',
|
213
|
+
'init' => {
|
214
|
+
'/_OBJECT_0' => @user_init,
|
215
|
+
'/_OBJECT_KEYS' => [{"class"=>"Symbol", "init"=>"user"}]
|
216
|
+
}
|
217
|
+
},
|
218
|
+
{ user => "['/_OBJECT_0']" }
|
219
|
+
)
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'files' do
|
223
|
+
pack( @file ).should == Rat.new( @file_pack , {}, [ @file ] )
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'tempfiles' do
|
227
|
+
pack( @tempfile ).should == Rat.new(
|
228
|
+
{
|
229
|
+
'class' => 'Aqua::FileStub',
|
230
|
+
'init' => {
|
231
|
+
'id' => 'temp.txt',
|
232
|
+
"methods"=>{
|
233
|
+
"content_type" => '', # not sure what's up with the mime determination
|
234
|
+
"content_length" => {"class"=>"Fixnum", "init"=>"16"}
|
235
|
+
}
|
236
|
+
}
|
237
|
+
},
|
238
|
+
{}, [@tempfile]
|
239
|
+
)
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'arrays with files' do
|
243
|
+
pack( [@file, 1] ).should == Rat.new({
|
244
|
+
'class' => 'Array',
|
245
|
+
'init' => [
|
246
|
+
@file_pack,
|
247
|
+
{"class"=>"Fixnum", "init"=>"1"}
|
248
|
+
]
|
249
|
+
}, {}, [@file]
|
250
|
+
)
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'arrays with deeply nested files' do
|
254
|
+
nested_pack = pack( ['layer 1', ['layer 2', ['layer 3', @file ] ] ] )
|
255
|
+
nested_pack.should == Rat.new(
|
256
|
+
{
|
257
|
+
'class' => 'Array',
|
258
|
+
'init' => [ 'layer 1',
|
259
|
+
{
|
260
|
+
'class' => 'Array',
|
261
|
+
'init' => [ 'layer 2',
|
262
|
+
{
|
263
|
+
'class' => 'Array',
|
264
|
+
'init' => [ 'layer 3', @file_pack ]
|
265
|
+
}
|
266
|
+
]
|
267
|
+
}
|
268
|
+
]
|
269
|
+
},
|
270
|
+
{}, [@file]
|
271
|
+
)
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'hashes with files' do
|
275
|
+
pack({'attachment' => @file}).should == Rat.new(
|
276
|
+
{'class' => 'Hash', 'init' => {
|
277
|
+
'attachment' => @file_pack
|
278
|
+
}},
|
279
|
+
{}, [@file]
|
280
|
+
)
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'hashes with file keys' do
|
284
|
+
pack({ @file => 'attachment'}).should == Rat.new(
|
285
|
+
{ 'class' => 'Hash', 'init' => {
|
286
|
+
'/_OBJECT_0' => 'attachment',
|
287
|
+
'/_OBJECT_KEYS' => [@file_pack]
|
288
|
+
}},
|
289
|
+
{}, [@file]
|
290
|
+
)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'hash derivatives' do
|
294
|
+
hashish = CannedHash.new( 1 => 'one' )
|
295
|
+
hashish.yum # sets instance variable
|
296
|
+
pack(hashish).should == Rat.new(
|
297
|
+
{'class' => 'CannedHash', 'init' => {
|
298
|
+
'/_OBJECT_0' => 'one',
|
299
|
+
'/_OBJECT_KEYS' => [{"class"=>"Fixnum", "init"=>"1"}]
|
300
|
+
}, 'ivars' => {'@yum' => 'Corned Beef!'} }
|
301
|
+
)
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'sets' do
|
305
|
+
pack(Set.new(['a', 'b'])).should == Rat.new(
|
306
|
+
{ 'class' => 'Set', 'init' =>{'class'=> 'Array', 'init' =>['a', 'b']} }
|
307
|
+
)
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'embedable objects' do
|
311
|
+
log = Log.new(:message => "Hi!")
|
312
|
+
pack( log ).should == Rat.new(
|
313
|
+
{'class' => 'Log', 'ivars' => {'@message' => 'Hi!'}}
|
314
|
+
)
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'an array with an embeddable object' do
|
318
|
+
log = Log.new(:message => "Hi!")
|
319
|
+
pack( [log] ).should == Rat.new(
|
320
|
+
{'class' => 'Array', 'init' => [
|
321
|
+
{'class' => 'Log', 'ivars' => {'@message' => 'Hi!'}}
|
322
|
+
]}
|
323
|
+
)
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'aquatic base objects in non-stub form' do
|
327
|
+
pack( @user ).pack['class'].should == 'User'
|
328
|
+
end
|
329
|
+
|
330
|
+
it 'embedded objects in an ivar' do
|
331
|
+
@user.log = Log.new(:message => 'Hi!')
|
332
|
+
pack( @user ).should == Rat.new(
|
333
|
+
{'class' => 'User', 'ivars' => {
|
334
|
+
'@log' => {'class' => 'Log', 'ivars' => {'@message' => 'Hi!'}},
|
335
|
+
'@username' => 'Kane'
|
336
|
+
}}
|
337
|
+
)
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'externals in an ivar' do
|
341
|
+
otter = User.new(:username => 'Otter')
|
342
|
+
@user.other_user = otter
|
343
|
+
pack( @user ).should == Rat.new(
|
344
|
+
{'class' => 'User', 'ivars' => {
|
345
|
+
'@other_user' => {'class' => 'Aqua::Stub', 'init' => {'class' => 'User', 'methods' => {'username' => 'Otter'}, 'id' => ''}},
|
346
|
+
'@username' => 'Kane'
|
347
|
+
}}, {otter => "['ivars']['@other_user']"}
|
348
|
+
)
|
349
|
+
end
|
350
|
+
|
351
|
+
it 'self-referential externals' do
|
352
|
+
@user.other_user = @user
|
353
|
+
pack( @user ).should == Rat.new(
|
354
|
+
{'class' => 'User', 'ivars' => {
|
355
|
+
'@other_user' => {'class' => 'Aqua::Stub', 'init' => {'class' => 'User', 'methods' => {'username' => 'Kane'}, 'id' => ''}},
|
356
|
+
'@username' => 'Kane'
|
357
|
+
}}, {@user => "['ivars']['@other_user']"}
|
358
|
+
)
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'self-referential embedded at first-generation' do
|
362
|
+
log = Log.new
|
363
|
+
log.message = log
|
364
|
+
pack( log ).should == Rat.new(
|
365
|
+
{'class' => 'Log', 'ivars' => {
|
366
|
+
'@message' => {'class' => 'Aqua::Stub', 'init' => {'class' => 'Log', 'id' => ''}}
|
367
|
+
}}, {log => "['ivars']['@message']" }
|
368
|
+
)
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'deeply nested self-referential embedded' do
|
372
|
+
pending( )
|
373
|
+
# create two class methods for packing ivars, one self referential
|
374
|
+
# depend on the instance method to determine if the object passed in is the base object
|
375
|
+
# query will have to search for either relf-referential or normal form
|
376
|
+
# unpacking should recognize self-referential form
|
377
|
+
log = Log.new
|
378
|
+
log.message = ['one', log]
|
379
|
+
pack( log ).should == Rat.new(
|
380
|
+
{'class' => 'Log', 'ivars' => {
|
381
|
+
'@message' => {
|
382
|
+
'class' => 'Array',
|
383
|
+
'init' => ['one', {
|
384
|
+
'class' => 'Aqua::Stub',
|
385
|
+
'init' => {'class' => 'Log', 'id' => 'self'}
|
386
|
+
}]
|
387
|
+
}
|
388
|
+
}}
|
389
|
+
)
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'nil' do
|
393
|
+
pack( nil ).pack.should == {'class' => 'NilClass', 'init' => '' }
|
394
|
+
end
|
395
|
+
|
396
|
+
describe 'classes' do
|
397
|
+
it 'should pack class variables'
|
398
|
+
it 'should pack class level instance variables'
|
399
|
+
it 'should pack class definition'
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|