shomen 0.1.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/.ruby +43 -0
- data/.yardopts +7 -0
- data/HISTORY.rdoc +10 -0
- data/NOTES.rdoc +5 -0
- data/README.rdoc +68 -0
- data/bin/shomen +4 -0
- data/lib/shomen.yml +43 -0
- data/lib/shomen/cli.rb +22 -0
- data/lib/shomen/cli/abstract.rb +120 -0
- data/lib/shomen/cli/rdoc.rb +122 -0
- data/lib/shomen/cli/tomdoc.rb +119 -0
- data/lib/shomen/cli/yard.rb +118 -0
- data/lib/shomen/core_ext/hash.rb +3 -0
- data/lib/shomen/metadata.rb +81 -0
- data/lib/shomen/model.rb +21 -0
- data/lib/shomen/model/abstract.rb +84 -0
- data/lib/shomen/model/attribute.rb +25 -0
- data/lib/shomen/model/class.rb +19 -0
- data/lib/shomen/model/constant.rb +34 -0
- data/lib/shomen/model/document.rb +36 -0
- data/lib/shomen/model/interface.rb +35 -0
- data/lib/shomen/model/method.rb +104 -0
- data/lib/shomen/model/module.rb +56 -0
- data/lib/shomen/model/script.rb +49 -0
- data/lib/shomen/rdoc.rb +598 -0
- data/lib/shomen/rdoc/extensions.rb +145 -0
- data/lib/shomen/server.rb +10 -0
- data/lib/shomen/tomdoc.rb +151 -0
- data/lib/shomen/yard.rb +471 -0
- data/spec/01_metadata.rdoc +24 -0
- data/spec/02_class.rdoc +63 -0
- data/spec/03_module.rdoc +59 -0
- data/spec/04_constant.rdoc +59 -0
- data/spec/05_method.rdoc +286 -0
- data/spec/08_rdoc/01_interface_overloading.rdoc +94 -0
- data/spec/09_yard/01_interface_overloading.rdoc +93 -0
- data/spec/applique/shomen.rb +26 -0
- data/spec/fixture/lib/example.rb +52 -0
- metadata +122 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module Shomen
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
require 'shomen/model/abstract'
|
6
|
+
|
7
|
+
#
|
8
|
+
class Constant < Abstract
|
9
|
+
#
|
10
|
+
def self.type; 'constant'; end
|
11
|
+
|
12
|
+
# Constant's basename, must start with a capitalized letter.
|
13
|
+
attr_accessor :name
|
14
|
+
|
15
|
+
#
|
16
|
+
attr_accessor :namespace
|
17
|
+
|
18
|
+
#
|
19
|
+
attr_accessor :comment
|
20
|
+
|
21
|
+
# Format of comment (rdoc, markdown or plain).
|
22
|
+
attr_accessor :format
|
23
|
+
|
24
|
+
#
|
25
|
+
attr_accessor :value
|
26
|
+
|
27
|
+
#
|
28
|
+
attr_accessor :files
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Shomen
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
require 'shomen/model/abstract'
|
6
|
+
|
7
|
+
#
|
8
|
+
class Document < Abstract
|
9
|
+
#
|
10
|
+
def self.type
|
11
|
+
'document'
|
12
|
+
end
|
13
|
+
|
14
|
+
#def key=(path)
|
15
|
+
# path = '/' + path unless path[0,1] == '/'
|
16
|
+
# super(path)
|
17
|
+
#end
|
18
|
+
|
19
|
+
attr_accessor :name
|
20
|
+
|
21
|
+
#attr_accessor :parent
|
22
|
+
|
23
|
+
attr_accessor :path
|
24
|
+
|
25
|
+
attr_accessor :mtime
|
26
|
+
|
27
|
+
attr_accessor :text
|
28
|
+
|
29
|
+
# Format of comment (rdoc, markdown or plain).
|
30
|
+
attr_accessor :format
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Shomen
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
require 'shomen/model/abstract'
|
6
|
+
|
7
|
+
#
|
8
|
+
class Interface < AbstractPrime
|
9
|
+
|
10
|
+
# TODO: validate that there is an interface image.
|
11
|
+
def initialize(settings={})
|
12
|
+
#@table = {'arguments'=>[], 'parameters'=>[]}
|
13
|
+
super(settings)
|
14
|
+
end
|
15
|
+
|
16
|
+
# The source code "image" of the method's inteface.
|
17
|
+
attr_accessor :signature
|
18
|
+
|
19
|
+
# Arguments breakdown.
|
20
|
+
attr_accessor :arguments
|
21
|
+
|
22
|
+
# Parameters breakdown.
|
23
|
+
attr_accessor :parameters
|
24
|
+
|
25
|
+
# Block
|
26
|
+
attr_accessor :block
|
27
|
+
|
28
|
+
# Return value.
|
29
|
+
attr_accessor :returns
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Shomen
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
require 'shomen/model/abstract'
|
6
|
+
require 'shomen/model/interface'
|
7
|
+
|
8
|
+
#
|
9
|
+
class Method < Abstract
|
10
|
+
|
11
|
+
#
|
12
|
+
def initialize(settings={})
|
13
|
+
super(settings)
|
14
|
+
@table['declarations'] ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
# Method's name.
|
18
|
+
attr_accessor :name
|
19
|
+
|
20
|
+
# Method's namespace.
|
21
|
+
attr_accessor :namespace
|
22
|
+
|
23
|
+
# Comment accompanying method definition.
|
24
|
+
attr_accessor :comment
|
25
|
+
|
26
|
+
# Format of comment (rdoc, markdown or plain).
|
27
|
+
attr_accessor :format
|
28
|
+
|
29
|
+
# Singleton method `true` or `false/nil`.
|
30
|
+
attr_accessor :singleton
|
31
|
+
|
32
|
+
# Delarations is a list of keywords that designates characteristics
|
33
|
+
# about a method. Common characteristics include `reader`, `writer`
|
34
|
+
# or `accessor` if the method is defined via an attr method; `public`
|
35
|
+
# `private` or `protected` given the methods visibility; and `class`
|
36
|
+
# or `instance` given the methods scope. Default designations are
|
37
|
+
# are impled if not specifically stated, such as `public` and `instance`.
|
38
|
+
#
|
39
|
+
# Using a declarations list simplifies the Shomen data format by allowing
|
40
|
+
# declarations to be freely defined, rather than creating a field for each
|
41
|
+
# possible designation possible.
|
42
|
+
attr_accessor :declarations
|
43
|
+
|
44
|
+
# Aliases.
|
45
|
+
attr_accessor :aliases
|
46
|
+
|
47
|
+
# Aliases.
|
48
|
+
attr_accessor :alias_for
|
49
|
+
|
50
|
+
# Breakdown of interfaces signature, arguments, parameters, block argument
|
51
|
+
# an return values.
|
52
|
+
attr_accessor :interfaces
|
53
|
+
|
54
|
+
#
|
55
|
+
def interfaces=(array)
|
56
|
+
self['interfaces'] = (
|
57
|
+
array.map do |settings|
|
58
|
+
case settings
|
59
|
+
when Interface
|
60
|
+
settings
|
61
|
+
else
|
62
|
+
Interface.new(settings)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
# List of possible returns types.
|
69
|
+
attr_accessor :returns
|
70
|
+
|
71
|
+
# List of possible raised errors.
|
72
|
+
attr_accessor :raises
|
73
|
+
|
74
|
+
# Method generated dynamically?
|
75
|
+
attr_accessor :dynamic
|
76
|
+
|
77
|
+
# Filename.
|
78
|
+
attr_accessor :file
|
79
|
+
|
80
|
+
# Line number.
|
81
|
+
attr_accessor :line
|
82
|
+
|
83
|
+
# Source code.
|
84
|
+
attr_accessor :source
|
85
|
+
|
86
|
+
# Source code language.
|
87
|
+
attr_accessor :language
|
88
|
+
|
89
|
+
|
90
|
+
# Deprecated method.
|
91
|
+
alias :parent :namespace
|
92
|
+
|
93
|
+
#
|
94
|
+
def to_h
|
95
|
+
h = super
|
96
|
+
h['!'] = 'method'
|
97
|
+
h['interfaces'] = (interfaces || []).map{ |s| s.to_h }
|
98
|
+
h
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Shomen
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
require 'shomen/model/abstract'
|
6
|
+
|
7
|
+
#
|
8
|
+
class Module < Abstract
|
9
|
+
|
10
|
+
#
|
11
|
+
def self.type; 'module'; end
|
12
|
+
|
13
|
+
# Method's name.
|
14
|
+
attr_accessor :name
|
15
|
+
|
16
|
+
# Namespace of module is the path of the class or module
|
17
|
+
# containing this module.
|
18
|
+
attr_accessor :namespace
|
19
|
+
|
20
|
+
# Comment associated with module.
|
21
|
+
attr_accessor :comment
|
22
|
+
|
23
|
+
# Format of comment (rdoc, markdown or plain).
|
24
|
+
attr_accessor :format
|
25
|
+
|
26
|
+
# Mixins.
|
27
|
+
attr_accessor :includes
|
28
|
+
|
29
|
+
# Metaclass mixins.
|
30
|
+
attr_accessor :extensions
|
31
|
+
|
32
|
+
# Constants defined within this module.
|
33
|
+
attr_accessor :constants
|
34
|
+
|
35
|
+
#
|
36
|
+
attr_accessor :modules
|
37
|
+
|
38
|
+
#
|
39
|
+
attr_accessor :classes
|
40
|
+
|
41
|
+
# List of instance methods defined in the module.
|
42
|
+
attr_accessor :methods
|
43
|
+
|
44
|
+
# List of attributes.
|
45
|
+
attr_accessor :accessors
|
46
|
+
|
47
|
+
# The files in which the module is defined.
|
48
|
+
attr_accessor :files
|
49
|
+
|
50
|
+
#
|
51
|
+
alias :fullname :path
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Shomen
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
require 'shomen/model/document'
|
6
|
+
|
7
|
+
#
|
8
|
+
class Script < Document
|
9
|
+
#
|
10
|
+
def self.type; 'script'; end
|
11
|
+
|
12
|
+
#
|
13
|
+
attr_accessor :source
|
14
|
+
|
15
|
+
# Route textto source.
|
16
|
+
alias :text :source
|
17
|
+
alias :text= :source=
|
18
|
+
|
19
|
+
#
|
20
|
+
attr_accessor :language
|
21
|
+
|
22
|
+
#
|
23
|
+
attr_accessor :name
|
24
|
+
|
25
|
+
attr_accessor :path
|
26
|
+
|
27
|
+
attr_accessor :mtime
|
28
|
+
|
29
|
+
attr_accessor :header
|
30
|
+
|
31
|
+
attr_accessor :footer
|
32
|
+
|
33
|
+
attr_accessor :requires
|
34
|
+
|
35
|
+
attr_accessor :constants
|
36
|
+
|
37
|
+
attr_accessor :modules
|
38
|
+
|
39
|
+
attr_accessor :classes
|
40
|
+
|
41
|
+
attr_accessor :class_methods
|
42
|
+
|
43
|
+
attr_accessor :methods
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/lib/shomen/rdoc.rb
ADDED
@@ -0,0 +1,598 @@
|
|
1
|
+
#begin
|
2
|
+
# # requiroing rubygems is needed here b/c ruby comes with
|
3
|
+
# # rdoc but it's not the latest version.
|
4
|
+
# require 'rubygems'
|
5
|
+
# #gem 'rdoc', '>= 2.4' unless ENV['RDOC_TEST'] or defined?($rdoc_rakefile)
|
6
|
+
# gem "rdoc", ">= 2.4.2"
|
7
|
+
#rescue
|
8
|
+
#end
|
9
|
+
|
10
|
+
require 'fileutils'
|
11
|
+
require 'pathname'
|
12
|
+
require 'yaml'
|
13
|
+
require 'json'
|
14
|
+
|
15
|
+
require 'rdoc/rdoc'
|
16
|
+
require 'rdoc/generator'
|
17
|
+
require 'rdoc/generator/markup'
|
18
|
+
|
19
|
+
require 'shomen/metadata'
|
20
|
+
require 'shomen/model' # TODO: have metadata in model
|
21
|
+
require 'shomen/rdoc/extensions'
|
22
|
+
|
23
|
+
# Shomen Adaptor for RDoc utilizes the rdoc tool to parse ruby source code
|
24
|
+
# to build a Shomen documenation file.
|
25
|
+
#
|
26
|
+
# RDoc is almost entirely a free-form documentation system, so it is not
|
27
|
+
# possible for Shomen to fully harness all the details it can support from
|
28
|
+
# the RDoc documentation, such as method argument descriptions.
|
29
|
+
|
30
|
+
class RDoc::Generator::Shomen
|
31
|
+
|
32
|
+
# Register shomen generator with RDoc.
|
33
|
+
RDoc::RDoc.add_generator(self)
|
34
|
+
|
35
|
+
#include RDocShomen::Metadata
|
36
|
+
|
37
|
+
# Standard generator factory method.
|
38
|
+
def self.for(options)
|
39
|
+
new(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
# User options from the command line.
|
43
|
+
attr :options
|
44
|
+
|
45
|
+
# List of all classes and modules.
|
46
|
+
#def all_classes_and_modules
|
47
|
+
# @all_classes_and_modules ||= RDoc::TopLevel.all_classes_and_modules
|
48
|
+
#end
|
49
|
+
|
50
|
+
# In the world of the RDoc Generators #classes is the same
|
51
|
+
# as #all_classes_and_modules. Well, except that its sorted
|
52
|
+
# too. For classes sans modules, see #types.
|
53
|
+
|
54
|
+
def classes
|
55
|
+
@classes ||= RDoc::TopLevel.all_classes_and_modules.sort
|
56
|
+
end
|
57
|
+
|
58
|
+
# Only toplevel classes and modules.
|
59
|
+
def classes_toplevel
|
60
|
+
@classes_toplevel ||= classes.select {|klass| !(RDoc::ClassModule === klass.parent) }
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
def files
|
65
|
+
@files ||= (
|
66
|
+
@files_rdoc.select{ |f| f.parser != RDoc::Parser::Simple }
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
# List of toplevel files. RDoc supplies this via the #generate method.
|
71
|
+
def files_toplevel
|
72
|
+
@files_toplevel ||= (
|
73
|
+
@files_rdoc.select{ |f| f.parser == RDoc::Parser::Simple }
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
|
79
|
+
def files_hash
|
80
|
+
@files ||= RDoc::TopLevel.files_hash
|
81
|
+
end
|
82
|
+
|
83
|
+
# List of all methods in all classes and modules.
|
84
|
+
def methods_all
|
85
|
+
@methods_all ||= classes.map{ |m| m.method_list }.flatten.sort
|
86
|
+
end
|
87
|
+
|
88
|
+
# List of all attributes in all classes and modules.
|
89
|
+
def attributes_all
|
90
|
+
@attributes_all ||= classes.map{ |m| m.attributes }.flatten.sort
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
def constants_all
|
95
|
+
@constants_all ||= classes.map{ |c| c.constants }.flatten
|
96
|
+
end
|
97
|
+
|
98
|
+
## TODO: What's this then?
|
99
|
+
##def json_creatable?
|
100
|
+
## RDoc::TopLevel.json_creatable?
|
101
|
+
##end
|
102
|
+
|
103
|
+
# RDoc needs this to function.
|
104
|
+
def class_dir ; nil ; end
|
105
|
+
|
106
|
+
# RDoc needs this to function.
|
107
|
+
def file_dir ; nil ; end
|
108
|
+
|
109
|
+
# TODO: Rename ?
|
110
|
+
def shomen
|
111
|
+
@table || {}
|
112
|
+
end
|
113
|
+
|
114
|
+
# Build the initial indices and output objects
|
115
|
+
# based on an array of top level objects containing
|
116
|
+
# the extracted information.
|
117
|
+
def generate(files)
|
118
|
+
@files_rdoc = files.sort
|
119
|
+
|
120
|
+
@table = {}
|
121
|
+
|
122
|
+
generate_metadata
|
123
|
+
generate_constants
|
124
|
+
generate_classes
|
125
|
+
#generate_attributes
|
126
|
+
generate_methods
|
127
|
+
generate_documents
|
128
|
+
generate_scripts # must be last b/c it depends on the others
|
129
|
+
|
130
|
+
# TODO: method accessor fields need to be handled
|
131
|
+
|
132
|
+
# THINK: Internal referencing model, YAML and JSYNC ?
|
133
|
+
#ref_table = reference_table(@table)
|
134
|
+
|
135
|
+
#rescue StandardError => err
|
136
|
+
# debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ]
|
137
|
+
# raise err
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
protected
|
142
|
+
|
143
|
+
#
|
144
|
+
def initialize(options)
|
145
|
+
@options = options
|
146
|
+
#@options.diagram = false # why?
|
147
|
+
|
148
|
+
@path_base = Pathname.pwd.expand_path
|
149
|
+
|
150
|
+
# TODO: This is probably not needed any more.
|
151
|
+
@path_output = Pathname.new(@options.op_dir).expand_path(@path_base)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Current pathname.
|
155
|
+
attr :path_base
|
156
|
+
|
157
|
+
# The output path.
|
158
|
+
attr :path_output
|
159
|
+
|
160
|
+
#
|
161
|
+
def path_output_relative(path=nil)
|
162
|
+
if path
|
163
|
+
path.to_s.sub(path_base.to_s+'/', '')
|
164
|
+
else
|
165
|
+
@path_output_relative ||= path_output.to_s.sub(path_base.to_s+'/', '')
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
#
|
170
|
+
def generate_metadata
|
171
|
+
metadata = Shomen::Metadata.new
|
172
|
+
@table['(metadata)'] = metadata.to_h
|
173
|
+
end
|
174
|
+
|
175
|
+
# Add constants to table.
|
176
|
+
def generate_constants
|
177
|
+
debug_msg "Generating constant documentation:"
|
178
|
+
constants_all.each do |rdoc|
|
179
|
+
model = Shomen::Model::Constant.new
|
180
|
+
|
181
|
+
model.path = rdoc.parent.full_name + '::' + rdoc.name
|
182
|
+
model.name = rdoc.name
|
183
|
+
model.namespace = rdoc.parent.full_name
|
184
|
+
model.comment = rdoc.comment
|
185
|
+
model.format = 'rdoc'
|
186
|
+
model.value = rdoc.value
|
187
|
+
model.files = ["/#{rdoc.file.full_name}"]
|
188
|
+
|
189
|
+
@table[model.path] = model.to_h
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Add classes (and modules) to table.
|
194
|
+
def generate_classes
|
195
|
+
debug_msg "Generating class/module documentation:"
|
196
|
+
|
197
|
+
classes.each do |rdoc_class|
|
198
|
+
debug_msg "%s (%s)" % [ rdoc_class.full_name, rdoc_class.path ]
|
199
|
+
|
200
|
+
if rdoc_class.type=='class'
|
201
|
+
model = Shomen::Model::Class.new
|
202
|
+
else
|
203
|
+
model = Shomen::Model::Module.new
|
204
|
+
end
|
205
|
+
|
206
|
+
model.path = rdoc_class.full_name
|
207
|
+
model.name = rdoc_class.name
|
208
|
+
model.namespace = rdoc_class.full_name.split('::')[0...-1].join('::')
|
209
|
+
model.includes = rdoc_class.includes.map{ |x| x.name } # FIXME: How to "lookup" full name?
|
210
|
+
model.extensions = [] # TODO: How to get extensions?
|
211
|
+
model.comment = rdoc_class.comment
|
212
|
+
model.format = 'rdoc'
|
213
|
+
model.constants = rdoc_class.constants.map{ |x| complete_name(x.name, rdoc_class.full_name) }
|
214
|
+
model.modules = rdoc_class.modules.map{ |x| complete_name(x.name, rdoc_class.full_name) }
|
215
|
+
model.classes = rdoc_class.classes.map{ |x| complete_name(x.name, rdoc_class.full_name) }
|
216
|
+
model.methods = rdoc_class.method_list.map{ |m| method_name(m) }.uniq
|
217
|
+
model.accessors = rdoc_class.attributes.map{ |a| method_name(a) }.uniq #+ ":#{a.rw}" }.uniq
|
218
|
+
model.files = rdoc_class.in_files.map{ |x| "/#{x.full_name}" }
|
219
|
+
|
220
|
+
if rdoc_class.type == 'class'
|
221
|
+
# HACK: No idea why RDoc is returning some weird superclass:
|
222
|
+
# <RDoc::NormalClass:0xd924d4 class Object < BasicObject includes: []
|
223
|
+
# attributes: [] methods: [#<RDoc::AnyMethod:0xd92b8c Object#fileutils
|
224
|
+
# (public)>] aliases: []>
|
225
|
+
# Maybe it has something to do with #fileutils?
|
226
|
+
model.superclass = (
|
227
|
+
case rdoc_class.superclass
|
228
|
+
when nil
|
229
|
+
when String
|
230
|
+
rdoc_class.superclass
|
231
|
+
else
|
232
|
+
rdoc_class.superclass.full_name
|
233
|
+
end
|
234
|
+
)
|
235
|
+
end
|
236
|
+
|
237
|
+
@table[model.path] = model.to_h
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Transform RDoc methods to Shomen model and add to table.
|
242
|
+
#
|
243
|
+
# TODO: How to get literal interface separate from call-sequnces?
|
244
|
+
def generate_methods
|
245
|
+
debug_msg "Generating method documentation:"
|
246
|
+
|
247
|
+
list = methods_all + attributes_all
|
248
|
+
|
249
|
+
list.each do |rdoc_method|
|
250
|
+
#debug_msg "%s" % [rdoc_method.full_name]
|
251
|
+
|
252
|
+
#full_name = method_name(m)
|
253
|
+
#'prettyname' => m.pretty_name,
|
254
|
+
#'type' => m.type, # class or instance
|
255
|
+
|
256
|
+
model = Shomen::Model::Method.new
|
257
|
+
|
258
|
+
model.path = method_name(rdoc_method)
|
259
|
+
model.name = rdoc_method.name
|
260
|
+
model.namespace = rdoc_method.parent_name
|
261
|
+
model.comment = rdoc_method.comment
|
262
|
+
model.format = 'rdoc'
|
263
|
+
model.aliases = rdoc_method.aliases.map{ |a| method_name(a) }
|
264
|
+
model.alias_for = method_name(rdoc_method.is_alias_for)
|
265
|
+
model.singleton = rdoc_method.singleton
|
266
|
+
|
267
|
+
model.declarations << rdoc_method.type.to_s #singleton ? 'class' : 'instance'
|
268
|
+
model.declarations << rdoc_method.visibility.to_s
|
269
|
+
|
270
|
+
model.interfaces = []
|
271
|
+
if rdoc_method.call_seq
|
272
|
+
rdoc_method.call_seq.split("\n").each do |cs|
|
273
|
+
cs = cs.to_s.strip
|
274
|
+
model.interfaces << parse_interface(cs) unless cs == ''
|
275
|
+
end
|
276
|
+
end
|
277
|
+
model.interfaces << parse_interface("#{rdoc_method.name}#{rdoc_method.params}")
|
278
|
+
|
279
|
+
model.returns = [] # RDoc doesn't support specifying return values
|
280
|
+
model.file = '/'+rdoc_method.source_code_location.first
|
281
|
+
model.line = rdoc_method.source_code_location.last.to_i
|
282
|
+
model.source = rdoc_method.source_code_raw
|
283
|
+
|
284
|
+
if rdoc_method.respond_to?(:c_function)
|
285
|
+
model.language = rdoc_method.c_function ? 'c' : 'ruby'
|
286
|
+
else
|
287
|
+
model.language = 'ruby'
|
288
|
+
end
|
289
|
+
|
290
|
+
@table[model.path] = model.to_h
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
#--
|
295
|
+
=begin
|
296
|
+
#
|
297
|
+
def generate_attributes
|
298
|
+
#$stderr.puts "HERE!"
|
299
|
+
#$stderr.puts attributes_all.inspect
|
300
|
+
#exit
|
301
|
+
debug_msg "Generating attributes documentation:"
|
302
|
+
attributes_all.each do |rdoc_attribute|
|
303
|
+
debug_msg "%s" % [rdoc_attribute.full_name]
|
304
|
+
|
305
|
+
adapter = Shomen::RDoc::MethodAdapter.new(rdoc_attribute)
|
306
|
+
data = Shomen::Model::Method.new(adapter).to_h
|
307
|
+
|
308
|
+
@table[data['path']] = data
|
309
|
+
|
310
|
+
#code = m.source_code_raw
|
311
|
+
#file, line = m.source_code_location
|
312
|
+
|
313
|
+
#full_name = method_name(m)
|
314
|
+
|
315
|
+
#'prettyname' => m.pretty_name,
|
316
|
+
#'type' => m.type, # class or instance
|
317
|
+
|
318
|
+
#model_class = m.singleton ? Shomen::Model::Function : Shomen::Model::Method
|
319
|
+
#model_class = Shomen::Model::Attribute
|
320
|
+
|
321
|
+
#@table[full_name] = model_class.new(
|
322
|
+
# 'path' => full_name,
|
323
|
+
# 'name' => m.name,
|
324
|
+
# 'namespace' => m.parent_name,
|
325
|
+
# 'comment' => m.comment,
|
326
|
+
# 'access' => m.visibility.to_s,
|
327
|
+
# 'rw' => m.rw, # TODO: better name ?
|
328
|
+
# 'singleton' => m.singleton,
|
329
|
+
# 'aliases' => m.aliases.map{ |a| method_name(a) },
|
330
|
+
# 'alias_for' => method_name(m.is_alias_for),
|
331
|
+
# 'image' => m.params,
|
332
|
+
# 'arguments' => [],
|
333
|
+
# 'parameters' => [],
|
334
|
+
# 'block' => m.block_params, # TODO: what is block?
|
335
|
+
# 'interface' => m.arglists,
|
336
|
+
# 'returns' => [],
|
337
|
+
# 'file' => file,
|
338
|
+
# 'line' => line,
|
339
|
+
# 'source' => code
|
340
|
+
#).to_h
|
341
|
+
end
|
342
|
+
end
|
343
|
+
=end
|
344
|
+
#++
|
345
|
+
|
346
|
+
# Parse method interface.
|
347
|
+
#
|
348
|
+
# TODO: remove any trailing comment too
|
349
|
+
def parse_interface(interface)
|
350
|
+
args, block = [], {}
|
351
|
+
|
352
|
+
interface, returns = interface.split(/[=-]\>/)
|
353
|
+
interface = interface.strip
|
354
|
+
if i = interface.index(/\)\s*\{/)
|
355
|
+
block['signature'] = interface[i+1..-1].strip
|
356
|
+
interface = interface[0..i].strip
|
357
|
+
end
|
358
|
+
|
359
|
+
arguments = interface.strip.sub(/^.*?\(/,'').chomp(')')
|
360
|
+
arguments = arguments.split(/\s*\,\s*/)
|
361
|
+
arguments.each do |a|
|
362
|
+
if a.start_with?('&')
|
363
|
+
block['name'] = a
|
364
|
+
else
|
365
|
+
n,v = a.split('=')
|
366
|
+
args << (v ? {'name'=>n,'default'=>v} : {'name'=>n})
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
result = {}
|
371
|
+
result['signature'] = interface
|
372
|
+
result['arguments'] = args
|
373
|
+
result['block'] = block unless block.empty?
|
374
|
+
result['returns'] = returns.strip if returns
|
375
|
+
return result
|
376
|
+
end
|
377
|
+
private :parse_interface
|
378
|
+
|
379
|
+
# Generate entries for information files, e.g. `README.rdoc`.
|
380
|
+
def generate_documents
|
381
|
+
files_toplevel.each do |rdoc_document|
|
382
|
+
absolute_path = File.join(path_base, rdoc_document.full_name)
|
383
|
+
|
384
|
+
model = Shomen::Model::Document.new
|
385
|
+
|
386
|
+
model.path = rdoc_document.full_name
|
387
|
+
model.name = File.basename(absolute_path)
|
388
|
+
model.mtime = File.mtime(absolute_path)
|
389
|
+
model.text = File.read(absolute_path) #file.comment
|
390
|
+
model.format = mime_type(absolute_path)
|
391
|
+
|
392
|
+
@table['/'+model.path] = model.to_h
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
# TODO: Add loadpath and make file path relative to it?
|
397
|
+
|
398
|
+
# Generate script entries.
|
399
|
+
def generate_scripts
|
400
|
+
#debug_msg "Generating file documentation in #{path_output_relative}:"
|
401
|
+
#templatefile = self.path_template + 'file.rhtml'
|
402
|
+
|
403
|
+
files.each do |rdoc_file|
|
404
|
+
debug_msg "%s" % [rdoc_file.full_name]
|
405
|
+
|
406
|
+
absolute_path = File.join(path_base, rdoc_file.full_name)
|
407
|
+
#rel_prefix = self.path_output.relative_path_from(outfile.dirname)
|
408
|
+
|
409
|
+
model = Shomen::Model::Script.new
|
410
|
+
|
411
|
+
model.path = rdoc_file.full_name
|
412
|
+
model.name = File.basename(rdoc_file.full_name)
|
413
|
+
model.mtime = File.mtime(absolute_path)
|
414
|
+
|
415
|
+
if Shomen.source?
|
416
|
+
model.source = File.read(absolute_path) #file.comment
|
417
|
+
model.language = mime_type(absolute_path)
|
418
|
+
end
|
419
|
+
|
420
|
+
#model.header =
|
421
|
+
#model.footer =
|
422
|
+
model.requires = rdoc_file.requires.map{ |r| r.name }
|
423
|
+
model.constants = rdoc_file.constants.map{ |c| c.full_name }
|
424
|
+
|
425
|
+
# note that this utilizes the table we are building
|
426
|
+
# so it needs to be the last thing done.
|
427
|
+
@table.each do |k, h|
|
428
|
+
case h['!']
|
429
|
+
when 'module'
|
430
|
+
model.modules ||= []
|
431
|
+
model.modules << k if h['files'].include?(rdoc_file.full_name)
|
432
|
+
when 'class'
|
433
|
+
model.classes ||= []
|
434
|
+
model.classes << k if h['files'].include?(rdoc_file.full_name)
|
435
|
+
when 'method'
|
436
|
+
model.methods ||= []
|
437
|
+
model.methods << k if h['file'] == rdoc_file.full_name
|
438
|
+
when 'class-method'
|
439
|
+
model.class_methods ||= []
|
440
|
+
model.class_methods << k if h['file'] == rdoc_file.full_name
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
@table['/'+model.path] = model.to_h
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
# Returns String of fully qualified name.
|
449
|
+
def complete_name(name, namespace)
|
450
|
+
if name !~ /^#{namespace}/
|
451
|
+
"#{namespace}::#{name}"
|
452
|
+
else
|
453
|
+
name
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
#
|
458
|
+
def collect_methods(class_module, singleton=false)
|
459
|
+
list = []
|
460
|
+
class_module.method_list.each do |m|
|
461
|
+
next if singleton ^ m.singleton
|
462
|
+
list << method_name(m)
|
463
|
+
end
|
464
|
+
list.uniq
|
465
|
+
end
|
466
|
+
|
467
|
+
#
|
468
|
+
def collect_attributes(class_module, singleton=false)
|
469
|
+
list = []
|
470
|
+
class_module.attributes.each do |a|
|
471
|
+
next if singleton ^ a.singleton
|
472
|
+
#p a.rw
|
473
|
+
#case a.rw
|
474
|
+
#when :write, 'W'
|
475
|
+
# list << "#{method_name(a)}="
|
476
|
+
#else
|
477
|
+
list << method_name(a)
|
478
|
+
#end
|
479
|
+
end
|
480
|
+
list.uniq
|
481
|
+
end
|
482
|
+
|
483
|
+
#
|
484
|
+
def method_name(method)
|
485
|
+
return nil if method.nil?
|
486
|
+
if method.singleton
|
487
|
+
i = method.full_name.rindex('::')
|
488
|
+
method.full_name[0...i] + '.' + method.full_name[i+2..-1]
|
489
|
+
else
|
490
|
+
method.full_name
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
#
|
495
|
+
def mime_type(path)
|
496
|
+
case File.extname(path)
|
497
|
+
when '.rb', '.rbx' then 'text/ruby'
|
498
|
+
when '.c' then 'text/c-source'
|
499
|
+
when '.rdoc' then 'text/rdoc'
|
500
|
+
when '.md', '.markdown' then 'text/markdown'
|
501
|
+
else 'text/plain'
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
# Output progress information if rdoc debugging is enabled
|
506
|
+
|
507
|
+
def debug_msg(msg)
|
508
|
+
return unless $DEBUG_RDOC
|
509
|
+
case msg[-1,1]
|
510
|
+
when '.' then tab = "= "
|
511
|
+
when ':' then tab = "== "
|
512
|
+
else tab = "* "
|
513
|
+
end
|
514
|
+
$stderr.puts(tab + msg)
|
515
|
+
end
|
516
|
+
|
517
|
+
end
|
518
|
+
|
519
|
+
|
520
|
+
|
521
|
+
#--
|
522
|
+
=begin
|
523
|
+
#
|
524
|
+
# N O T U S E D
|
525
|
+
#
|
526
|
+
|
527
|
+
# Sort based on how often the top level namespace occurs, and then on the
|
528
|
+
# name of the module -- this works for projects that put their stuff into
|
529
|
+
# a namespace, of course, but doesn't hurt if they don't.
|
530
|
+
def sort_salient(classes)
|
531
|
+
nscounts = classes.inject({}) do |counthash, klass|
|
532
|
+
top_level = klass.full_name.gsub( /::.*/, '' )
|
533
|
+
counthash[top_level] ||= 0
|
534
|
+
counthash[top_level] += 1
|
535
|
+
counthash
|
536
|
+
endfiles_toplevel
|
537
|
+
classes.sort_by{ |klass|
|
538
|
+
top_level = klass.full_name.gsub( /::.*/, '' )
|
539
|
+
[nscounts[top_level] * -1, klass.full_name]
|
540
|
+
}.select{ |klass|
|
541
|
+
klass.document_self
|
542
|
+
}
|
543
|
+
end
|
544
|
+
=end
|
545
|
+
|
546
|
+
=begin
|
547
|
+
# Loop through table and convert all named references into bonofied object
|
548
|
+
# references.
|
549
|
+
def reference_table(table)
|
550
|
+
debug_msg "== Generating Reference Table"
|
551
|
+
new_table = {}
|
552
|
+
table.each do |key, entry|
|
553
|
+
debug_msg "%s" % [key]
|
554
|
+
data = entry.dup
|
555
|
+
new_table[key] = data
|
556
|
+
case data['!']
|
557
|
+
when 'script'
|
558
|
+
data["constants"] = ref_list(data["constants"])
|
559
|
+
data["modules"] = ref_list(data["modules"])
|
560
|
+
data["classes"] = ref_list(data["classes"])
|
561
|
+
data["functions"] = ref_list(data["functions"])
|
562
|
+
data["methods"] = ref_list(data["methods"])
|
563
|
+
when 'file'
|
564
|
+
when 'constant'
|
565
|
+
data["namespace"] = ref_item(data["namespace"])
|
566
|
+
when 'module', 'class'
|
567
|
+
data["namespace"] = ref_item(data["namespace"])
|
568
|
+
data["includes"] = ref_list(data["includes"])
|
569
|
+
#data["extended"] = ref_list(data["extended"])
|
570
|
+
data["constants"] = ref_list(data["constants"])
|
571
|
+
data["modules"] = ref_list(data["modules"])
|
572
|
+
data["classes"] = ref_list(data["classes"])
|
573
|
+
data["functions"] = ref_list(data["functions"])
|
574
|
+
data["methods"] = ref_list(data["methods"])
|
575
|
+
data["files"] = ref_list(data["files"])
|
576
|
+
data["superclass"] = ref_item(data["superclass"]) if data.key?("superclass")
|
577
|
+
when 'method', 'function'
|
578
|
+
data["namespace"] = ref_item(data["namespace"])
|
579
|
+
data["file"] = ref_item(data["file"])
|
580
|
+
end
|
581
|
+
end
|
582
|
+
new_table
|
583
|
+
end
|
584
|
+
|
585
|
+
# Given a key, return the matching table item. If not found return the key.
|
586
|
+
def ref_item(key)
|
587
|
+
@table[key] || key
|
588
|
+
end
|
589
|
+
|
590
|
+
# Given a list of keys, return the matching table items.
|
591
|
+
def ref_list(keys)
|
592
|
+
#keys.map{ |k| @table[k] || k }
|
593
|
+
keys.map{ |k| @table[k] || nil }.compact
|
594
|
+
end
|
595
|
+
|
596
|
+
=end
|
597
|
+
#++
|
598
|
+
|