moab-versioning 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/moab.rb +59 -0
- data/lib/moab/bagger.rb +289 -0
- data/lib/moab/config.rb +21 -0
- data/lib/moab/exceptions.rb +18 -0
- data/lib/moab/file_group.rb +244 -0
- data/lib/moab/file_group_difference.rb +336 -0
- data/lib/moab/file_group_difference_subset.rb +45 -0
- data/lib/moab/file_instance.rb +82 -0
- data/lib/moab/file_instance_difference.rb +54 -0
- data/lib/moab/file_inventory.rb +279 -0
- data/lib/moab/file_inventory_difference.rb +132 -0
- data/lib/moab/file_manifestation.rb +85 -0
- data/lib/moab/file_signature.rb +200 -0
- data/lib/moab/signature_catalog.rb +195 -0
- data/lib/moab/signature_catalog_entry.rb +61 -0
- data/lib/moab/storage_object.rb +220 -0
- data/lib/moab/storage_object_version.rb +333 -0
- data/lib/moab/storage_repository.rb +57 -0
- data/lib/moab/storage_services.rb +104 -0
- data/lib/moab/verification_result.rb +83 -0
- data/lib/moab/version_metadata.rb +38 -0
- data/lib/moab/version_metadata_entry.rb +64 -0
- data/lib/moab/version_metadata_event.rb +47 -0
- data/lib/moab_stanford.rb +18 -0
- data/lib/monkey_patches.rb +65 -0
- data/lib/serializer.rb +36 -0
- data/lib/serializer/manifest.rb +76 -0
- data/lib/serializer/serializable.rb +178 -0
- data/lib/stanford/active_fedora_object.rb +34 -0
- data/lib/stanford/content_inventory.rb +236 -0
- data/lib/stanford/dor_metadata.rb +49 -0
- data/lib/stanford/storage_repository.rb +46 -0
- data/lib/stanford/storage_services.rb +66 -0
- data/lib/tasks/yard.rake +34 -0
- data/lib/tools/api_doc_generator.rb +396 -0
- data/lib/tools/spec_generator.rb +410 -0
- data/lib/tools/spec_generator_old.rb +49 -0
- metadata +252 -0
@@ -0,0 +1,410 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hashery/orderedhash' if RUBY_VERSION < '1.9'
|
3
|
+
require 'pathname'
|
4
|
+
require 'yard'
|
5
|
+
include YARD
|
6
|
+
|
7
|
+
class String
|
8
|
+
def snake_case
|
9
|
+
self.gsub(/::/, '/').
|
10
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
11
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
12
|
+
tr("-", "_").
|
13
|
+
downcase
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Symbol
|
18
|
+
def snake_case
|
19
|
+
self.to_s.snake_case
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class SpecGenerator
|
24
|
+
|
25
|
+
def initialize(rootpath)
|
26
|
+
@rootpath = rootpath
|
27
|
+
@ios = $stdout
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_tests
|
31
|
+
spec_pathname = Pathname(@rootpath).join('spec', 'temp', "temp_unit_tests")
|
32
|
+
classes = get_classes
|
33
|
+
classes.each do |cls|
|
34
|
+
test_pathname = spec_pathname.join(cls.path.snake_case + "_spec.rb")
|
35
|
+
test_pathname.parent.mkpath
|
36
|
+
#puts test_pathname.to_s
|
37
|
+
unless test_pathname.exist?
|
38
|
+
begin
|
39
|
+
@constructor_params = Array.new
|
40
|
+
@indent = 0
|
41
|
+
@ios = test_pathname.open("w")
|
42
|
+
process_class(cls)
|
43
|
+
ensure
|
44
|
+
@ios.close
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_classes()
|
51
|
+
yardoc = File.join(@rootpath, '.yardoc')
|
52
|
+
Registry.load!(yardoc) # loads all objects into memory
|
53
|
+
Registry.all(:class) # Array
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param string [String]
|
57
|
+
def output(string)
|
58
|
+
@ios.puts " "*@indent + string
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param cls [CodeObjects::ClassObject]
|
62
|
+
def process_class(cls)
|
63
|
+
output %q{require File.join('..', '..','spec_helper')}
|
64
|
+
output ""
|
65
|
+
output "# Unit tests for class {#{cls.path}}"
|
66
|
+
output "describe '#{cls.path}' do"
|
67
|
+
@indent += 1
|
68
|
+
mhash = categorize_members(cls)
|
69
|
+
if mhash[:class_attributes].size > 0
|
70
|
+
process_attributes(cls, :class, mhash[:class_attributes])
|
71
|
+
end
|
72
|
+
if mhash[:class_methods].size > 0
|
73
|
+
process_methods(cls, :class, mhash)
|
74
|
+
end
|
75
|
+
|
76
|
+
process_constructor(cls, mhash)
|
77
|
+
|
78
|
+
if mhash[:instance_attributes].size > 0
|
79
|
+
process_attributes(cls, :instance, mhash[:instance_attributes])
|
80
|
+
end
|
81
|
+
if mhash[:instance_methods].size > 0
|
82
|
+
process_methods(cls, :instance, mhash)
|
83
|
+
end
|
84
|
+
|
85
|
+
@indent -= 1
|
86
|
+
output ""
|
87
|
+
output "end"
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param cls [CodeObjects::ClassObject]
|
91
|
+
def categorize_members(cls)
|
92
|
+
mhash = {
|
93
|
+
:class_attributes => OrderedHash.new,
|
94
|
+
:instance_attributes => OrderedHash.new,
|
95
|
+
:class_methods => Array.new,
|
96
|
+
:instance_methods => Array.new
|
97
|
+
}
|
98
|
+
cls.children.each do |member|
|
99
|
+
attr_symbol = member.name.to_s.gsub(/=$/, '').to_sym
|
100
|
+
if member.name == :initialize
|
101
|
+
mhash[:constructor] = member
|
102
|
+
elsif cls.class_attributes[attr_symbol]
|
103
|
+
mhash[:class_attributes][attr_symbol] = cls.class_attributes[attr_symbol]
|
104
|
+
elsif member.name.to_s[0..1] == '@@'
|
105
|
+
#mhash[:class_attributes][attr_symbol] = cls.class_attributes[attr_symbol]
|
106
|
+
elsif cls.instance_attributes[attr_symbol]
|
107
|
+
mhash[:instance_attributes][attr_symbol] = cls.instance_attributes[attr_symbol]
|
108
|
+
elsif not member.respond_to?(:scope)
|
109
|
+
#puts 'huh?'
|
110
|
+
elsif member.scope == :class
|
111
|
+
mhash[:class_methods] << member
|
112
|
+
elsif member.scope == :instance
|
113
|
+
mhash[:instance_methods] << member
|
114
|
+
end
|
115
|
+
end
|
116
|
+
mhash
|
117
|
+
end
|
118
|
+
|
119
|
+
def process_constructor(cls, mhash)
|
120
|
+
output ""
|
121
|
+
output "describe '=========================== CONSTRUCTOR ===========================' do"
|
122
|
+
|
123
|
+
@indent += 1
|
124
|
+
method = mhash[:constructor]
|
125
|
+
if method.respond_to?(:docstring)
|
126
|
+
@constructor_params = method.docstring.tags(:param)
|
127
|
+
|
128
|
+
output ""
|
129
|
+
output "# Unit test for constructor: {#{method.path}}"
|
130
|
+
output "# Which returns an instance of: [#{cls.path}]"
|
131
|
+
output "# For input parameters:"
|
132
|
+
@constructor_params.each do |p|
|
133
|
+
output "# * #{p.name} [#{p.types.join(', ')}] = #{p.text.gsub(/\n/, ' ')} "
|
134
|
+
end
|
135
|
+
output "specify '#{method.path}' do"
|
136
|
+
@indent += 1
|
137
|
+
|
138
|
+
cls_instance = cls.name.snake_case
|
139
|
+
param_list = (@constructor_params.collect { |p| p.name }).join(', ')
|
140
|
+
|
141
|
+
output " "
|
142
|
+
output "# test initialization with required parameters (if any)"
|
143
|
+
@constructor_params.each do |p|
|
144
|
+
if p.name == 'opts'
|
145
|
+
output "opts = {}"
|
146
|
+
else
|
147
|
+
output "#{p.name} = #{value_for(p.name, p.types[0])} "
|
148
|
+
end
|
149
|
+
end
|
150
|
+
output "#{cls_instance} = #{cls.name}.new(#{param_list})"
|
151
|
+
output "#{cls_instance}.should be_instance_of(#{cls.name})"
|
152
|
+
@constructor_params.each do |p|
|
153
|
+
unless p.name == 'opts'
|
154
|
+
output "#{cls_instance}.#{p.name}.should == #{p.name}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
arrays_and_hashes = attribute_arrays_and_hashes(mhash)
|
159
|
+
if arrays_and_hashes.size > 0
|
160
|
+
output " "
|
161
|
+
output "# test initialization of arrays and hashes"
|
162
|
+
arrays_and_hashes.each do |attr_name, type|
|
163
|
+
output "#{cls_instance}.#{attr_name}.should be_kind_of(#{type})"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
@constructor_params.each do |p|
|
168
|
+
if p.name == 'opts'
|
169
|
+
output " "
|
170
|
+
output "# test initialization with options hash"
|
171
|
+
output "opts = OrderedHash.new"
|
172
|
+
attribute_name_type_pairs(mhash).each do |name, type|
|
173
|
+
output "opts[:#{name}] = #{value_for(name, type)}"
|
174
|
+
end
|
175
|
+
output "#{cls_instance} = #{cls.name}.new(#{param_list})"
|
176
|
+
attribute_name_type_pairs(mhash).each do |name, type|
|
177
|
+
output "#{cls_instance}.#{name}.should == opts[:#{name}]"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
output_source(method)
|
183
|
+
@indent -= 1
|
184
|
+
|
185
|
+
output "end"
|
186
|
+
|
187
|
+
end
|
188
|
+
@indent -= 1
|
189
|
+
output ""
|
190
|
+
output "end"
|
191
|
+
end
|
192
|
+
|
193
|
+
def process_attributes(cls, scope, attributes)
|
194
|
+
output ""
|
195
|
+
output "describe '=========================== #{scope.to_s.upcase} ATTRIBUTES ===========================' do"
|
196
|
+
@indent += 1
|
197
|
+
|
198
|
+
if scope == :instance
|
199
|
+
output ""
|
200
|
+
output "before(:all) do"
|
201
|
+
@indent += 1
|
202
|
+
@constructor_params.each do |p|
|
203
|
+
if p.name == 'opts'
|
204
|
+
output "opts = {}"
|
205
|
+
else
|
206
|
+
output "#{p.name} = #{value_for(p.name, p.types[0])} "
|
207
|
+
end
|
208
|
+
end
|
209
|
+
cls_instance = cls.name.snake_case
|
210
|
+
param_list = (@constructor_params.collect { |p| p.name }).join(', ')
|
211
|
+
output "@#{cls_instance} = #{cls.name}.new(#{param_list})"
|
212
|
+
@indent -= 1
|
213
|
+
output "end"
|
214
|
+
end
|
215
|
+
|
216
|
+
attributes.values.each do |attribute|
|
217
|
+
if attribute.nil?
|
218
|
+
puts "huh?"
|
219
|
+
end
|
220
|
+
write = attribute[:write]
|
221
|
+
read = attribute[:read]
|
222
|
+
return_tag = read.docstring.tag(:return)
|
223
|
+
return_type = return_tag.types[0]
|
224
|
+
output ""
|
225
|
+
output "# Unit test for attribute: {#{read.path}}"
|
226
|
+
output "# Which stores: [#{return_type}] #{return_tag.text.gsub(/\n/, ' ')}"
|
227
|
+
output "specify '#{read.path}' do"
|
228
|
+
|
229
|
+
@indent += 1
|
230
|
+
output "value = #{value_for(read.name, return_type)}"
|
231
|
+
case scope
|
232
|
+
when :class
|
233
|
+
output "#{write.path} value"
|
234
|
+
output "#{read.path}.should == value"
|
235
|
+
when :instance
|
236
|
+
output "@#{cls.name.snake_case}.#{write.name} value"
|
237
|
+
output "@#{cls.name.snake_case}.#{read.name}.should == value"
|
238
|
+
end
|
239
|
+
|
240
|
+
output_source(write)
|
241
|
+
output_source(read)
|
242
|
+
|
243
|
+
@indent -= 1
|
244
|
+
output "end"
|
245
|
+
end
|
246
|
+
@indent -= 1
|
247
|
+
|
248
|
+
output ""
|
249
|
+
output "end"
|
250
|
+
end
|
251
|
+
|
252
|
+
def process_methods(cls, scope, mhash)
|
253
|
+
output ""
|
254
|
+
output "describe '=========================== #{scope.to_s.upcase} METHODS ===========================' do"
|
255
|
+
@indent += 1
|
256
|
+
|
257
|
+
if scope == :instance
|
258
|
+
output ""
|
259
|
+
output "before(:each) do"
|
260
|
+
@indent += 1
|
261
|
+
@constructor_params.each do |p|
|
262
|
+
if p.name == 'opts'
|
263
|
+
output "@opts = {}"
|
264
|
+
else
|
265
|
+
output "@#{p.name} = #{value_for(p.name, p.types[0])} "
|
266
|
+
end
|
267
|
+
end
|
268
|
+
cls_instance = cls.name.snake_case
|
269
|
+
param_list = (@constructor_params.collect { |p| '@'+p.name }).join(', ')
|
270
|
+
output "@#{cls_instance} = #{cls.name}.new(#{param_list})"
|
271
|
+
output ""
|
272
|
+
attribute_name_type_pairs(mhash).each do |name, type|
|
273
|
+
output "@#{cls_instance}.#{name} = #{value_for(name, type)}"
|
274
|
+
end
|
275
|
+
@indent -= 1
|
276
|
+
output "end"
|
277
|
+
end
|
278
|
+
|
279
|
+
case scope
|
280
|
+
when :class
|
281
|
+
methods =mhash[:class_methods]
|
282
|
+
when :instance
|
283
|
+
methods =mhash[:instance_methods]
|
284
|
+
end
|
285
|
+
|
286
|
+
methods.each do |method|
|
287
|
+
begin
|
288
|
+
return_tag = method.docstring.tag(:return)
|
289
|
+
return_type = return_tag.types[0]
|
290
|
+
|
291
|
+
|
292
|
+
params = method.docstring.tags(:param)
|
293
|
+
|
294
|
+
output ""
|
295
|
+
output "# Unit test for method: {#{method.path}}"
|
296
|
+
output "# Which returns: [#{return_type}] #{return_tag.text.gsub(/\n/, ' ')}"
|
297
|
+
if params.length > 0
|
298
|
+
output "# For input parameters:"
|
299
|
+
params.each do |p|
|
300
|
+
output "# * #{p.name} [#{p.types.join(', ')}] = #{p.text.gsub(/\n/, ' ')} "
|
301
|
+
end
|
302
|
+
else
|
303
|
+
output "# For input parameters: (None)"
|
304
|
+
end
|
305
|
+
|
306
|
+
output "specify '#{method.path}' do"
|
307
|
+
|
308
|
+
@indent += 1
|
309
|
+
params.each do |p|
|
310
|
+
output "#{p.name} = #{value_for(p.name, p.types[0])} "
|
311
|
+
end
|
312
|
+
param_list = (params.collect { |p| p.name }).join(', ')
|
313
|
+
if return_type == 'void'
|
314
|
+
case scope
|
315
|
+
when :class
|
316
|
+
output "#{method.path}(#{param_list})"
|
317
|
+
when :instance
|
318
|
+
output "@#{cls.name.snake_case}.#{method.name}(#{param_list})"
|
319
|
+
end
|
320
|
+
else
|
321
|
+
case scope
|
322
|
+
when :class
|
323
|
+
output "#{method.path}(#{param_list}).should == "
|
324
|
+
when :instance
|
325
|
+
output "@#{cls.name.snake_case}.#{method.name}(#{param_list}).should == "
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
output_source(method)
|
330
|
+
@indent -= 1
|
331
|
+
|
332
|
+
output "end"
|
333
|
+
|
334
|
+
rescue Exception => e
|
335
|
+
raise "Error processing method: #{method.path} - " + e.message
|
336
|
+
e.backtrace
|
337
|
+
end
|
338
|
+
end
|
339
|
+
@indent -= 1
|
340
|
+
|
341
|
+
output ""
|
342
|
+
output "end"
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
def value_for(name, return_type)
|
347
|
+
case return_type
|
348
|
+
when 'Symbol'
|
349
|
+
":test_#{name}"
|
350
|
+
when 'Integer'
|
351
|
+
rand(100).to_s
|
352
|
+
when 'String'
|
353
|
+
"'Test #{name}'"
|
354
|
+
when 'Boolean'
|
355
|
+
"true"
|
356
|
+
when 'Pathname'
|
357
|
+
"Pathname.new('/test/#{name}')"
|
358
|
+
when 'Time'
|
359
|
+
"Time.now"
|
360
|
+
else
|
361
|
+
type = return_type.split(/[<>]/)
|
362
|
+
if type.length > 1
|
363
|
+
case type[0]
|
364
|
+
when 'Array'
|
365
|
+
"[#{value_for(name, type[1])}]"
|
366
|
+
when 'Hash', 'OrderedHash'
|
367
|
+
key, value = type[1].split(/[,]/)
|
368
|
+
"{#{value_for(name, key)} => #{value_for(name, value)}}"
|
369
|
+
else
|
370
|
+
"double(#{return_type}.name)"
|
371
|
+
end
|
372
|
+
else
|
373
|
+
"double(#{return_type}.name)"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def attribute_arrays_and_hashes(mhash)
|
379
|
+
arrays_and_hashes = OrderedHash.new
|
380
|
+
attribute_name_type_pairs(mhash).each do |name, type|
|
381
|
+
if type.include?('Array')
|
382
|
+
arrays_and_hashes[name] = 'Array'
|
383
|
+
elsif type.include?('Hash')
|
384
|
+
arrays_and_hashes[name] = 'Hash'
|
385
|
+
end
|
386
|
+
end
|
387
|
+
arrays_and_hashes
|
388
|
+
end
|
389
|
+
|
390
|
+
def attribute_name_type_pairs(mhash)
|
391
|
+
pairs = OrderedHash.new
|
392
|
+
mhash[:instance_attributes].values.each do |attribute|
|
393
|
+
read = attribute[:read]
|
394
|
+
return_tag = read.docstring.tag(:return)
|
395
|
+
pairs[read.name] =return_tag.types[0]
|
396
|
+
end
|
397
|
+
pairs
|
398
|
+
end
|
399
|
+
|
400
|
+
def output_source(method)
|
401
|
+
output " "
|
402
|
+
lines = method.source.split(/\n/)
|
403
|
+
lines.each { |line| output "# #{line}" }
|
404
|
+
end
|
405
|
+
|
406
|
+
end
|
407
|
+
|
408
|
+
|
409
|
+
sg = SpecGenerator.new(File.expand_path(File.join(File.dirname(__FILE__), '..', '..')))
|
410
|
+
sg.generate_tests
|
@@ -0,0 +1,49 @@
|
|
1
|
+
rootpath = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
2
|
+
puts rootpath
|
3
|
+
lib = File.join(rootpath,'lib')
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'moab'
|
6
|
+
#spec_helper = File.join(rootpath,'spec','spec_helper')
|
7
|
+
|
8
|
+
class SpecGeneratorOld
|
9
|
+
|
10
|
+
attr_accessor :c
|
11
|
+
attr_accessor :members
|
12
|
+
|
13
|
+
def initialize(c)
|
14
|
+
@c=c
|
15
|
+
#require camel_to_snake_case(c.name)
|
16
|
+
i_members = c.instance_methods(include_super=false)
|
17
|
+
i_setters = i_members.grep /[^=][=]$/
|
18
|
+
i_getters = i_setters.collect { |s| s.gsub(/[=]$/,'') }
|
19
|
+
@members = Hash.new
|
20
|
+
@members['Instance Variables'] = (i_getters).sort
|
21
|
+
@members['Instance Methods'] = (i_members - i_setters - i_getters).sort
|
22
|
+
@members['Class Methods'] = c.methods(include_super=false).sort
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate
|
26
|
+
puts "require 'spec_helper'"
|
27
|
+
puts ""
|
28
|
+
puts "describe '#{@c.name}' do"
|
29
|
+
puts ""
|
30
|
+
['Instance Variables','Instance Methods','Class Methods'].each do |type |
|
31
|
+
puts " context '#{type}' do"
|
32
|
+
puts ""
|
33
|
+
@members[type].each do |member|
|
34
|
+
puts " describe '##{member}' do"
|
35
|
+
puts " pending"
|
36
|
+
puts " end"
|
37
|
+
puts ""
|
38
|
+
end
|
39
|
+
puts " end"
|
40
|
+
puts ""
|
41
|
+
end
|
42
|
+
puts "end"
|
43
|
+
end
|
44
|
+
|
45
|
+
def camel_to_snake_case(camel)
|
46
|
+
camel.gsub(/(.)([A-Z])/,'\1_\2').downcase
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|