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.

Files changed (46) hide show
  1. data/ChangeLog +119 -0
  2. data/README.md +16 -2
  3. data/Rakefile +29 -10
  4. data/docs/GettingStarted.md +186 -35
  5. data/lib/yard.rb +1 -1
  6. data/lib/yard/autoload.rb +10 -0
  7. data/lib/yard/cli/yri.rb +2 -2
  8. data/lib/yard/code_objects/base.rb +1 -1
  9. data/lib/yard/code_objects/method_object.rb +2 -1
  10. data/lib/yard/code_objects/root_object.rb +2 -2
  11. data/lib/yard/parser/ruby/ast_node.rb +0 -4
  12. data/lib/yard/parser/ruby/ruby_parser.rb +30 -1
  13. data/lib/yard/server/adapter.rb +50 -1
  14. data/lib/yard/server/commands/base.rb +117 -23
  15. data/lib/yard/server/commands/display_file_command.rb +3 -0
  16. data/lib/yard/server/commands/display_object_command.rb +1 -0
  17. data/lib/yard/server/commands/frames_command.rb +1 -0
  18. data/lib/yard/server/commands/library_command.rb +8 -1
  19. data/lib/yard/server/commands/list_command.rb +4 -0
  20. data/lib/yard/server/doc_server_helper.rb +15 -0
  21. data/lib/yard/server/doc_server_serializer.rb +2 -0
  22. data/lib/yard/server/library_version.rb +141 -0
  23. data/lib/yard/server/rack_adapter.rb +35 -2
  24. data/lib/yard/server/router.rb +71 -1
  25. data/lib/yard/server/static_caching.rb +29 -0
  26. data/lib/yard/server/webrick_adapter.rb +4 -0
  27. data/lib/yard/templates/engine.rb +1 -1
  28. data/lib/yard/templates/helpers/markup_helper.rb +22 -7
  29. data/spec/cli/diff_spec.rb +2 -2
  30. data/spec/cli/stats_spec.rb +1 -1
  31. data/spec/cli/yardoc_spec.rb +1 -1
  32. data/spec/cli/yri_spec.rb +21 -0
  33. data/spec/handlers/class_handler_spec.rb +1 -0
  34. data/spec/handlers/examples/class_handler_001.rb.txt +1 -0
  35. data/spec/parser/ruby/legacy/statement_list_spec.rb +6 -0
  36. data/spec/parser/ruby/ruby_parser_spec.rb +29 -0
  37. data/spec/server/rack_adapter_spec.rb +18 -0
  38. data/spec/spec_helper.rb +6 -2
  39. data/spec/templates/engine_spec.rb +4 -1
  40. data/spec/templates/helpers/html_helper_spec.rb +11 -0
  41. data/spec/templates/helpers/markup_helper_spec.rb +9 -5
  42. data/spec/templates/module_spec.rb +1 -1
  43. data/spec/templates/spec_helper.rb +3 -3
  44. data/templates/default/fulldoc/html/css/style.css +1 -1
  45. data/templates/default/fulldoc/html/js/app.js +3 -2
  46. metadata +7 -15
@@ -1,5 +1,5 @@
1
1
  module YARD
2
- VERSION = "0.6.3"
2
+ VERSION = "0.6.4"
3
3
 
4
4
  # The root path for YARD source libraries
5
5
  ROOT = File.expand_path(File.dirname(__FILE__))
@@ -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')
@@ -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
@@ -388,7 +388,7 @@ module YARD
388
388
  # @return [String] the unique path of the object
389
389
  # @see #sep
390
390
  def path
391
- if parent && !parent.root?
391
+ @path ||= if parent && !parent.root?
392
392
  [parent.path, name.to_s].join(sep)
393
393
  else
394
394
  name.to_s
@@ -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)
@@ -321,10 +321,6 @@ module YARD
321
321
  def namespace
322
322
  Array.new flatten[0...-1]
323
323
  end
324
-
325
- def source
326
- super.split(/\s+/).first
327
- end
328
324
  end
329
325
 
330
326
  class ParameterNode < AstNode
@@ -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 AstNode.new(:string_literal, args)
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)
@@ -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
- # @return [Adapter] the server adapter
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
- def not_found
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
- protected
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
- def render(object = nil)
80
- case object
81
- when CodeObjects::Base
82
- cache object.format(options)
83
- when nil
84
- cache Templates::Engine.render(options)
85
- else
86
- cache object
87
- end
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
@@ -1,6 +1,9 @@
1
1
  module YARD
2
2
  module Server
3
3
  module Commands
4
+ # Displays a README or extra file.
5
+ #
6
+ # @todo Implement better support for detecting binary (image) filetypes
4
7
  class DisplayFileCommand < LibraryCommand
5
8
  def run
6
9
  ppath = library.source_path