yard 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/Rakefile +1 -1
- data/docs/Tags.md +10 -9
- data/lib/rubygems_plugin.rb +7 -3
- data/lib/yard.rb +5 -6
- data/lib/yard/autoload.rb +12 -9
- data/lib/yard/cli/stats.rb +11 -1
- data/lib/yard/cli/yri.rb +2 -2
- data/lib/yard/code_objects/base.rb +12 -2
- data/lib/yard/code_objects/class_object.rb +2 -0
- data/lib/yard/code_objects/class_variable_object.rb +2 -0
- data/lib/yard/code_objects/constant_object.rb +2 -0
- data/lib/yard/code_objects/method_object.rb +3 -0
- data/lib/yard/code_objects/module_object.rb +2 -0
- data/lib/yard/code_objects/namespace_mapper.rb +113 -0
- data/lib/yard/code_objects/namespace_object.rb +3 -0
- data/lib/yard/docstring.rb +1 -1
- data/lib/yard/docstring_parser.rb +28 -1
- data/lib/yard/handlers/c/handler_methods.rb +1 -0
- data/lib/yard/handlers/c/mixin_handler.rb +7 -1
- data/lib/yard/handlers/ruby/alias_handler.rb +4 -3
- data/lib/yard/handlers/ruby/constant_handler.rb +6 -1
- data/lib/yard/handlers/ruby/dsl_handler_methods.rb +20 -3
- data/lib/yard/parser/c/comment_parser.rb +1 -1
- data/lib/yard/parser/ruby/ruby_parser.rb +25 -5
- data/lib/yard/parser/source_parser.rb +1 -0
- data/lib/yard/registry.rb +22 -43
- data/lib/yard/registry_resolver.rb +171 -0
- data/lib/yard/rubygems/hook.rb +164 -0
- data/lib/yard/server.rb +2 -1
- data/lib/yard/server/commands/root_request_command.rb +27 -0
- data/lib/yard/server/commands/static_file_command.rb +3 -16
- data/lib/yard/server/doc_server_helper.rb +1 -1
- data/lib/yard/server/router.rb +16 -6
- data/lib/yard/tags/default_factory.rb +3 -1
- data/lib/yard/tags/directives.rb +4 -0
- data/lib/yard/templates/engine.rb +1 -1
- data/lib/yard/templates/helpers/html_helper.rb +7 -2
- data/lib/yard/templates/helpers/module_helper.rb +1 -0
- data/lib/yard/templates/helpers/text_helper.rb +12 -0
- data/lib/yard/templates/template_options.rb +1 -1
- data/lib/yard/version.rb +1 -1
- data/spec/cli/stats_spec.rb +8 -3
- data/spec/code_objects/base_spec.rb +9 -1
- data/spec/docstring_parser_spec.rb +36 -1
- data/spec/docstring_spec.rb +1 -6
- data/spec/handlers/c/mixin_handler_spec.rb +16 -0
- data/spec/handlers/constant_handler_spec.rb +9 -0
- data/spec/handlers/dsl_handler_spec.rb +18 -0
- data/spec/handlers/examples/dsl_handler_001.rb.txt +29 -0
- data/spec/parser/ruby/ruby_parser_spec.rb +42 -0
- data/spec/registry_spec.rb +46 -3
- data/spec/server/router_spec.rb +1 -1
- data/spec/server_spec.rb +9 -0
- data/spec/tags/default_factory_spec.rb +5 -0
- data/spec/templates/engine_spec.rb +10 -0
- data/spec/templates/examples/constant001.txt +2 -2
- data/spec/templates/helpers/html_helper_spec.rb +8 -1
- data/spec/templates/helpers/module_helper_spec.rb +35 -0
- data/spec/templates/helpers/text_helper_spec.rb +20 -0
- data/templates/default/module/setup.rb +1 -1
- metadata +7 -4
- data/spec/server/commands/static_file_command_spec.rb +0 -84
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/user_interaction'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Gem::YARDoc provides methods to generate YARDoc and yri data for installed gems
|
7
|
+
# upon gem installation.
|
8
|
+
#
|
9
|
+
# This file is automatically required by RubyGems 1.9 and newer.
|
10
|
+
|
11
|
+
module YARD
|
12
|
+
class RubygemsHook
|
13
|
+
|
14
|
+
include Gem::UserInteraction
|
15
|
+
extend Gem::UserInteraction
|
16
|
+
|
17
|
+
@yard_version = nil
|
18
|
+
|
19
|
+
##
|
20
|
+
# Force installation of documentation?
|
21
|
+
|
22
|
+
attr_accessor :force
|
23
|
+
|
24
|
+
##
|
25
|
+
# Generate yard?
|
26
|
+
|
27
|
+
attr_accessor :generate_yard
|
28
|
+
|
29
|
+
##
|
30
|
+
# Generate yri data?
|
31
|
+
|
32
|
+
attr_accessor :generate_yri
|
33
|
+
|
34
|
+
class << self
|
35
|
+
|
36
|
+
##
|
37
|
+
# Loaded version of YARD. Set by ::load_yard
|
38
|
+
|
39
|
+
attr_reader :yard_version
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Post installs hook that generates documentation for each specification in
|
45
|
+
# +specs+
|
46
|
+
|
47
|
+
def self.generation_hook(installer, specs)
|
48
|
+
start = Time.now
|
49
|
+
types = installer.document
|
50
|
+
|
51
|
+
generate_yard = types.include?('yardoc') || types.include?('yard')
|
52
|
+
generate_yri = types.include? 'yri'
|
53
|
+
|
54
|
+
specs.each do |spec|
|
55
|
+
new(spec, generate_yard, generate_yri).generate
|
56
|
+
end
|
57
|
+
|
58
|
+
return unless generate_yard or generate_yri
|
59
|
+
|
60
|
+
duration = (Time.now - start).to_i
|
61
|
+
names = specs.map(&:name).join ', '
|
62
|
+
|
63
|
+
say "Done installing documentation for #{names} after #{duration} seconds"
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Loads the YARD generator
|
68
|
+
|
69
|
+
def self.load_yard
|
70
|
+
return if @yard_version
|
71
|
+
|
72
|
+
require 'yard'
|
73
|
+
|
74
|
+
@yard_version = Gem::Version.new ::YARD::VERSION
|
75
|
+
end
|
76
|
+
|
77
|
+
def initialize(spec, generate_yard = false, generate_yri = true)
|
78
|
+
@doc_dir = spec.doc_dir
|
79
|
+
@force = false
|
80
|
+
@spec = spec
|
81
|
+
|
82
|
+
@generate_yard = generate_yard
|
83
|
+
@generate_yri = generate_yri
|
84
|
+
|
85
|
+
@yard_dir = spec.doc_dir('yard')
|
86
|
+
@yri_dir = spec.doc_dir('.yardoc')
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_yardoc(*args)
|
90
|
+
args << '--quiet' unless Gem.configuration.really_verbose
|
91
|
+
args << '--backtrace' if Gem.configuration.backtrace
|
92
|
+
unless File.file?(File.join(@spec.full_gem_path, '.yardopts'))
|
93
|
+
args << @spec.require_paths
|
94
|
+
if @spec.extra_rdoc_files.size > 0
|
95
|
+
args << '-'
|
96
|
+
args += @spec.extra_rdoc_files
|
97
|
+
end
|
98
|
+
end
|
99
|
+
args = args.flatten.map {|arg| arg.to_s }
|
100
|
+
|
101
|
+
Dir.chdir(@spec.full_gem_path) do
|
102
|
+
YARD::CLI::Yardoc.run(*args)
|
103
|
+
end
|
104
|
+
rescue Errno::EACCES => e
|
105
|
+
dirname = File.dirname e.message.split("-")[1].strip
|
106
|
+
raise Gem::FilePermissionError.new(dirname)
|
107
|
+
rescue => ex
|
108
|
+
alert_error "While generating documentation for #{@spec.full_name}"
|
109
|
+
ui.errs.puts "... MESSAGE: #{ex}"
|
110
|
+
ui.errs.puts "... YARDOC args: #{args.join(' ')}"
|
111
|
+
ui.errs.puts "\t#{ex.backtrace.join("\n\t")}" if Gem.configuration.backtrace
|
112
|
+
ui.errs.puts "(continuing with the rest of the installation)"
|
113
|
+
end
|
114
|
+
|
115
|
+
def install_yard
|
116
|
+
FileUtils.rm_rf @yard_dir
|
117
|
+
|
118
|
+
say "Installing YARD documentation for #{@spec.full_name}..."
|
119
|
+
run_yardoc '-o', @yard_dir
|
120
|
+
end
|
121
|
+
|
122
|
+
def install_yri
|
123
|
+
FileUtils.rm_rf @yri_dir
|
124
|
+
|
125
|
+
say "Building YARD (yri) index for #{@spec.full_name}..."
|
126
|
+
run_yardoc '-c', '-n', '--db', @yri_dir
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Generates YARD and yri data
|
131
|
+
|
132
|
+
def generate
|
133
|
+
return if @spec.default_gem?
|
134
|
+
return unless @generate_yri || @generate_yard
|
135
|
+
|
136
|
+
setup
|
137
|
+
|
138
|
+
if @generate_yri && (@force || !File.exist?(@yri_dir))
|
139
|
+
install_yri
|
140
|
+
end
|
141
|
+
|
142
|
+
if @generate_yard && (@force || !File.exist?(@yard_dir))
|
143
|
+
install_yard
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Prepares the spec for documentation generation
|
149
|
+
|
150
|
+
def setup
|
151
|
+
self.class.load_yard
|
152
|
+
|
153
|
+
if File.exist?(@doc_dir)
|
154
|
+
unless File.writable?(@doc_dir)
|
155
|
+
raise Gem::FilePermissionError, @doc_dir
|
156
|
+
end
|
157
|
+
else
|
158
|
+
FileUtils.mkdir_p @doc_dir
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
Gem.done_installing(&YARD::RubygemsHook.method(:generation_hook))
|
data/lib/yard/server.rb
CHANGED
@@ -5,7 +5,8 @@ module YARD
|
|
5
5
|
# @return [void]
|
6
6
|
# @since 0.6.2
|
7
7
|
def self.register_static_path(path)
|
8
|
-
Commands::StaticFileCommand::STATIC_PATHS
|
8
|
+
static_paths = Commands::StaticFileCommand::STATIC_PATHS
|
9
|
+
static_paths.push(path) unless static_paths.include?(path)
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module YARD
|
2
|
+
module Server
|
3
|
+
module Commands
|
4
|
+
# Serves requests from the root of the server
|
5
|
+
class RootRequestCommand < Base
|
6
|
+
def run
|
7
|
+
favicon?
|
8
|
+
|
9
|
+
self.body = "Could not find: #{request.path}"
|
10
|
+
self.status = 404
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Return an empty favicon.ico if it does not exist so that
|
16
|
+
# browsers don't complain.
|
17
|
+
def favicon?
|
18
|
+
return unless request.path == '/favicon.ico'
|
19
|
+
self.headers['Content-Type'] = 'image/png'
|
20
|
+
self.status = 200
|
21
|
+
self.body = ''
|
22
|
+
raise FinishRequest
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -4,7 +4,7 @@ module YARD
|
|
4
4
|
module Server
|
5
5
|
module Commands
|
6
6
|
# Serves static content when no other router matches a request
|
7
|
-
class StaticFileCommand <
|
7
|
+
class StaticFileCommand < LibraryCommand
|
8
8
|
include WEBrick::HTTPUtils
|
9
9
|
|
10
10
|
DefaultMimeTypes['js'] = 'text/javascript'
|
@@ -17,7 +17,6 @@ module YARD
|
|
17
17
|
|
18
18
|
def run
|
19
19
|
assets_template = Templates::Engine.template(:default, :fulldoc, :html)
|
20
|
-
path = File.cleanpath(request.path).gsub(%r{^(../)+}, '')
|
21
20
|
|
22
21
|
file = nil
|
23
22
|
([adapter.document_root] + STATIC_PATHS.reverse).compact.each do |path_prefix|
|
@@ -30,27 +29,15 @@ module YARD
|
|
30
29
|
file ||= assets_template.find_file(path)
|
31
30
|
|
32
31
|
if file
|
33
|
-
ext = "." + (
|
32
|
+
ext = "." + (path[/\.(\w+)$/, 1] || "html")
|
34
33
|
headers['Content-Type'] = mime_type(ext, DefaultMimeTypes)
|
35
34
|
self.body = File.read(file)
|
36
35
|
return
|
37
36
|
end
|
38
37
|
|
39
|
-
|
38
|
+
self.body = "Could not find: #{request.path}"
|
40
39
|
self.status = 404
|
41
40
|
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
# Return an empty favicon.ico if it does not exist so that
|
46
|
-
# browsers don't complain.
|
47
|
-
def favicon?
|
48
|
-
return unless request.path == '/favicon.ico'
|
49
|
-
self.headers['Content-Type'] = 'image/png'
|
50
|
-
self.status = 200
|
51
|
-
self.body = ''
|
52
|
-
raise FinishRequest
|
53
|
-
end
|
54
41
|
end
|
55
42
|
end
|
56
43
|
end
|
@@ -10,7 +10,7 @@ module YARD
|
|
10
10
|
def url_for(obj, anchor = nil, relative = false)
|
11
11
|
return '' if obj.nil?
|
12
12
|
return url_for_index if obj == '_index.html'
|
13
|
-
return "/#{obj}" if String === obj
|
13
|
+
return "/#{base_path(router.static_prefix)}/#{obj}" if String === obj
|
14
14
|
url = super(obj, anchor, false)
|
15
15
|
return unless url
|
16
16
|
File.join('', base_path(router.docs_prefix), url)
|
data/lib/yard/server/router.rb
CHANGED
@@ -8,8 +8,8 @@ module YARD
|
|
8
8
|
# options through {Adapter#initialize} or by directly modifying {Adapter#router}.
|
9
9
|
#
|
10
10
|
# The most general customization is to change the URL prefixes recognized by
|
11
|
-
# routing, which can be done by overriding {#docs_prefix}, {#list_prefix}
|
12
|
-
# and {#search_prefix}.
|
11
|
+
# routing, which can be done by overriding {#docs_prefix}, {#list_prefix},
|
12
|
+
# {#static_prefix}, and {#search_prefix}.
|
13
13
|
#
|
14
14
|
# == Implementing Custom Caching
|
15
15
|
# By default, the Router class performs static disk-based caching on all
|
@@ -22,6 +22,7 @@ module YARD
|
|
22
22
|
# class MyRouter < YARD::Server::Router
|
23
23
|
# def docs_prefix; 'mydocs' end
|
24
24
|
# def list_prefix; 'mylist' end
|
25
|
+
# def static_prefix; 'mystatic' end
|
25
26
|
# def search_prefix; 'mysearch' end
|
26
27
|
# end
|
27
28
|
#
|
@@ -45,7 +46,7 @@ module YARD
|
|
45
46
|
end
|
46
47
|
|
47
48
|
# Perform routing on a specific request, serving the request as a static
|
48
|
-
# file through {Commands::
|
49
|
+
# file through {Commands::RootRequestCommand} if no route is found.
|
49
50
|
#
|
50
51
|
# @param [Adapter Dependent] request the request object
|
51
52
|
# @return [Array(Numeric,Hash,Array)] the Rack-style server response data
|
@@ -54,7 +55,7 @@ module YARD
|
|
54
55
|
if result = (check_static_cache || route)
|
55
56
|
result
|
56
57
|
else
|
57
|
-
|
58
|
+
RootRequestCommand.new(adapter.options).call(request)
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
@@ -69,6 +70,9 @@ module YARD
|
|
69
70
|
# @return [String] the URI prefix for all search requests
|
70
71
|
def search_prefix; 'search' end
|
71
72
|
|
73
|
+
# @return [String] the URI prefix for all static assets (templates)
|
74
|
+
def static_prefix; 'static' end
|
75
|
+
|
72
76
|
# @group Routing Methods
|
73
77
|
|
74
78
|
# @return [Array(LibraryVersion, Array<String>)] the library followed
|
@@ -101,7 +105,7 @@ module YARD
|
|
101
105
|
path = path.gsub(%r{//+}, '/').gsub(%r{^/|/$}, '')
|
102
106
|
return route_index if path.empty? || path == docs_prefix
|
103
107
|
case path
|
104
|
-
when /^(#{docs_prefix}|#{list_prefix}|#{search_prefix})(\/.*|$)/
|
108
|
+
when /^(#{docs_prefix}|#{list_prefix}|#{search_prefix}|#{static_prefix})(\/.*|$)/
|
105
109
|
prefix = $1
|
106
110
|
paths = $2.gsub(%r{^/|/$}, '').split('/')
|
107
111
|
library, paths = *parse_library_from_path(paths)
|
@@ -110,6 +114,7 @@ module YARD
|
|
110
114
|
when docs_prefix; route_docs(library, paths)
|
111
115
|
when list_prefix; route_list(library, paths)
|
112
116
|
when search_prefix; route_search(library, paths)
|
117
|
+
when static_prefix; route_static(library, paths)
|
113
118
|
end
|
114
119
|
end
|
115
120
|
nil
|
@@ -161,6 +166,10 @@ module YARD
|
|
161
166
|
SearchCommand.new(final_options(library, paths)).call(request)
|
162
167
|
end
|
163
168
|
|
169
|
+
def route_static(library, paths)
|
170
|
+
StaticFileCommand.new(final_options(library, paths)).call(request)
|
171
|
+
end
|
172
|
+
|
164
173
|
# @group Utility Methods
|
165
174
|
|
166
175
|
# Adds extra :library/:path option keys to the adapter options.
|
@@ -169,7 +178,8 @@ module YARD
|
|
169
178
|
# @param (see #route_docs)
|
170
179
|
# @return [Hash] finalized options
|
171
180
|
def final_options(library, paths)
|
172
|
-
|
181
|
+
path = File.cleanpath(paths.join('/')).gsub(%r{^(\.\./)+}, '')
|
182
|
+
adapter.options.merge(:library => library, :path => path)
|
173
183
|
end
|
174
184
|
end
|
175
185
|
end
|
@@ -162,10 +162,12 @@ module YARD
|
|
162
162
|
elsif c =~ /\S/ && level == 0
|
163
163
|
break e = i if seen_space && list == ['']
|
164
164
|
before << c
|
165
|
-
elsif c =~
|
165
|
+
elsif c =~ /[ \t]/ && level == 0 && !before.empty?
|
166
166
|
seen_space = true
|
167
167
|
elsif level >= 1
|
168
168
|
list.last << c
|
169
|
+
elsif level == 0 && c == "\n"
|
170
|
+
break e = i
|
169
171
|
end
|
170
172
|
last_seen = c
|
171
173
|
i += 1
|
data/lib/yard/tags/directives.rb
CHANGED
@@ -408,6 +408,10 @@ module YARD
|
|
408
408
|
obj.docstring = Docstring.new!(parser.text, parser.tags, obj,
|
409
409
|
parser.raw_text, parser.reference)
|
410
410
|
handler.register_module_function(obj)
|
411
|
+
old_obj = parser.object
|
412
|
+
parser.object = obj
|
413
|
+
parser.post_process
|
414
|
+
parser.object = old_obj
|
411
415
|
obj
|
412
416
|
end
|
413
417
|
end
|
@@ -18,7 +18,7 @@ module YARD
|
|
18
18
|
# @param [String] path a new template path
|
19
19
|
# @return [void]
|
20
20
|
def register_template_path(path)
|
21
|
-
template_paths.push path
|
21
|
+
template_paths.push(path) unless template_paths.include?(path)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Creates a template module representing the path. Searches on disk
|
@@ -242,12 +242,17 @@ module YARD
|
|
242
242
|
file = CodeObjects::ExtraFileObject.new(file)
|
243
243
|
end
|
244
244
|
file.attributes[:markup] ||= markup_for_file('', file.filename)
|
245
|
-
|
245
|
+
insert_include(file.contents, file.attributes[:markup] || options.markup)
|
246
246
|
end
|
247
247
|
|
248
248
|
# (see BaseHelper#link_include_object)
|
249
249
|
def link_include_object(obj)
|
250
|
-
|
250
|
+
insert_include(obj.docstring)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Inserts an include link while respecting inlining
|
254
|
+
def insert_include(text, markup = options.markup)
|
255
|
+
htmlify(text, markup).gsub(/\A\s*<p>|<\/p>\s*\Z/, '')
|
251
256
|
end
|
252
257
|
|
253
258
|
# (see BaseHelper#link_object)
|
@@ -9,6 +9,7 @@ module YARD
|
|
9
9
|
# @return [Array<CodeObjects::Base>] a pruned list of methods
|
10
10
|
def prune_method_listing(list, hide_attributes = true)
|
11
11
|
list = run_verifier(list)
|
12
|
+
list = list.reject {|o| run_verifier([o.parent]).empty? }
|
12
13
|
list = list.reject {|o| o.is_alias? unless CodeObjects::Proxy === o.namespace }
|
13
14
|
list = list.reject {|o| o.is_attribute? unless CodeObjects::Proxy === o.namespace } if hide_attributes
|
14
15
|
list
|
@@ -6,6 +6,7 @@ module YARD
|
|
6
6
|
# @return [String] escapes text
|
7
7
|
def h(text)
|
8
8
|
out = ""
|
9
|
+
text = resolve_links(text)
|
9
10
|
text = text.split(/\n/)
|
10
11
|
text.each_with_index do |line, i|
|
11
12
|
out <<
|
@@ -89,6 +90,17 @@ module YARD
|
|
89
90
|
title = "%s%s%s %s%s%s" % [scope, name, args, blk, type, extras_text]
|
90
91
|
title.gsub(/\s+/, ' ')
|
91
92
|
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def resolve_links(text)
|
97
|
+
text.gsub(/(\\|!)?\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=[\W]|$)/m) do |str|
|
98
|
+
escape, name, title, match = $1, $2, $3, $&
|
99
|
+
next(match[1..-1]) if escape
|
100
|
+
next(match) if name[0,1] == '|'
|
101
|
+
linkify(name, title)
|
102
|
+
end
|
103
|
+
end
|
92
104
|
end
|
93
105
|
end
|
94
106
|
end
|
@@ -75,8 +75,8 @@ module YARD
|
|
75
75
|
# @return [Boolean] whether a mixin matches the embed_mixins list
|
76
76
|
# @return [nil] if the mixin is not a module object
|
77
77
|
def embed_mixins_match?(mixin)
|
78
|
+
return true if mixin == object # the method is not inherited
|
78
79
|
return nil unless mixin.is_a?(CodeObjects::ModuleObject)
|
79
|
-
return nil if mixin == object # the method is not inherited
|
80
80
|
embed_mixins.any? do |embed_mixin|
|
81
81
|
re = /\A#{Regexp.quote(embed_mixin).gsub('\*', '.*')}\Z/
|
82
82
|
matchstr = embed_mixin.include?("::") ? mixin.path : mixin.name
|