yard 0.6.3 → 0.6.4
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.
- data/ChangeLog +119 -0
- data/README.md +16 -2
- data/Rakefile +29 -10
- data/docs/GettingStarted.md +186 -35
- data/lib/yard.rb +1 -1
- data/lib/yard/autoload.rb +10 -0
- data/lib/yard/cli/yri.rb +2 -2
- data/lib/yard/code_objects/base.rb +1 -1
- data/lib/yard/code_objects/method_object.rb +2 -1
- data/lib/yard/code_objects/root_object.rb +2 -2
- data/lib/yard/parser/ruby/ast_node.rb +0 -4
- data/lib/yard/parser/ruby/ruby_parser.rb +30 -1
- data/lib/yard/server/adapter.rb +50 -1
- data/lib/yard/server/commands/base.rb +117 -23
- data/lib/yard/server/commands/display_file_command.rb +3 -0
- data/lib/yard/server/commands/display_object_command.rb +1 -0
- data/lib/yard/server/commands/frames_command.rb +1 -0
- data/lib/yard/server/commands/library_command.rb +8 -1
- data/lib/yard/server/commands/list_command.rb +4 -0
- data/lib/yard/server/doc_server_helper.rb +15 -0
- data/lib/yard/server/doc_server_serializer.rb +2 -0
- data/lib/yard/server/library_version.rb +141 -0
- data/lib/yard/server/rack_adapter.rb +35 -2
- data/lib/yard/server/router.rb +71 -1
- data/lib/yard/server/static_caching.rb +29 -0
- data/lib/yard/server/webrick_adapter.rb +4 -0
- data/lib/yard/templates/engine.rb +1 -1
- data/lib/yard/templates/helpers/markup_helper.rb +22 -7
- data/spec/cli/diff_spec.rb +2 -2
- data/spec/cli/stats_spec.rb +1 -1
- data/spec/cli/yardoc_spec.rb +1 -1
- data/spec/cli/yri_spec.rb +21 -0
- data/spec/handlers/class_handler_spec.rb +1 -0
- data/spec/handlers/examples/class_handler_001.rb.txt +1 -0
- data/spec/parser/ruby/legacy/statement_list_spec.rb +6 -0
- data/spec/parser/ruby/ruby_parser_spec.rb +29 -0
- data/spec/server/rack_adapter_spec.rb +18 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/templates/engine_spec.rb +4 -1
- data/spec/templates/helpers/html_helper_spec.rb +11 -0
- data/spec/templates/helpers/markup_helper_spec.rb +9 -5
- data/spec/templates/module_spec.rb +1 -1
- data/spec/templates/spec_helper.rb +3 -3
- data/templates/default/fulldoc/html/css/style.css +1 -1
- data/templates/default/fulldoc/html/js/app.js +3 -2
- metadata +7 -15
data/lib/yard.rb
CHANGED
data/lib/yard/autoload.rb
CHANGED
@@ -135,10 +135,20 @@ module YARD
|
|
135
135
|
end
|
136
136
|
|
137
137
|
# Namespace for classes and modules that handle serving documentation over HTTP
|
138
|
+
#
|
139
|
+
# == Implementing a Custom Server
|
140
|
+
# To customize the YARD server, see the {Adapter} and {Router} classes.
|
141
|
+
#
|
142
|
+
# == Rack Middleware
|
143
|
+
# If you want to use the YARD server as a Rack middleware, see the documentation
|
144
|
+
# in {RackMiddleware}.
|
145
|
+
#
|
138
146
|
# @since 0.6.0
|
139
147
|
module Server
|
140
148
|
require __p('server')
|
141
149
|
|
150
|
+
# Commands implement specific kinds of server responses which are routed
|
151
|
+
# to by the {Router} class. To implement a custom command, subclass {Commands::Base}.
|
142
152
|
module Commands
|
143
153
|
autoload :Base, __p('server/commands/base')
|
144
154
|
autoload :DisplayFileCommand, __p('server/commands/display_file_command')
|
data/lib/yard/cli/yri.rb
CHANGED
@@ -49,7 +49,7 @@ module YARD
|
|
49
49
|
def run(*args)
|
50
50
|
optparse(*args)
|
51
51
|
|
52
|
-
if Config::CONFIG['host_os'] =~ /mingw|win32/
|
52
|
+
if ::Config::CONFIG['host_os'] =~ /mingw|win32/
|
53
53
|
@serializer ||= YARD::Serializers::StdoutSerializer.new
|
54
54
|
else
|
55
55
|
@serializer ||= YARD::Serializers::ProcessSerializer.new('less')
|
@@ -190,4 +190,4 @@ module YARD
|
|
190
190
|
end
|
191
191
|
end
|
192
192
|
end
|
193
|
-
end
|
193
|
+
end
|
@@ -45,6 +45,7 @@ module YARD::CodeObjects
|
|
45
45
|
def scope=(v)
|
46
46
|
reregister = @scope ? true : false
|
47
47
|
YARD::Registry.delete(self) if reregister
|
48
|
+
@path = nil
|
48
49
|
@scope = v.to_sym
|
49
50
|
YARD::Registry.register(self) if reregister
|
50
51
|
end
|
@@ -124,7 +125,7 @@ module YARD::CodeObjects
|
|
124
125
|
# (they should still have a separator as a prefix).
|
125
126
|
# @return [String] the path of a method
|
126
127
|
def path
|
127
|
-
if !namespace || namespace.path == ""
|
128
|
+
@path ||= if !namespace || namespace.path == ""
|
128
129
|
sep + super
|
129
130
|
else
|
130
131
|
super
|
@@ -3,8 +3,8 @@ module YARD
|
|
3
3
|
# Represents the root namespace object (the invisible Ruby module that
|
4
4
|
# holds all top level modules, class and other objects).
|
5
5
|
class RootObject < ModuleObject
|
6
|
-
def path; "" end
|
7
|
-
def inspect; "#<yardoc root>" end
|
6
|
+
def path; @path ||= "" end
|
7
|
+
def inspect; @inspect ||= "#<yardoc root>" end
|
8
8
|
def root?; true end
|
9
9
|
def equal?(other)
|
10
10
|
other == :root ? true : super(other)
|
@@ -27,6 +27,7 @@ module YARD
|
|
27
27
|
@source = source
|
28
28
|
@tokens = []
|
29
29
|
@comments = {}
|
30
|
+
@heredoc_tokens = []
|
30
31
|
@map = {}
|
31
32
|
@ns_charno = 0
|
32
33
|
@list = []
|
@@ -88,6 +89,7 @@ module YARD
|
|
88
89
|
:string_literal => [:tstring_beg, :heredoc_beg],
|
89
90
|
:super => "super",
|
90
91
|
:symbol => :symbeg,
|
92
|
+
:top_const_ref => "::",
|
91
93
|
:undef => "undef",
|
92
94
|
:unless => "unless",
|
93
95
|
:until => "until",
|
@@ -218,8 +220,13 @@ module YARD
|
|
218
220
|
def add_token(token, data)
|
219
221
|
if @tokens.last && @tokens.last[0] == :symbeg
|
220
222
|
@tokens[-1] = [:symbol, ":" + data]
|
223
|
+
elsif token == :heredoc_end
|
224
|
+
@heredoc_tokens << [@tokens.pop, [token, data]]
|
221
225
|
else
|
222
226
|
@tokens << [token, data]
|
227
|
+
if token == :nl && @heredoc_tokens.size > 0
|
228
|
+
@tokens += @heredoc_tokens.pop
|
229
|
+
end
|
223
230
|
end
|
224
231
|
end
|
225
232
|
|
@@ -281,6 +288,23 @@ module YARD
|
|
281
288
|
visit_ns_token(:rbracket, tok, false)
|
282
289
|
end
|
283
290
|
|
291
|
+
def on_top_const_ref(*args)
|
292
|
+
type = :top_const_ref
|
293
|
+
node = AstNode.node_class_for(type).new(type, args)
|
294
|
+
mapping = @map[MAPPINGS[type]]
|
295
|
+
extra_op = mapping.last[1] + 2 == charno ? mapping.pop : nil
|
296
|
+
lstart, sstart = *mapping.pop
|
297
|
+
node.source_range = Range.new(sstart, args.last.source_range.last)
|
298
|
+
node.line_range = Range.new(lstart, args.last.line_range.last)
|
299
|
+
mapping.push(extra_op) if extra_op
|
300
|
+
node
|
301
|
+
end
|
302
|
+
|
303
|
+
def on_const_path_ref(*args)
|
304
|
+
klass = AstNode.node_class_for(:const_path_ref)
|
305
|
+
klass.new(:const_path_ref, args, listline: lineno..lineno, listchar: charno..charno)
|
306
|
+
end
|
307
|
+
|
284
308
|
[:if_mod, :unless_mod, :while_mod].each do |kw|
|
285
309
|
node_class = AstNode.node_class_for(kw)
|
286
310
|
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
@@ -298,7 +322,12 @@ module YARD
|
|
298
322
|
end
|
299
323
|
|
300
324
|
def on_string_literal(*args)
|
301
|
-
visit_event_arr
|
325
|
+
node = visit_event_arr(AstNode.new(:string_literal, args))
|
326
|
+
if @source[charno, 1] !~ /["']/
|
327
|
+
nsr = node.source_range
|
328
|
+
node.source_range = Range.new(nsr.first, nsr.last + 1)
|
329
|
+
end
|
330
|
+
node
|
302
331
|
end
|
303
332
|
|
304
333
|
def on_lambda(*args)
|
data/lib/yard/server/adapter.rb
CHANGED
@@ -1,30 +1,73 @@
|
|
1
1
|
module YARD
|
2
2
|
module Server
|
3
|
+
|
4
|
+
# Short circuits a request by raising an error. This exception is caught
|
5
|
+
# by {Commands::Base#call} to immedaitely end a request and return a response.
|
3
6
|
class FinishRequest < RuntimeError; end
|
7
|
+
|
8
|
+
# Raises an error if a resource is not found. This exception is caught by
|
9
|
+
# {Commands::Base#call} to immediately end a request and return a 404 response
|
10
|
+
# code. If a message is provided, the body is set to the exception message.
|
4
11
|
class NotFoundError < RuntimeError; end
|
5
12
|
|
13
|
+
# This class implements the bridge between the {Router} and the server
|
14
|
+
# backend for a specific server type. YARD implements concrete adapters
|
15
|
+
# for WEBrick and Rack respectively, though other adapters can be made
|
16
|
+
# for other server architectures.
|
17
|
+
#
|
18
|
+
# == Subclassing Notes
|
19
|
+
# To create a concrete adapter class, implement the {#start} method to
|
20
|
+
# initiate the server backend.
|
21
|
+
#
|
22
|
+
# @abstract
|
6
23
|
class Adapter
|
7
|
-
# @return [String] the location where static files are located, if any
|
24
|
+
# @return [String] the location where static files are located, if any.
|
25
|
+
# To set this field on initialization, pass +:DocumentRoot+ to the
|
26
|
+
# +server_opts+ argument in {#initialize}
|
8
27
|
attr_accessor :document_root
|
9
28
|
|
29
|
+
# @return [Hash{String=>Array<LibraryVersion>}] a map of libraries.
|
30
|
+
# @see LibraryVersion LibraryVersion for information on building a list of libraries
|
31
|
+
# @see #add_library
|
10
32
|
attr_accessor :libraries
|
11
33
|
|
34
|
+
# @return [Hash] options passed and processed by adapters. The actual
|
35
|
+
# options mostly depend on the adapters themselves.
|
12
36
|
attr_accessor :options
|
13
37
|
|
38
|
+
# @return [Hash] a set of options to pass to the server backend. Note
|
39
|
+
# that +:DocumentRoot+ also sets the {#document_root}.
|
14
40
|
attr_accessor :server_options
|
15
41
|
|
42
|
+
# @return [Router] the router object used to route URLs to commands
|
16
43
|
attr_accessor :router
|
17
44
|
|
45
|
+
# Performs any global initialization for the adapter.
|
46
|
+
# @note If you subclass this method, make sure to call +super+.
|
47
|
+
# @return [void]
|
18
48
|
def self.setup
|
19
49
|
Templates::Template.extra_includes |= [YARD::Server::DocServerHelper]
|
20
50
|
Templates::Engine.template_paths |= [File.dirname(__FILE__) + '/templates']
|
21
51
|
end
|
22
52
|
|
53
|
+
# Performs any global shutdown procedures for the adapter.
|
54
|
+
# @note If you subclass this method, make sure to call +super+.
|
55
|
+
# @return [void]
|
23
56
|
def self.shutdown
|
24
57
|
Templates::Template.extra_includes -= [YARD::Server::DocServerHelper]
|
25
58
|
Templates::Engine.template_paths -= [File.dirname(__FILE__) + '/templates']
|
26
59
|
end
|
27
60
|
|
61
|
+
# Creates a new adapter object
|
62
|
+
#
|
63
|
+
# @param [Hash{String=>Array<LibraryVersion>}] libs a list of libraries,
|
64
|
+
# see {#libraries} for formulating this list.
|
65
|
+
# @param [Hash] opts extra options to pass to the adapter
|
66
|
+
# @option opts [Class] :router (Router) the router class to initialize as the
|
67
|
+
# adapter's router.
|
68
|
+
# @option opts [Boolean] :caching (false) whether or not caching is enabled
|
69
|
+
# @option opts [Boolean] :single_library (false) whether to server documentation
|
70
|
+
# for a single or multiple libraries (changes URL structure)
|
28
71
|
def initialize(libs, opts = {}, server_opts = {})
|
29
72
|
self.class.setup
|
30
73
|
self.libraries = libs
|
@@ -38,11 +81,17 @@ module YARD
|
|
38
81
|
log.debug "Document root: #{document_root}" if document_root
|
39
82
|
end
|
40
83
|
|
84
|
+
# Adds a library to the {#libraries} mapping for a given library object.
|
85
|
+
# @example Adding a new library to an adapter
|
86
|
+
# adapter.add_library LibraryVersion.new('mylib', '1.0', '/path/to/.yardoc')
|
87
|
+
# @param [LibraryVersion] library a library to add
|
41
88
|
def add_library(library)
|
42
89
|
libraries[library.name] ||= []
|
43
90
|
libraries[library.name] |= [library]
|
44
91
|
end
|
45
92
|
|
93
|
+
# Implement this method to connect your adapter to your server.
|
94
|
+
# @abstract
|
46
95
|
def start
|
47
96
|
raise NotImplementedError
|
48
97
|
end
|
@@ -3,10 +3,47 @@ require 'fileutils'
|
|
3
3
|
module YARD
|
4
4
|
module Server
|
5
5
|
module Commands
|
6
|
+
# This is the base command class used to implement custom commands for
|
7
|
+
# a server. A command will be routed to by the {Router} class and return
|
8
|
+
# a Rack-style response.
|
9
|
+
#
|
10
|
+
# == Attribute Initializers
|
11
|
+
# All attributes can be initialized via options passed into the {#initialize}
|
12
|
+
# method. When creating a custom command, the {Adapter#options} will
|
13
|
+
# automatically be mapped to attributes by the same name on your class.
|
14
|
+
#
|
15
|
+
# class MyCommand < Base
|
16
|
+
# attr_accessor :myattr
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Adapter.new(libs, {:myattr => 'foo'}).start
|
20
|
+
#
|
21
|
+
# # when a request comes in, cmd.myattr == 'foo'
|
22
|
+
#
|
23
|
+
# == Subclassing Notes
|
24
|
+
# To implement a custom command, override the {#run} method, not {#call}.
|
25
|
+
# In your implementation, you should set the body and status for requests.
|
26
|
+
# See details in the +#run+ method documentation.
|
27
|
+
#
|
28
|
+
# Note that if your command deals directly with libraries, you should
|
29
|
+
# consider subclassing the more specific {LibraryCommand} class instead.
|
30
|
+
#
|
31
|
+
# @abstract
|
32
|
+
# @see #run
|
6
33
|
class Base
|
34
|
+
# @group Basic Command and Adapter Options
|
35
|
+
|
7
36
|
# @return [Hash] the options passed to the command's constructor
|
8
37
|
attr_accessor :command_options
|
9
38
|
|
39
|
+
# @return [Adapter] the server adapter
|
40
|
+
attr_accessor :adapter
|
41
|
+
|
42
|
+
# @return [Boolean] whether to cache
|
43
|
+
attr_accessor :caching
|
44
|
+
|
45
|
+
# @group Attributes Set Per Request
|
46
|
+
|
10
47
|
# @return [Request] request object
|
11
48
|
attr_accessor :request
|
12
49
|
|
@@ -16,18 +53,24 @@ module YARD
|
|
16
53
|
# @return [Hash{String => String}] response headers
|
17
54
|
attr_accessor :headers
|
18
55
|
|
19
|
-
# @return [Numeric] status code
|
56
|
+
# @return [Numeric] status code. Defaults to 200 per request
|
20
57
|
attr_accessor :status
|
21
58
|
|
22
|
-
# @return [String] the response body
|
59
|
+
# @return [String] the response body. Defaults to empty string.
|
23
60
|
attr_accessor :body
|
24
61
|
|
25
|
-
# @
|
26
|
-
attr_accessor :adapter
|
27
|
-
|
28
|
-
# @return [Boolean] whether to cache
|
29
|
-
attr_accessor :caching
|
62
|
+
# @group Instance Method Summary
|
30
63
|
|
64
|
+
# Creates a new command object, setting attributes named by keys
|
65
|
+
# in the options hash. After initialization, the options hash
|
66
|
+
# is saved in {#command_options} for further inspection.
|
67
|
+
#
|
68
|
+
# @example Creating a Command
|
69
|
+
# cmd = DisplayObjectCommand.new(:caching => true, :library => mylib)
|
70
|
+
# cmd.library # => mylib
|
71
|
+
# cmd.command_options # => {:caching => true, :library => mylib}
|
72
|
+
# @param [Hash] opts the options hash, saved to {#command_options}
|
73
|
+
# after initialization.
|
31
74
|
def initialize(opts = {})
|
32
75
|
opts.each do |key, value|
|
33
76
|
send("#{key}=", value) if respond_to?("#{key}=")
|
@@ -35,6 +78,13 @@ module YARD
|
|
35
78
|
self.command_options = opts
|
36
79
|
end
|
37
80
|
|
81
|
+
# The main method called by a router with a request object.
|
82
|
+
#
|
83
|
+
# @note This command should not be overridden by subclasses. Implement
|
84
|
+
# the callback method {#run} instead.
|
85
|
+
# @param [Adapter Dependent] request the request object
|
86
|
+
# @return [Array(Number,Hash,Array<String>)] a Rack-style response
|
87
|
+
# of status, headers, and body wrapped in an array.
|
38
88
|
def call(request)
|
39
89
|
self.request = request
|
40
90
|
self.path ||= request.path[1..-1]
|
@@ -51,20 +101,61 @@ module YARD
|
|
51
101
|
not_found if status == 404
|
52
102
|
[status, headers, body.is_a?(Array) ? body : [body]]
|
53
103
|
end
|
104
|
+
|
105
|
+
# @group Abstract Methods
|
54
106
|
|
107
|
+
# Subclass this method to implement a custom command. This method
|
108
|
+
# should set the {#status} and {#body}, and optionally modify the
|
109
|
+
# {#headers}. Note that +#status+ defaults to 200.
|
110
|
+
#
|
111
|
+
# @example A custom command
|
112
|
+
# class ErrorCommand < Base
|
113
|
+
# def run
|
114
|
+
# self.body = 'ERROR! The System is down!'
|
115
|
+
# self.status = 500
|
116
|
+
# self.headers['Conten-Type'] = 'text/plain'
|
117
|
+
# end
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# @abstract
|
121
|
+
# @return [void]
|
55
122
|
def run
|
56
123
|
raise NotImplementedError
|
57
124
|
end
|
125
|
+
|
126
|
+
protected
|
58
127
|
|
59
|
-
|
60
|
-
return unless body.empty?
|
61
|
-
self.body = "Not found: #{request.path}"
|
62
|
-
self.headers['Content-Type'] = 'text/plain'
|
63
|
-
self.headers['X-Cascade'] = 'pass'
|
64
|
-
end
|
128
|
+
# @group Helper Methods
|
65
129
|
|
66
|
-
|
130
|
+
# Renders a specific object if provided, or a regular template rendering
|
131
|
+
# if object is not provided.
|
132
|
+
#
|
133
|
+
# @todo This method is dependent on +#options+, it should be in {LibraryCommand}.
|
134
|
+
# @param [CodeObjects::Base, nil] object calls {CodeObjects::Base#format} if
|
135
|
+
# an object is provided, or {Templates::Engine.render} if object is nil. Both
|
136
|
+
# receive +#options+ as an argument.
|
137
|
+
# @return [String] the resulting output to display
|
138
|
+
def render(object = nil)
|
139
|
+
case object
|
140
|
+
when CodeObjects::Base
|
141
|
+
cache object.format(options)
|
142
|
+
when nil
|
143
|
+
cache Templates::Engine.render(options)
|
144
|
+
else
|
145
|
+
cache object
|
146
|
+
end
|
147
|
+
end
|
67
148
|
|
149
|
+
# Override this method to implement custom caching mechanisms for
|
150
|
+
#
|
151
|
+
# @example Caching to memory
|
152
|
+
# $memory_cache = {}
|
153
|
+
# def cache(data)
|
154
|
+
# $memory_cache[path] = data
|
155
|
+
# end
|
156
|
+
# @param [String] data the data to cache
|
157
|
+
# @return [String] the same cached data (for chaining)
|
158
|
+
# @see StaticCaching
|
68
159
|
def cache(data)
|
69
160
|
if caching && adapter.document_root
|
70
161
|
path = File.join(adapter.document_root, request.path.sub(/\.html$/, '') + '.html')
|
@@ -76,17 +167,20 @@ module YARD
|
|
76
167
|
self.body = data
|
77
168
|
end
|
78
169
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
170
|
+
# Sets the body and headers (but not status) for a 404 response. Does
|
171
|
+
# nothing if the body is already set.
|
172
|
+
#
|
173
|
+
# @return [void]
|
174
|
+
def not_found
|
175
|
+
return unless body.empty?
|
176
|
+
self.body = "Not found: #{request.path}"
|
177
|
+
self.headers['Content-Type'] = 'text/plain'
|
178
|
+
self.headers['X-Cascade'] = 'pass'
|
88
179
|
end
|
89
180
|
|
181
|
+
# Sets the headers and status code for a redirection to a given URL
|
182
|
+
# @param [String] url the URL to redirect to
|
183
|
+
# @raise [FinishRequest] causes the request to terminate.
|
90
184
|
def redirect(url)
|
91
185
|
headers['Location'] = url
|
92
186
|
self.status = 302
|