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,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
|
data/lib/tasks/yard.rake
ADDED
@@ -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)
|