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,145 @@
|
|
1
|
+
class RDoc::TopLevel
|
2
|
+
#
|
3
|
+
def to_h
|
4
|
+
{
|
5
|
+
:path => path,
|
6
|
+
:name => base_name,
|
7
|
+
:fullname => full_name,
|
8
|
+
:rootname => absolute_name,
|
9
|
+
:modified => last_modified,
|
10
|
+
:diagram => diagram
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
#def to_json
|
16
|
+
# to_h.to_json
|
17
|
+
#end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
class RDoc::ClassModule
|
22
|
+
#
|
23
|
+
def with_documentation?
|
24
|
+
document_self_or_methods || classes_and_modules.any?{ |c| c.with_documentation? }
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
def document_self_or_methods
|
29
|
+
document_self || method_list.any?{ |m| m.document_self }
|
30
|
+
end
|
31
|
+
|
32
|
+
# #
|
33
|
+
# def to_h
|
34
|
+
# {
|
35
|
+
# :name => name,
|
36
|
+
# :fullname => full_name,
|
37
|
+
# :type => type,
|
38
|
+
# :path => path,
|
39
|
+
# :superclass => module? ? nil : superclass
|
40
|
+
# }
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# def to_json
|
44
|
+
# to_h.to_json
|
45
|
+
# end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
module RDoc::SourceCodeAccess
|
50
|
+
|
51
|
+
#
|
52
|
+
def source_code_raw
|
53
|
+
return '' unless @token_stream
|
54
|
+
src = ""
|
55
|
+
@token_stream.each do |t|
|
56
|
+
next unless t
|
57
|
+
src << t.text
|
58
|
+
end
|
59
|
+
#add_line_numbers(src)
|
60
|
+
src
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
def source_code_location
|
65
|
+
src = source_code_raw
|
66
|
+
if md = /File (.*?), line (\d+)/.match(src)
|
67
|
+
file = md[1]
|
68
|
+
line = md[2]
|
69
|
+
else
|
70
|
+
file = "(unknown)"
|
71
|
+
line = 0
|
72
|
+
end
|
73
|
+
return file, line
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
class RDoc::AnyMethod
|
80
|
+
include RDoc::SourceCodeAccess
|
81
|
+
|
82
|
+
# # NOTE: dont_rename_initialize isn't used
|
83
|
+
# def to_h
|
84
|
+
# {
|
85
|
+
# :name => name,
|
86
|
+
# :fullname => full_name,
|
87
|
+
# :prettyname => pretty_name,
|
88
|
+
# :path => path,
|
89
|
+
# :type => type,
|
90
|
+
# :visibility => visibility,
|
91
|
+
# :blockparams => block_params,
|
92
|
+
# :singleton => singleton,
|
93
|
+
# :text => text,
|
94
|
+
# :aliases => aliases,
|
95
|
+
# :aliasfor => is_alias_for,
|
96
|
+
# :aref => aref,
|
97
|
+
# :parms => params,
|
98
|
+
# :callseq => call_seq
|
99
|
+
# #:paramseq => param_seq,
|
100
|
+
# }
|
101
|
+
# end
|
102
|
+
|
103
|
+
# #
|
104
|
+
# def to_json
|
105
|
+
# to_h.to_json
|
106
|
+
# end
|
107
|
+
end
|
108
|
+
|
109
|
+
class RDoc::Attr
|
110
|
+
include RDoc::SourceCodeAccess
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# DEPRECATE ASAP
|
115
|
+
require "rdoc/parser/c"
|
116
|
+
# New RDoc somehow misses class comemnts.
|
117
|
+
# copyied this function from "2.2.2"
|
118
|
+
if ['2.4.2', '2.4.3'].include? RDoc::VERSION
|
119
|
+
class RDoc::Parser::C
|
120
|
+
def find_class_comment(class_name, class_meth)
|
121
|
+
comment = nil
|
122
|
+
if @content =~ %r{((?>/\*.*?\*/\s+))
|
123
|
+
(static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then
|
124
|
+
comment = $1
|
125
|
+
elsif @content =~ %r{Document-(?:class|module):\s#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m
|
126
|
+
comment = $1
|
127
|
+
else
|
128
|
+
if @content =~ /rb_define_(class|module)/m then
|
129
|
+
class_name = class_name.split("::").last
|
130
|
+
comments = []
|
131
|
+
@content.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
|
132
|
+
comments[index] = chunk
|
133
|
+
if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
|
134
|
+
comment = comments[index-1]
|
135
|
+
break
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
class_meth.comment = mangle_comment(comment) if comment
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'tomdoc'
|
2
|
+
require 'shomen/metadata'
|
3
|
+
require 'shomen/model' # TODO: have metadata in model
|
4
|
+
|
5
|
+
module TomDoc
|
6
|
+
|
7
|
+
module Generators
|
8
|
+
|
9
|
+
# Shomen generator for TomDoc.
|
10
|
+
#
|
11
|
+
# IMPORTANT: Unfortunately TomDoc's parser does not yet provide enough
|
12
|
+
# information to generate a substantial Shomen model. As things currently
|
13
|
+
# stand THIS GENERATOR IS NOT USABLE. Hopefully in time the missing
|
14
|
+
# information will be added, and this can become a real option.
|
15
|
+
class Shomen < Generator
|
16
|
+
|
17
|
+
#
|
18
|
+
def initialize(options = {}, scopes = {})
|
19
|
+
super(options, scopes)
|
20
|
+
@table = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
def table; @table; end
|
25
|
+
|
26
|
+
#
|
27
|
+
def write_scope_header(scope, prefix)
|
28
|
+
# TODO: is it a module or class ?
|
29
|
+
model = ::Shomen::Model::Module.new
|
30
|
+
model = ::Shomen::Model::Class.new
|
31
|
+
|
32
|
+
model.name = scope.name.to_s
|
33
|
+
model.path = prefix.to_s + scope.name.to_s
|
34
|
+
model.comment = clean(scope.comment.strip)
|
35
|
+
|
36
|
+
@table[model.path] = model.to_h
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
def write_class_methods(scope, prefix)
|
41
|
+
prefix ="#{prefix}#{scope.name}."
|
42
|
+
|
43
|
+
scope.class_methods.map do |method|
|
44
|
+
next if !valid?(method, prefix)
|
45
|
+
write_method(method, prefix, 'class')
|
46
|
+
end.compact
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
def write_method(tomdoc_method, prefix='', kind='instance')
|
51
|
+
model = ::Shomen::Model::Method.new
|
52
|
+
|
53
|
+
doc = ::TomDoc::TomDoc.new(tomdoc_method.comment)
|
54
|
+
|
55
|
+
model.path = prefix + tomdoc_method.name.to_s
|
56
|
+
model.name = tomdoc_method.name.to_s
|
57
|
+
model.namespace = prefix.chomp('#').chomp('.')
|
58
|
+
# TODO: add examples to description or should shomen support examples?
|
59
|
+
model.comment = doc.description
|
60
|
+
|
61
|
+
model.format = 'tomdoc'
|
62
|
+
#model.aliases = tomdoc_method.aliases.map{ |a| method_name(a) }
|
63
|
+
#model.alias_for = method_name(tomdoc_method.is_alias_for)
|
64
|
+
model.singleton = (kind == 'class')
|
65
|
+
|
66
|
+
model.declarations << kind
|
67
|
+
|
68
|
+
# TODO: how to get visibility?
|
69
|
+
#model.declarations << tomdoc_method.visibility.to_s
|
70
|
+
|
71
|
+
#model.interfaces = []
|
72
|
+
#if tomdoc_method.call_seq
|
73
|
+
# tomdoc_method.call_seq.split("\n").each do |cs|
|
74
|
+
# cs = cs.to_s.strip
|
75
|
+
# model.interfaces << parse_interface(cs) unless cs == ''
|
76
|
+
# end
|
77
|
+
#end
|
78
|
+
|
79
|
+
model.interfaces = []
|
80
|
+
model.interfaces << parse_interface(tomdoc_method, doc)
|
81
|
+
|
82
|
+
model.returns = doc.returns
|
83
|
+
model.raises = doc.raises
|
84
|
+
|
85
|
+
# TODO: tomdoc doesn't provide these, so we are S.O.L.
|
86
|
+
# model.file = '/'+tomdoc_method.source_code_location.first
|
87
|
+
# model.line = tomdoc_method.source_code_location.last.to_i
|
88
|
+
# model.source = tomdoc_method.source_code_raw
|
89
|
+
|
90
|
+
#if tomdoc_method.respond_to?(:c_function)
|
91
|
+
# model.language = tomdoc_method.c_function ? 'c' : 'ruby'
|
92
|
+
#else
|
93
|
+
model.language = 'ruby'
|
94
|
+
#end
|
95
|
+
|
96
|
+
@table[model.path] = model.to_h
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# Parse method interface.
|
102
|
+
def parse_interface(method, doc)
|
103
|
+
args, block = [], {}
|
104
|
+
|
105
|
+
#interface, returns = interface.split(/[=-]\>/)
|
106
|
+
#interface = interface.strip
|
107
|
+
#if i = interface.index(/\)\s*\{/)
|
108
|
+
# block['signature'] = interface[i+1..-1].strip
|
109
|
+
# interface = interface[0..i].strip
|
110
|
+
#end
|
111
|
+
|
112
|
+
#arguments = interface.strip.sub(/^.*?\(/,'').chomp(')')
|
113
|
+
#arguments = arguments.split(/\s*\,\s*/)
|
114
|
+
doc.args.each do |a|
|
115
|
+
name = a.name.to_s
|
116
|
+
desc = a.description
|
117
|
+
|
118
|
+
if name.start_with?('&')
|
119
|
+
block['name'] = name
|
120
|
+
else
|
121
|
+
h = {'name'=>name,'comment'=>desc}
|
122
|
+
# TODO: doesn't look like tomdoc is providing argument defaults :(
|
123
|
+
if e = method.args.find{ |x| /^#{name}/ =~ x }
|
124
|
+
n,v = e.to_s.split('=')
|
125
|
+
h['default'] = v if v
|
126
|
+
end
|
127
|
+
args << h
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
result = {}
|
132
|
+
result['signature'] = "#{method.name}(#{method.args.join(',')})"
|
133
|
+
result['arguments'] = args
|
134
|
+
result['block'] = block unless block.empty?
|
135
|
+
#result['returns'] = returns.strip if returns
|
136
|
+
return result
|
137
|
+
end
|
138
|
+
|
139
|
+
# Remove hash prefixes from raw comment.
|
140
|
+
def clean(comment)
|
141
|
+
clean = comment.split("\n").map do |line|
|
142
|
+
line =~ /^(\s*# ?)/ ? line.sub($1, '') : nil
|
143
|
+
end.compact.join("\n")
|
144
|
+
clean
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
data/lib/shomen/yard.rb
ADDED
@@ -0,0 +1,471 @@
|
|
1
|
+
require 'yard'
|
2
|
+
require 'shomen/metadata'
|
3
|
+
require 'shomen/model'
|
4
|
+
|
5
|
+
module Shomen
|
6
|
+
|
7
|
+
# This adapter is used to convert YARD's documentation extracted
|
8
|
+
# from a local store (`.yardoc`) to Shomen's pure-data format.
|
9
|
+
#
|
10
|
+
class YardAdaptor
|
11
|
+
|
12
|
+
# The hash object that is used to store the generated
|
13
|
+
# documentation.
|
14
|
+
attr :table
|
15
|
+
|
16
|
+
# New adaptor.
|
17
|
+
def initialize(options)
|
18
|
+
@db = options[:db] || '.yardoc'
|
19
|
+
@files = options[:files] || ['lib', 'README*']
|
20
|
+
end
|
21
|
+
|
22
|
+
# Generate the shomen data structure.
|
23
|
+
def generate
|
24
|
+
if not File.exist?(@db)
|
25
|
+
$stderr.puts "ERROR: YARD database not found -- '#{@db}`."
|
26
|
+
exit -1
|
27
|
+
end
|
28
|
+
|
29
|
+
@table = {}
|
30
|
+
|
31
|
+
generate_metadata
|
32
|
+
|
33
|
+
@registry = YARD::Registry.load!(@db)
|
34
|
+
@registry.each do |object|
|
35
|
+
case object.type
|
36
|
+
when :constant
|
37
|
+
generate_constant(object)
|
38
|
+
when :class, :module
|
39
|
+
generate_class(object)
|
40
|
+
# TODO: is this needed?
|
41
|
+
object.constants.each do |c|
|
42
|
+
generate_constant(c)
|
43
|
+
end
|
44
|
+
#when :module
|
45
|
+
# generate_module(object)
|
46
|
+
# # TODO: is this needed?
|
47
|
+
# object.constants.each do |c|
|
48
|
+
# generate_constant(c)
|
49
|
+
# end
|
50
|
+
when :method
|
51
|
+
generate_method(object)
|
52
|
+
else
|
53
|
+
$stderr.puts "What is an #{object.type}? Ignored!"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# TODO: Are c/c++ sourse files working okay?
|
58
|
+
# TODO: Add a generator for non-ruby script (e.g. .js)?
|
59
|
+
collect_files.each do |file|
|
60
|
+
case File.extname(file)
|
61
|
+
when '.rb', '.rbx', '.c', '.cpp'
|
62
|
+
generate_script(file)
|
63
|
+
when '.rdoc', '.md', '.markdown', '.txt'
|
64
|
+
generate_document(file)
|
65
|
+
else
|
66
|
+
generate_document(file)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Collect files given list of +globs+.
|
74
|
+
def collect_files
|
75
|
+
globs = @files
|
76
|
+
globs = globs.map{ |glob| Dir[glob] }.flatten.uniq
|
77
|
+
globs = globs.map do |glob|
|
78
|
+
if File.directory?(glob)
|
79
|
+
Dir[File.join(glob, '**/*')]
|
80
|
+
else
|
81
|
+
glob
|
82
|
+
end
|
83
|
+
end
|
84
|
+
list = globs.flatten.uniq.compact
|
85
|
+
list = list.reject{ |path| File.extname(path) == '.html' }
|
86
|
+
list = list.select{ |path| File.file?(path) }
|
87
|
+
list
|
88
|
+
end
|
89
|
+
|
90
|
+
# Generate project metadata entry.
|
91
|
+
#
|
92
|
+
# @return [Hash] metadata added to the documentation table
|
93
|
+
def generate_metadata
|
94
|
+
metadata = Metadata.new
|
95
|
+
|
96
|
+
@table['(metadata)'] = metadata.to_h
|
97
|
+
end
|
98
|
+
|
99
|
+
# Generate a class or module structure.
|
100
|
+
#
|
101
|
+
# @note As to whether `methods` also contains the accessor methods
|
102
|
+
# listed in `accessors` is left to YARD to determine.
|
103
|
+
#
|
104
|
+
# @return [Hash] class data that has been placed in the table
|
105
|
+
def generate_class(yard_class)
|
106
|
+
debug_msg(yard_class.path.to_s)
|
107
|
+
|
108
|
+
meths = yard_class.meths(:included=>false, :inherited=>false)
|
109
|
+
|
110
|
+
if yard_class.type == :class
|
111
|
+
model = Model::Class.new
|
112
|
+
model.superclass = yard_class.superclass ? yard_class.superclass.path : 'Object'
|
113
|
+
else
|
114
|
+
model = Model::Module.new
|
115
|
+
end
|
116
|
+
|
117
|
+
model.path = yard_class.path
|
118
|
+
model.name = yard_class.name.to_s
|
119
|
+
model.namespace = yard_class.namespace.path #full_name.split('::')[0...-1].join('::'),
|
120
|
+
model.comment = yard_class.docstring.to_s
|
121
|
+
model.format = 'rdoc' #TODO: how to determine? rdoc, markdown or plaintext ?
|
122
|
+
model.constants = yard_class.constants.map{ |x| x.path } #TODO: complete_name(x.name, c.full_name) }
|
123
|
+
model.includes = yard_class.instance_mixins.map{ |x| x.path }
|
124
|
+
model.extensions = yard_class.class_mixins.map{ |x| x.path }
|
125
|
+
model.modules = yard_class.children.select{ |x| x.type == :module }.map{ |x| x.path }
|
126
|
+
#yard_class.modules.map{ |x| complete_name(x.name, c.full_name) }
|
127
|
+
model.classes = yard_class.children.select{ |x| x.type == :class }.map{ |x| x.path }
|
128
|
+
#yard_class.classes.map{ |x| complete_name(x.name, c.full_name) }
|
129
|
+
|
130
|
+
model.methods = meths.select.map{ |m| m.path }
|
131
|
+
#model.methods = meths.select{ |m| m.scope == :instance }.map{ |m| m.path }
|
132
|
+
#model.class_methods = meths.select{ |m| m.scope == :class }.map{ |m| m.path }
|
133
|
+
|
134
|
+
model.accessors = yard_class.attributes[:class].map{ |k, rw| yard_class.path + '.' + k.to_s } +
|
135
|
+
yard_class.attributes[:instance].map{ |k, rw| yard_class.path + '#' + k.to_s }
|
136
|
+
#model.class_accessors = yard_class.attributes[:class].map{ |k, rw| yard_class.path + '.' + k.to_s }
|
137
|
+
|
138
|
+
model.files = yard_class.files.map{ |f, l| "/#{f}" } # :#{l}" }
|
139
|
+
|
140
|
+
model.tags = translate_tags(yard_class)
|
141
|
+
|
142
|
+
#@files.concat(yard_class.files.map{ |f, l| f })
|
143
|
+
|
144
|
+
@table[model.path] = model.to_h
|
145
|
+
end
|
146
|
+
|
147
|
+
=begin
|
148
|
+
# Generate a module structure.
|
149
|
+
#
|
150
|
+
def generate_module(object)
|
151
|
+
index = object.path.to_s
|
152
|
+
#meths = object.meths(:included=>false, :inherited=>false)
|
153
|
+
|
154
|
+
debug_msg(index)
|
155
|
+
|
156
|
+
data = Model::Module.new(Yard::ModuleAdapter.new(object)).to_h
|
157
|
+
|
158
|
+
#data = Shomen::Model::Module.new(
|
159
|
+
# 'name' => object.name.to_s,
|
160
|
+
# 'namespace' => object.namespace.path, #full_name.split('::')[0...-1].join('::')
|
161
|
+
# 'comment' => object.docstring.to_s,
|
162
|
+
# 'constants' => object.constants.map{ |x| x.path }, #complete_name(x.name, c.full_name) }
|
163
|
+
# 'includes' => object.instance_mixins.map{ |x| x.path },
|
164
|
+
# 'extensions' => object.class_mixins.map{ |x| x.path },
|
165
|
+
# 'modules' => object.children.select{ |x| x.type == :module }.map{ |x| x.path },
|
166
|
+
# #object.modules.map{ |x| complete_name(x.name, c.full_name) }
|
167
|
+
# 'classes' => object.children.select{ |x| x.type == :class }.map{ |x| x.path },
|
168
|
+
# #object.classes.map{ |x| complete_name(x.name, c.full_name) }
|
169
|
+
# 'methods' => meths.select{ |m| m.scope == :instance }.map{ |m| m.path },
|
170
|
+
# 'class-methods' => meths.select{ |m| m.scope == :class }.map{ |m| m.path },
|
171
|
+
# #'attributes' => meths.select{ |m| m.scope == :instance }.map{ |m| m.path },
|
172
|
+
# #'class-attributes' => meths.select{ |m| m.scope == :class }.map{ |m| m.path },
|
173
|
+
# 'files' => object.files.map{ |f, l| "/#{f}:#{l}" }
|
174
|
+
#).to_h
|
175
|
+
|
176
|
+
#@files.concat(object.files.map{ |f, l| f })
|
177
|
+
|
178
|
+
@table[index] = data
|
179
|
+
end
|
180
|
+
=end
|
181
|
+
|
182
|
+
# Generate a method structure.
|
183
|
+
#
|
184
|
+
def generate_method(yard_method)
|
185
|
+
debug_msg(yard_method.to_s)
|
186
|
+
|
187
|
+
model = Model::Method.new
|
188
|
+
#class_model = object.scope == :instance ? Shomen::Module::Method : Shomen::Model::Function
|
189
|
+
|
190
|
+
model.path = yard_method.path
|
191
|
+
model.name = yard_method.name.to_s
|
192
|
+
model.namespace = yard_method.parent.path
|
193
|
+
model.comment = yard_method.docstring.to_s
|
194
|
+
model.format = 'rdoc' # TODO: how to determine? rdoc, markdown or plain
|
195
|
+
model.aliases = yard_method.aliases.map{ |a| a.path } #method_name(a) }
|
196
|
+
# TODO: how to get alias_for from YARD?
|
197
|
+
#model.alias_for = method_name(yard_method.alias_for)
|
198
|
+
model.singleton = (yard_method.scope == :class)
|
199
|
+
|
200
|
+
model.declarations << yard_method.scope.to_s
|
201
|
+
model.declarations << yard_method.visibility.to_s
|
202
|
+
# FIXME
|
203
|
+
#model.declarations << yard_method.attr_info
|
204
|
+
|
205
|
+
model.interfaces = []
|
206
|
+
yard_method.tags.each do |tag|
|
207
|
+
case tag
|
208
|
+
when ::YARD::Tags::OverloadTag
|
209
|
+
model.interfaces << parse_interface(tag)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
model.interfaces << parse_interface(yard_method)
|
213
|
+
|
214
|
+
model.returns = (
|
215
|
+
rtns = []
|
216
|
+
yard_method.tags(:return).each do |tag|
|
217
|
+
tag.types.each do |t|
|
218
|
+
rtns << {'type'=>t, 'comment'=>tag.text}
|
219
|
+
end
|
220
|
+
end
|
221
|
+
rtns
|
222
|
+
)
|
223
|
+
|
224
|
+
model.file = '/'+yard_method.file
|
225
|
+
model.line = yard_method.line.to_i
|
226
|
+
model.source = yard_method.source
|
227
|
+
model.language = yard_method.source_type.to_s
|
228
|
+
model.dynamic = yard_method.dynamic
|
229
|
+
|
230
|
+
model.tags = translate_tags(yard_method)
|
231
|
+
|
232
|
+
@table[model.path] = model.to_h
|
233
|
+
end
|
234
|
+
|
235
|
+
# Parse a yard method's interface.
|
236
|
+
def parse_interface(yard_method)
|
237
|
+
args, block = [], {}
|
238
|
+
|
239
|
+
image, returns = yard_method.signature.split(/[=-]\>/)
|
240
|
+
|
241
|
+
image = image.strip
|
242
|
+
if i = image.index(/\)\s*\{/)
|
243
|
+
block['image'] = image[i+1..-1].strip
|
244
|
+
image = image[0..i].strip
|
245
|
+
end
|
246
|
+
image = image.sub(/^def\s*/, '')
|
247
|
+
image = image.sub(/^self\./, '')
|
248
|
+
image = image.sub('( )','()')
|
249
|
+
|
250
|
+
yard_method.parameters.each do |n,v|
|
251
|
+
n = n.to_s
|
252
|
+
case n
|
253
|
+
when /^\&/
|
254
|
+
block['name'] = n
|
255
|
+
else
|
256
|
+
args << (v ? {'name'=>n,'default'=>v} : {'name'=>n})
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
result = {}
|
261
|
+
result['signature'] = image
|
262
|
+
result['arguments'] = args
|
263
|
+
#result['parameters'] = params
|
264
|
+
result['block'] = block unless block.empty?
|
265
|
+
result['returns'] = returns.strip if returns
|
266
|
+
result
|
267
|
+
end
|
268
|
+
private :parse_interface
|
269
|
+
|
270
|
+
# Generate a constant.
|
271
|
+
#
|
272
|
+
def generate_constant(yard_constant)
|
273
|
+
debug_msg(yard_constant.path.to_s)
|
274
|
+
|
275
|
+
model = Model::Constant.new
|
276
|
+
|
277
|
+
model.path = yard_constant.path
|
278
|
+
model.name = yard_constant.name.to_s
|
279
|
+
model.namespace = yard_constant.namespace.path
|
280
|
+
model.comment = yard_constant.docstring.to_s
|
281
|
+
model.format = 'rdoc' # TODO: how to determine? rdoc, markdown or plain
|
282
|
+
model.value = yard_constant.value
|
283
|
+
model.tags = translate_tags(yard_constant)
|
284
|
+
model.files = yard_constant.files.map{|f,l| "/#{f}"} # or "#{f}:#{l}" ?
|
285
|
+
|
286
|
+
@table[model.path] = model.to_h
|
287
|
+
end
|
288
|
+
|
289
|
+
# Generate a file.
|
290
|
+
#
|
291
|
+
def generate_document(yard_document)
|
292
|
+
debug_msg(yard_document)
|
293
|
+
|
294
|
+
model = Model::Document.new
|
295
|
+
|
296
|
+
# FIXME: make absolute
|
297
|
+
absolute_path = yard_document.to_s
|
298
|
+
|
299
|
+
model.path = yard_document.to_s
|
300
|
+
model.name = File.basename(absolute_path)
|
301
|
+
model.mtime = File.mtime(absolute_path)
|
302
|
+
model.text = File.read(absolute_path)
|
303
|
+
model.format = mime_type(absolute_path)
|
304
|
+
|
305
|
+
@table['/'+model.path] = model.to_h
|
306
|
+
end
|
307
|
+
|
308
|
+
# Generate a script entry.
|
309
|
+
#
|
310
|
+
def generate_script(yard_script)
|
311
|
+
debug_msg(yard_script)
|
312
|
+
|
313
|
+
model = Model::Script.new
|
314
|
+
|
315
|
+
# FIXME: make absolute
|
316
|
+
absolute_path = yard_script.to_s
|
317
|
+
|
318
|
+
model.path = yard_script.to_s
|
319
|
+
model.name = File.basename(absolute_path)
|
320
|
+
model.mtime = File.mtime(absolute_path)
|
321
|
+
model.source = File.read(absolute_path)
|
322
|
+
model.language = mime_type(absolute_path)
|
323
|
+
|
324
|
+
# model.header = ""
|
325
|
+
# model.footer = ""
|
326
|
+
# model.requires =
|
327
|
+
# model.constants =
|
328
|
+
# model.modules =
|
329
|
+
# model.classes =
|
330
|
+
# model.methods =
|
331
|
+
# model.class_methods =
|
332
|
+
|
333
|
+
@table['/'+model.path] = model.to_h
|
334
|
+
|
335
|
+
#table[index] = Shomen::Model::Script.new(
|
336
|
+
# "name" => File.basename(object),
|
337
|
+
# "path" => object,
|
338
|
+
# #"loadpath" => "lib",
|
339
|
+
# "mtime" => File.mtime(object),
|
340
|
+
# "header" => "",
|
341
|
+
# "footer" => "",
|
342
|
+
# # "requires" : ["fileutils"],
|
343
|
+
# # "constants" : ["MusicStore::CONFIG_DIRECTORY"],
|
344
|
+
# # "modules" : ["MusicStore", "MusicStore::MusicMixin"],
|
345
|
+
# # "classes" : ["MusicStore::Song"],
|
346
|
+
# # "functions" : ["MusicStore.config_directory"],
|
347
|
+
# # "methods" : ["MusicStore::MusicMixin#play", "MusicStore::MusicMixin#artist"]
|
348
|
+
# "source" => File.read(object)
|
349
|
+
#).to_h
|
350
|
+
|
351
|
+
@table['/'+model.path] = model.to_h
|
352
|
+
end
|
353
|
+
|
354
|
+
# Output progress information if debugging is enabled
|
355
|
+
#
|
356
|
+
def debug_msg(msg)
|
357
|
+
return unless $DEBUG
|
358
|
+
case msg[-1,1]
|
359
|
+
when '.' then tab = "= "
|
360
|
+
when ':' then tab = "== "
|
361
|
+
else tab = "* "
|
362
|
+
end
|
363
|
+
$stderr.puts(tab + msg)
|
364
|
+
end
|
365
|
+
|
366
|
+
# Given a file return offical mime-type basic on file extension.
|
367
|
+
#
|
368
|
+
# FIXME: official mime types?
|
369
|
+
def mime_type(path)
|
370
|
+
case File.extname(path)
|
371
|
+
when '.rb', '.rbx' then 'text/x-ruby'
|
372
|
+
when '.c' then 'text/c-source' # x-c-code
|
373
|
+
when '.js' then 'text/ecmascript'
|
374
|
+
when '.rdoc' then 'text/rdoc'
|
375
|
+
when '.md', '.markdown' then 'text/markdown'
|
376
|
+
else 'text/plain'
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Convert YARD Tags to simple Hash.
|
381
|
+
#
|
382
|
+
# TODO: Remove param tags?
|
383
|
+
def translate_tags(yard_object)
|
384
|
+
tags = {}
|
385
|
+
yard_object.tags.each do |tag|
|
386
|
+
next if tag.tag_name == 'return'
|
387
|
+
tags[tag.tag_name] = tag.text
|
388
|
+
end
|
389
|
+
return tags
|
390
|
+
end
|
391
|
+
|
392
|
+
end
|
393
|
+
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
|
398
|
+
|
399
|
+
|
400
|
+
|
401
|
+
|
402
|
+
|
403
|
+
|
404
|
+
|
405
|
+
|
406
|
+
|
407
|
+
|
408
|
+
|
409
|
+
|
410
|
+
|
411
|
+
|
412
|
+
|
413
|
+
=begin
|
414
|
+
# Generate a method structure.
|
415
|
+
#
|
416
|
+
def generate_attribute(object)
|
417
|
+
index = "#{object.path}"
|
418
|
+
|
419
|
+
debug_msg(index)
|
420
|
+
|
421
|
+
data = Model::Method.new(Yard::MethodAdapter.new(object)).to_h
|
422
|
+
|
423
|
+
##code = m.source_code_raw
|
424
|
+
##file, line = m.source_code_location
|
425
|
+
|
426
|
+
##full_name = method_name(m)
|
427
|
+
|
428
|
+
##'prettyname' => m.pretty_name,
|
429
|
+
##'type' => m.type, # class or instance
|
430
|
+
|
431
|
+
#args = []
|
432
|
+
#object.parameters.each do |var, val|
|
433
|
+
# if val
|
434
|
+
# args << { 'name' => var, 'default'=>val }
|
435
|
+
# else
|
436
|
+
# args << { 'name' => var }
|
437
|
+
# end
|
438
|
+
#end
|
439
|
+
#
|
440
|
+
#rtns = []
|
441
|
+
#object.tags(:return).each do |t|
|
442
|
+
# t.types.each do |ty|
|
443
|
+
# rtns << { 'type' => ty, 'comment' => t.text }
|
444
|
+
# end
|
445
|
+
#end
|
446
|
+
#
|
447
|
+
#table[index] = Shomen::Model::Attribute.new(
|
448
|
+
# 'name' => object.name.to_s,
|
449
|
+
# 'namespace' => object.parent.path,
|
450
|
+
# 'comment' => object.docstring.to_s,
|
451
|
+
# 'access' => object.visibility.to_s,
|
452
|
+
# 'singleton' => object.scope == :class,
|
453
|
+
# 'aliases' => object.aliases.map{ |a| a.path }, #method_name(a) },
|
454
|
+
# #'alias_for' => method_name(m.is_alias_for),
|
455
|
+
# 'interfaces' => [{'interface' => object.signature.sub('def ', ''), #m.params,
|
456
|
+
# 'arguments' => args,
|
457
|
+
# 'parameters' => []
|
458
|
+
# #'block' => m.block_params, # TODO: what is block?
|
459
|
+
# }],
|
460
|
+
# 'returns' => rtns,
|
461
|
+
# 'file' => "/#{object.file}",
|
462
|
+
# 'line' => object.line,
|
463
|
+
# 'source' => object.source,
|
464
|
+
# 'language' => object.source_type.to_s,
|
465
|
+
# 'dynamic' => object.dynamic
|
466
|
+
#).to_h
|
467
|
+
|
468
|
+
@table[index] = model.to_h
|
469
|
+
end
|
470
|
+
=end
|
471
|
+
|