moab-versioning 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/lib/moab.rb +59 -0
  3. data/lib/moab/bagger.rb +289 -0
  4. data/lib/moab/config.rb +21 -0
  5. data/lib/moab/exceptions.rb +18 -0
  6. data/lib/moab/file_group.rb +244 -0
  7. data/lib/moab/file_group_difference.rb +336 -0
  8. data/lib/moab/file_group_difference_subset.rb +45 -0
  9. data/lib/moab/file_instance.rb +82 -0
  10. data/lib/moab/file_instance_difference.rb +54 -0
  11. data/lib/moab/file_inventory.rb +279 -0
  12. data/lib/moab/file_inventory_difference.rb +132 -0
  13. data/lib/moab/file_manifestation.rb +85 -0
  14. data/lib/moab/file_signature.rb +200 -0
  15. data/lib/moab/signature_catalog.rb +195 -0
  16. data/lib/moab/signature_catalog_entry.rb +61 -0
  17. data/lib/moab/storage_object.rb +220 -0
  18. data/lib/moab/storage_object_version.rb +333 -0
  19. data/lib/moab/storage_repository.rb +57 -0
  20. data/lib/moab/storage_services.rb +104 -0
  21. data/lib/moab/verification_result.rb +83 -0
  22. data/lib/moab/version_metadata.rb +38 -0
  23. data/lib/moab/version_metadata_entry.rb +64 -0
  24. data/lib/moab/version_metadata_event.rb +47 -0
  25. data/lib/moab_stanford.rb +18 -0
  26. data/lib/monkey_patches.rb +65 -0
  27. data/lib/serializer.rb +36 -0
  28. data/lib/serializer/manifest.rb +76 -0
  29. data/lib/serializer/serializable.rb +178 -0
  30. data/lib/stanford/active_fedora_object.rb +34 -0
  31. data/lib/stanford/content_inventory.rb +236 -0
  32. data/lib/stanford/dor_metadata.rb +49 -0
  33. data/lib/stanford/storage_repository.rb +46 -0
  34. data/lib/stanford/storage_services.rb +66 -0
  35. data/lib/tasks/yard.rake +34 -0
  36. data/lib/tools/api_doc_generator.rb +396 -0
  37. data/lib/tools/spec_generator.rb +410 -0
  38. data/lib/tools/spec_generator_old.rb +49 -0
  39. metadata +252 -0
@@ -0,0 +1,49 @@
1
+ require 'moab_stanford'
2
+
3
+ module Stanford
4
+
5
+ # Stanford-specific utility methods for interfacing with DOR metadata files
6
+ #
7
+ # ====Data Model
8
+ # * <b>{DorMetadata} = utility methods for interfacing with Stanford metadata files (esp contentMetadata)</b>
9
+ # * {ContentInventory} [1..1] = utilities for transforming contentMetadata to versionInventory and doing comparsions
10
+ # * {ActiveFedoraObject} [1..*] = utility for extracting content or other information from a Fedora Instance
11
+ #
12
+ # @note Copyright (c) 2012 by The Board of Trustees of the Leland Stanford Junior University.
13
+ # All rights reserved. See {file:LICENSE.rdoc} for details.
14
+ class DorMetadata
15
+
16
+ # @return [String] The digital object identifier (druid)
17
+ attr_accessor :digital_object_id
18
+
19
+ # @return [Integer] \@versionId = The ordinal version number
20
+ attr_accessor :version_id
21
+
22
+ # @param digital_object_id [String] The digital object identifier
23
+ # @param version_id [Integer] The ordinal version number
24
+ # @return [Stanford::DorMetadata]
25
+ def initialize(digital_object_id, version_id=nil)
26
+ @digital_object_id = digital_object_id
27
+ @version_id = version_id
28
+ end
29
+
30
+ # @api internal
31
+ # @param directory [String] The location of the directory to be inventoried
32
+ # @param version_id (see #initialize)
33
+ # @return [FileInventory] Inventory of the files under the specified directory
34
+ def inventory_from_directory(directory, version_id=nil)
35
+ version_id ||= @version_id
36
+ version_inventory = FileInventory.new(:type=>'version',:digital_object_id=>@digital_object_id, :version_id=>version_id)
37
+ content_metadata = IO.read(File.join(directory,'contentMetadata.xml'))
38
+ content_group = ContentInventory.new.group_from_cm(content_metadata, 'preserve' )
39
+ version_inventory.groups << content_group
40
+ metadata_group = FileGroup.new(:group_id=>'metadata').group_from_directory(directory)
41
+ version_inventory.groups << metadata_group
42
+ version_inventory
43
+ end
44
+
45
+
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,46 @@
1
+ require 'moab_stanford'
2
+
3
+ module Stanford
4
+
5
+ # A class to represent the SDR repository store
6
+ #
7
+ # ====Data Model
8
+ # * <b>{StorageRepository} = represents a digital object repository storage node</b>
9
+ #
10
+ # @note Copyright (c) 2012 by The Board of Trustees of the Leland Stanford Junior University.
11
+ # All rights reserved. See {file:LICENSE.rdoc} for details.
12
+ class StorageRepository < Moab::StorageRepository
13
+
14
+ # @param object_id [String] The identifier of the digital object whose version is desired
15
+ # @return [Pathname] The location of the desired object's home directory
16
+ def storage_object_pathname(object_id)
17
+ case Moab::Config.path_method.to_s
18
+ when 'druid_tree'
19
+ repository_home.join(druid_tree(object_id))
20
+ when 'druid'
21
+ repository_home.join(object_id.split(/:/)[-1])
22
+ end
23
+ end
24
+
25
+ # @param object_id [String] The identifier of the digital object whose path is requested
26
+ # @return [String] the druid tree directory path based on the given object identifier.
27
+ def druid_tree(object_id)
28
+ syntax_msg = "Identifier has invalid suri syntax: #{object_id}"
29
+ raise syntax_msg + "nil or empty" if object_id.to_s.empty?
30
+ identifier = object_id.split(':')[-1]
31
+ raise syntax_msg if identifier.to_s.empty?
32
+ # The object identifier must be in the SURI format, otherwise an exception is raised:
33
+ # e.g. druid:aannnaannnn or aannnaannnn
34
+ # where 'a' is an alphabetic character
35
+ # where 'n' is a numeric character
36
+ if identifier =~ /^([a-z]{2})(\d{3})([a-z]{2})(\d{4})$/
37
+ return File.join( $1, $2, $3, $4, identifier)
38
+ else
39
+ raise syntax_msg
40
+ end
41
+ end
42
+
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,66 @@
1
+ require 'moab_stanford'
2
+
3
+ module Stanford
4
+
5
+ # An interface class to support access to SDR storage via a RESTful server
6
+ class StorageServices < Moab::StorageServices
7
+
8
+ # @return [StorageRepository] an instance of the interface to SDR storage
9
+ @@repository = Stanford::StorageRepository.new
10
+
11
+ # @param new_content_metadata [String] The content metadata to be compared to the base
12
+ # @param object_id [String] The digital object identifier of the object whose version inventory is the basis of the comparison
13
+ # @param subset [String] Speciifes which subset of files to list in the inventories extracted from the contentMetadata (all|preserve|publish|shelve)
14
+ # @param base_version [Integer] The ID of the version whose inventory is the basis of, if nil use latest version
15
+ # @return [FileInventoryDifference] The report of differences between the content metadata and the specified version
16
+ def self.compare_cm_to_version(new_content_metadata, object_id, subset, base_version=nil)
17
+ new_inventory = ContentInventory.new.inventory_from_cm(new_content_metadata, object_id, subset)
18
+ begin
19
+ # ObjectNotFoundException is raised if the object does not exist in storage
20
+ base_version ||= self.current_version(object_id)
21
+ # FileNotFoundException is raised if object exists but has no contentMetadata file
22
+ base_cm_pathname = self.retrieve_file('metadata', 'contentMetadata.xml', object_id, base_version)
23
+ base_inventory = ContentInventory.new.inventory_from_cm(base_cm_pathname.read, object_id, subset, base_version)
24
+ rescue Moab::ObjectNotFoundException, Moab::FileNotFoundException
25
+ # Create a skeletal FileInventory object, containing no file entries
26
+ storage_object = StorageObject.new(object_id, 'dummy')
27
+ base_version = StorageObjectVersion.new(storage_object,0)
28
+ base_inventory = base_version.file_inventory('version')
29
+ end
30
+ diff = FileInventoryDifference.new.compare(base_inventory, new_inventory)
31
+ metadata_diff = diff.group_difference('metadata')
32
+ diff.group_differences.delete(metadata_diff) if metadata_diff
33
+ diff
34
+ end
35
+
36
+ # @param new_content_metadata [String] The content metadata to be compared to the current signtature catalog
37
+ # @param object_id [String] The digital object identifier of the object whose signature catalog is to be used
38
+ # @param version_id [Integer] The ID of the version whose signature catalog is to be used, if nil use latest version
39
+ # @return [FileInventory] The versionAddtions report showing which files are new or modified in the content metadata
40
+ def self.cm_version_additions(new_content_metadata, object_id, version_id=nil)
41
+ new_inventory = ContentInventory.new.inventory_from_cm(new_content_metadata, object_id, 'preserve')
42
+ begin
43
+ # ObjectNotFoundException is raised if the object does not exist in storage
44
+ version_id ||= self.current_version(object_id)
45
+ storage_object_version = @@repository.storage_object(object_id).find_object_version(version_id)
46
+ signature_catalog = storage_object_version.signature_catalog
47
+ rescue Moab::ObjectNotFoundException
48
+ storage_object = StorageObject.new(object_id, 'dummy')
49
+ base_version = StorageObjectVersion.new(storage_object,0)
50
+ signature_catalog = base_version.signature_catalog
51
+ end
52
+ signature_catalog.version_additions(new_inventory)
53
+ end
54
+
55
+ # @param object_id [String] The digital object identifier of the object whose contentMetadata is to be remediated
56
+ # @param version_id [Integer] The ID of the version whose file data is to be used, if nil use latest version
57
+ # @return [String] Returns a remediated copy of the contentMetadata with fixity data filled in
58
+ def self.cm_remediate(object_id, version_id=nil)
59
+ cm = self.retrieve_file('metadata', 'contentMetadata.xml', object_id, version_id)
60
+ group = self.retrieve_file_group('content', object_id, version_id)
61
+ ContentInventory.new.remediate_content_metadata(cm,group)
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,34 @@
1
+ desc "Generate RDoc"
2
+ task :doc => ['doc:generate']
3
+
4
+ namespace :doc do
5
+ project_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
6
+ doc_destination = File.join(project_root, 'doc')
7
+
8
+ begin
9
+ require 'yard'
10
+ require 'yard/rake/yardoc_task'
11
+
12
+ YARD::Rake::YardocTask.new(:generate) do |yt|
13
+ yt.files = Dir.glob(File.join(project_root, 'lib', '*.rb')) +
14
+ Dir.glob(File.join(project_root, 'lib', 'serializer', '*.rb')) +
15
+ Dir.glob(File.join(project_root, 'lib', 'moab', '*.rb')) +
16
+ Dir.glob(File.join(project_root, 'lib', 'stanford', '*.rb')) +
17
+ ['-'] +
18
+ [ File.join(project_root, 'LICENSE.rdoc') ]
19
+
20
+ yt.options = ['--output-dir', doc_destination, '--hide-void-return']
21
+ end
22
+ rescue LoadError
23
+ desc "Generate YARD Documentation"
24
+ task :generate do
25
+ abort "Please install the YARD gem to generate rdoc."
26
+ end
27
+ end
28
+
29
+ desc "Remove generated documentation"
30
+ task :clean do
31
+ rm_r doc_destination if File.exists?(doc_destination)
32
+ end
33
+
34
+ end
@@ -0,0 +1,396 @@
1
+ #$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
2
+ require 'rubygems'
3
+ require 'hashery/orderedhash'
4
+ require 'pathname'
5
+ require 'yard'
6
+ include YARD
7
+ require 'moab_stanford'
8
+ include Serializer
9
+ include Moab
10
+ include Stanford
11
+
12
+ class String
13
+ def snake_case
14
+ self.gsub(/::/, '/').
15
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
16
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
17
+ tr("-", "_").
18
+ downcase
19
+ end
20
+ end
21
+
22
+ class Symbol
23
+ def snake_case
24
+ self.to_s.snake_case
25
+ end
26
+ end
27
+
28
+ class ApiClass
29
+ attr_accessor :class_name
30
+ attr_accessor :yard_class
31
+ attr_accessor :mhash
32
+ attr_accessor :ruby_class
33
+ attr_accessor :xml_tag
34
+ attr_accessor :description
35
+ attr_accessor :model
36
+
37
+ def self.class_hash=(class_hash)
38
+ @@class_hash = class_hash
39
+ end
40
+
41
+ def self.rootpath=(rootpath)
42
+ @@rootpath = rootpath
43
+ end
44
+
45
+ def initialize(class_name)
46
+ @class_name = class_name
47
+ @yard_class = @@class_hash[class_name]
48
+ if yard_class.nil?
49
+ raise "class_hash[#{class_name}] is Nil"
50
+ end
51
+ @mhash = categorize_members(@yard_class)
52
+ if @yard_class.path.include?('::')
53
+ ruby_module = Object::const_get(yard_class.path.split(/::/)[0])
54
+ @ruby_class = ruby_module.const_get(yard_class.name)
55
+ else
56
+ @ruby_class = Object::const_get(yard_class.path)
57
+ end
58
+
59
+ if @ruby_class.respond_to?(:tag_name)
60
+ @xml_tag = "<#{ruby_class.tag_name}>"
61
+ else
62
+ @xml_tag = '-'
63
+ end
64
+ docstring_all = confluence_translate(yard_class.docstring.all.split(/@/)[0])
65
+ docstring_parts = docstring_all.split(/h4. Data Model\n/)
66
+ @description = docstring_parts[0]
67
+ @model = docstring_parts.size > 1 ? docstring_parts[1] : nil
68
+ end
69
+
70
+ def categorize_members(yard_class)
71
+ mhash = {
72
+ :class_attributes => OrderedHash.new,
73
+ :instance_attributes => OrderedHash.new,
74
+ :class_methods => Array.new,
75
+ :instance_methods => Array.new
76
+ }
77
+ yard_class.children.each do |member|
78
+ attr_symbol = member.name.to_s.gsub(/=$/, '').to_sym
79
+ if member.name == :initialize
80
+ mhash[:constructor] = member
81
+ elsif yard_class.class_attributes[attr_symbol]
82
+ mhash[:class_attributes][attr_symbol] = yard_class.class_attributes[attr_symbol]
83
+ elsif yard_class.instance_attributes[attr_symbol]
84
+ mhash[:instance_attributes][attr_symbol] = yard_class.instance_attributes[attr_symbol]
85
+ elsif member.scope == :class
86
+ mhash[:class_methods] << member
87
+ elsif member.scope == :instance
88
+ mhash[:instance_methods] << member
89
+ end
90
+ end
91
+ mhash
92
+ end
93
+
94
+ def title
95
+ title = "\n{anchor:#{yard_class.name}}\n"
96
+ title << "h3. Class #{yard_class.path}"
97
+ title
98
+ end
99
+
100
+ def description
101
+ description = "\nh4. Description\n\n"
102
+ description << @description
103
+ description
104
+ end
105
+
106
+ def model
107
+ model = "\nh4. Data Model\n\n"
108
+ model << @model
109
+ model
110
+ end
111
+
112
+ def xml_example
113
+ xml_example = String.new
114
+ if yard_class.docstring.has_tag?('example')
115
+ xml_example << "\nh4. XML Example\n"
116
+ xml_example << "{code:lang=xml}\n"
117
+ filename = yard_class.docstring.tag('example').name.split(/[:)}]/)[2]
118
+ example = IO.read(File.join(@@rootpath, filename))
119
+ xml_example << example
120
+ xml_example << "{code}\n"
121
+ end
122
+ xml_example
123
+ end
124
+
125
+ def instance_attributes_table(mode=:all)
126
+ table = String.new
127
+ table << "\\\\\n||XML Element||Ruby Class||Inherits From||\n"
128
+ table << "|#{xml_tag}|[##{class_name}]|#{yard_class.superclass}|\n"
129
+ table << "\\\\\n||XML Child Node||Ruby Attribute||Data Type||Description||\n"
130
+ xml_names = xml_name_hash
131
+ @mhash[:instance_attributes].values.each do |attribute|
132
+ read = attribute[:read]
133
+ return_tag = read.docstring.tag(:return)
134
+ ruby_name = read.name.to_s
135
+ xml_name = xml_names[ruby_name] ? xml_names[ruby_name] : "-"
136
+ data_type = return_tag.types[0]
137
+ description = confluence_translate(return_tag.text.gsub(/\n/, ' '))
138
+ table_row = "|#{xml_name}|#{ruby_name}|#{data_type}|#{description.gsub(/\|/, '\\|')}|\n"
139
+ case mode
140
+ when :xml
141
+ if xml_name != '-'
142
+ table << table_row
143
+ end
144
+ when :ruby
145
+ if xml_name == '-'
146
+ table << table_row
147
+ end
148
+ else
149
+ table << table_row
150
+ end
151
+ end
152
+ table
153
+ end
154
+
155
+ def xml_name_hash
156
+ xml_name_hash = Hash.new
157
+ if @ruby_class.respond_to?(:attributes)
158
+ @ruby_class.attributes.each do |attribute|
159
+ xml_name_hash[attribute.name.to_s] = "@#{attribute.tag}"
160
+ end
161
+ end
162
+ if @ruby_class.respond_to?(:elements)
163
+ @ruby_class.elements.each do |element|
164
+ if element.options.size == 0 or element.options[:single]
165
+ xml_name_hash[element.name.to_s] = "<#{element.tag}>"
166
+ else
167
+ xml_name_hash[element.name.to_s] = "<#{element.tag}> \\[1..\\*]"
168
+ end
169
+ end
170
+ end
171
+ xml_name_hash
172
+ end
173
+
174
+ def methods_documentation
175
+
176
+ methods_documentation = String.new
177
+
178
+ #methods_documentation ""
179
+ #methods_documentation "h4. Constructor"
180
+ #method = mhash[:constructor]
181
+ #methods_documentation_method(method, yard_class) if method
182
+
183
+ methods =mhash[:class_methods]
184
+ if methods.size > 0
185
+ methods_documentation << "\nh4. Class Methods\n"
186
+ methods.each do |method|
187
+ methods_documentation << method_documentation(method)
188
+ end
189
+ end
190
+
191
+ methods =mhash[:instance_methods]
192
+ if methods.size > 0
193
+ public_methods = Array.new
194
+ methods.each do |method|
195
+ if method.docstring.has_tag?(:api) && method.docstring.tag(:api).text == 'external'
196
+ public_methods << method
197
+ end
198
+ end
199
+ if public_methods.size > 0
200
+ methods_documentation << "\nh4. Instance Methods\n"
201
+ public_methods.each do |method|
202
+ methods_documentation << method_documentation(method)
203
+ end
204
+ end
205
+ end
206
+ methods_documentation
207
+ end
208
+
209
+ def method_documentation(method)
210
+
211
+ method_documentation = String.new
212
+ if method.nil?
213
+ raise "method is nil"
214
+ end
215
+ method_documentation << "\nh5. #{method.path}\n"
216
+
217
+ method_documentation << "||Method||Return Type||Description||\n"
218
+ if method.name == :initialize
219
+ return_type = @yard_class.name
220
+ description = 'constructor'
221
+ else
222
+ return_tag = method.docstring.tag(:return)
223
+ if return_tag.nil?
224
+ raise "#{method.name} return tag is nil"
225
+ end
226
+ return_type = return_tag.types[0]
227
+ description = confluence_translate(return_tag.text.gsub(/\n/, ' '))
228
+ end
229
+ method_documentation << "|#{method.name}|#{return_type}|#{example.description}|\n"
230
+
231
+ if method.respond_to?(:docstring)
232
+ params = method.docstring.tags(:param)
233
+ if params && params.size > 0
234
+ method_documentation << "\n||Parameter||Data Type||Description||\n"
235
+ params.each do |p|
236
+ description = confluence_translate(p.text.gsub(/\n/, ' '))
237
+ method_documentation << "|#{p.name}|#{p.types.join(', ')}|#{example.description}|\n"
238
+ end
239
+ end
240
+ end
241
+
242
+ method_documentation << "{code:lang=none|title=Ruby Source Code}\n"
243
+ method_documentation << method.source
244
+ method_documentation << "{code}\n"
245
+
246
+ if method.docstring.has_tag?('example')
247
+ method_documentation << "\n{code:lang=none|title=Usage Example}\n"
248
+ filename = method.docstring.tag('example').name.split(/[:)}]/)[2]
249
+ example = IO.read(File.join(@@rootpath, filename))
250
+ method_documentation << example
251
+ method_documentation << "{code}\n"
252
+ end
253
+ method_documentation
254
+ end
255
+
256
+ def confluence_translate(input)
257
+ map = OrderedHash.new
258
+ map[/\|/] = "\\|"
259
+ map[/====/] = "h4. "
260
+ map[/\*/] = "\\*"
261
+ map[/\n\s{6}\\\*\s/] = "\n****\s"
262
+ map[/\n\s{4}\\\*\s/] = "\n***\s"
263
+ map[/\n\s{2}\\\*\s/] = "\n**\s"
264
+ map[/\n\\\*\s/] = "\n*\s"
265
+ map[/<[\/]*b>/] = "*"
266
+ map[/<[\/]*i>/] = "_"
267
+ map[/\[/] = "\\["
268
+ map[/\{#/] = "[#"
269
+ map[/\{http/] = "[http"
270
+ map[/\{/] = "[#"
271
+ map[/\}/] = "]"
272
+ output = input
273
+ map.each do |regex, replacement|
274
+ output.gsub!(regex, replacement)
275
+ end
276
+ output
277
+ end
278
+
279
+ end
280
+
281
+
282
+ class ApiDoc < ApiClass
283
+ attr_accessor :ios
284
+ attr_accessor :classes
285
+
286
+ def process_doc(ios)
287
+ @ios = ios
288
+ parse_model
289
+
290
+ output component
291
+ output model
292
+ output description
293
+ output xml_example
294
+ output xml_nodes
295
+ classes_detail
296
+ end
297
+
298
+ def component
299
+ component = "h2. Component: #{yard_class.name}\n"
300
+ component
301
+ end
302
+
303
+ def xml_nodes
304
+ nodes = "\nh4. XML Nodes\n"
305
+ @classes.each do |cls|
306
+ nodes << cls.instance_attributes_table(mode=:xml)
307
+ end
308
+ nodes
309
+ end
310
+
311
+ def classes_detail
312
+ @classes.each do |cls|
313
+ output cls.title
314
+ output cls.description if cls != self
315
+ output cls.methods_documentation
316
+ end
317
+ end
318
+
319
+ def parse_model
320
+ @classes = Array.new
321
+ @classes << self
322
+ if @model
323
+ model.lines.each do |line|
324
+ matches = line.scan(/\[#(.*)?\]/)
325
+ if matches.size > 0
326
+ match = matches[0][0].split(/\]/)[0]
327
+ if match != class_name
328
+ @classes << ApiClass.new(match)
329
+ end
330
+ end
331
+ end
332
+ end
333
+
334
+ end
335
+
336
+ def output(string)
337
+ @ios.puts string
338
+ end
339
+
340
+
341
+ end
342
+
343
+
344
+ class DocGenerator
345
+
346
+ def initialize(rootpath)
347
+ @rootpath = rootpath
348
+ end
349
+
350
+ def generate_docs(apis)
351
+ temp_pathname = Pathname(@rootpath).join('api', 'temp')
352
+ ApiClass.class_hash = get_class_hash
353
+ ApiClass.rootpath = @rootpath
354
+ apis.each do |api_name|
355
+ doc_pathname = temp_pathname.join(api_name + "_confluence.txt")
356
+ doc_pathname.parent.mkpath
357
+ #puts doc_pathname.to_s
358
+ #unless doc_pathname.exist?
359
+ begin
360
+ @constructor_params = Array.new
361
+ @indent = 0
362
+ ios = doc_pathname.open("w")
363
+ api_doc = ApiDoc.new(api_name)
364
+ api_doc.process_doc(ios)
365
+ ensure
366
+ ios.close
367
+ end
368
+ #end
369
+ end
370
+ end
371
+
372
+ def get_class_hash()
373
+ class_hash = Hash.new
374
+ yardoc = File.join(@rootpath, '.yardoc')
375
+ Registry.load!(yardoc) # loads all objects into memory
376
+ class_array = Registry.all(:class) # Array
377
+ class_array.each do |cls|
378
+ class_hash[cls.name.to_s] = cls
379
+ end
380
+ class_hash
381
+ end
382
+
383
+ end
384
+
385
+ apis = Array.new
386
+ apis << 'FileInventory'
387
+ apis << 'SignatureCatalog'
388
+ apis << 'FileInventoryDifference'
389
+ apis << 'VersionMetadata'
390
+ apis << 'Serializable'
391
+ apis << 'StorageObject'
392
+ apis << 'StorageRepository'
393
+ apis << 'DorMetadata'
394
+
395
+ sg = DocGenerator.new(File.expand_path(File.join(File.dirname(__FILE__), '..', '..')))
396
+ sg.generate_docs(apis)