moab-versioning 1.3.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.
- 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
|