yard-api 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/LICENSE +674 -0
  4. data/README.md +27 -0
  5. data/lib/yard-api/markup/redcarpet.rb +42 -0
  6. data/lib/yard-api/options.rb +13 -0
  7. data/lib/yard-api/railtie.rb +11 -0
  8. data/lib/yard-api/tags.rb +16 -0
  9. data/lib/yard-api/templates/helpers/base_helper.rb +108 -0
  10. data/lib/yard-api/templates/helpers/html_helper.rb +87 -0
  11. data/lib/yard-api/templates/helpers/route_helper.rb +19 -0
  12. data/lib/yard-api/verifier.rb +34 -0
  13. data/lib/yard-api/version.rb +5 -0
  14. data/lib/yard-api/yardoc_task.rb +78 -0
  15. data/lib/yard-api.rb +48 -0
  16. data/spec/spec_helper.rb +44 -0
  17. data/tasks/yard_api.rake +13 -0
  18. data/templates/api/appendix/html/setup.rb +19 -0
  19. data/templates/api/docstring/html/setup.rb +3 -0
  20. data/templates/api/docstring/html/text.erb +6 -0
  21. data/templates/api/fulldoc/html/setup.rb +78 -0
  22. data/templates/api/layout/html/footer.erb +11 -0
  23. data/templates/api/layout/html/headers.erb +19 -0
  24. data/templates/api/layout/html/layout.erb +17 -0
  25. data/templates/api/layout/html/scripts.erb +35 -0
  26. data/templates/api/layout/html/setup.rb +63 -0
  27. data/templates/api/layout/html/sidebar.erb +29 -0
  28. data/templates/api/method_details/html/header.erb +12 -0
  29. data/templates/api/method_details/html/method_signature.erb +19 -0
  30. data/templates/api/method_details/html/setup.rb +35 -0
  31. data/templates/api/tags/html/_example_code_block.erb +8 -0
  32. data/templates/api/tags/html/argument.erb +32 -0
  33. data/templates/api/tags/html/emits.erb +7 -0
  34. data/templates/api/tags/html/example_request.erb +13 -0
  35. data/templates/api/tags/html/example_response.erb +14 -0
  36. data/templates/api/tags/html/generic_tag.erb +20 -0
  37. data/templates/api/tags/html/index.erb +3 -0
  38. data/templates/api/tags/html/no_content.erb +3 -0
  39. data/templates/api/tags/html/note.erb +6 -0
  40. data/templates/api/tags/html/returns.erb +10 -0
  41. data/templates/api/tags/html/see.erb +8 -0
  42. data/templates/api/tags/html/throws.erb +49 -0
  43. data/templates/api/tags/html/warning.erb +6 -0
  44. data/templates/api/tags/setup.rb +83 -0
  45. data/templates/api/topic/html/header.erb +7 -0
  46. data/templates/api/topic/html/method_details_list.erb +5 -0
  47. data/templates/api/topic/html/setup.rb +58 -0
  48. data/templates/api/topic/html/topic_doc.erb +27 -0
  49. data/yard-api.gemspec +22 -0
  50. metadata +149 -0
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # yard-api
2
+
3
+ [![Build Status](https://travis-ci.org/amireh/yard-api.png)](https://travis-ci.org/amireh/yard-api)
4
+
5
+ TODO
6
+
7
+ ## Usage
8
+
9
+ TODO
10
+
11
+ ## Notes
12
+
13
+ - can only document classes and class methods; modules, root objects, and constants are ignored
14
+
15
+ ## Changelog
16
+
17
+ **10/9/2014**
18
+
19
+ - Support for github-flavored markdown when you're using Markdown as a markup, and `redcarpet` as the provider
20
+ - Syntax highlighting for multiple languages (with auto-detection) using [highlight.js](https://highlightjs.org/)
21
+ - `@example_response` and `@example_request` tags now support a title for the response
22
+ - A new option: `copyright` for displaying a copyright in the footer of every page
23
+ - A new option: `footer_note` for displaying a custom note, like linking to the project's source code, in the footer of every page
24
+
25
+ ## License
26
+
27
+ Released under the [AGPLv3](http://www.gnu.org/licenses/agpl-3.0.html) license.
@@ -0,0 +1,42 @@
1
+ require 'redcarpet'
2
+ require 'yard/templates/helpers/markup_helper'
3
+
4
+ module YARD::APIPlugin::Markup
5
+ # TODO: make this configurable
6
+ class RedcarpetDelegate
7
+ Extensions = {
8
+ no_intra_emphasis: true,
9
+ fenced_code_blocks: true,
10
+ autolink: true,
11
+ tables: true,
12
+ lax_spacing: false,
13
+ space_after_headers: true,
14
+ underline: true,
15
+ highlight: true,
16
+ footnotes: true
17
+ }.freeze
18
+
19
+ RendererOptions = {
20
+ }.freeze
21
+
22
+ def initialize(text, extensions_and_options=nil)
23
+ @renderer = Redcarpet::Render::HTML.new(RendererOptions)
24
+ @markdown = Redcarpet::Markdown.new(@renderer, Extensions)
25
+ @text = text
26
+ end
27
+
28
+ def to_html
29
+ @markdown.render(@text)
30
+ end
31
+ end
32
+ end
33
+
34
+ module YARD::Templates::Helpers
35
+ if MarkupHelper.markup_cache.nil?
36
+ MarkupHelper.clear_markup_cache
37
+ end
38
+
39
+ MarkupHelper.markup_cache[:markdown] ||= {}
40
+ MarkupHelper.markup_cache[:markdown][:class] = YARD::APIPlugin::Markup::RedcarpetDelegate
41
+ end
42
+
@@ -0,0 +1,13 @@
1
+ module YARD::APIPlugin
2
+ class Options < YARD::Options
3
+ default_attr :title, 'Rails API Project'
4
+ default_attr :static, []
5
+ default_attr :files, []
6
+ default_attr :route_namespace, ''
7
+
8
+ default_attr :footer_copyright, nil
9
+ default_attr :footer_note, nil
10
+
11
+ attr_accessor :readme
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'rails'
2
+
3
+ module YARD::APIPlugin
4
+ class Railtie < ::Rails::Railtie
5
+ railtie_name :yard_api
6
+
7
+ rake_tasks do
8
+ load File.join(YARD::APIPlugin::TASK_PATH, 'yard_api.rake')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ YARD::Tags::Library.define_tag("API endpiont", :API)
2
+ YARD::Tags::Library.define_tag("API endpiont argument", :argument)
3
+ YARD::Tags::Library.define_tag("API response field", :request_field)
4
+ YARD::Tags::Library.define_tag("API response field", :response_field)
5
+ YARD::Tags::Library.define_tag("API example request", :example_request, :with_title_and_text)
6
+ YARD::Tags::Library.define_tag("API example response", :example_response, :with_title_and_text)
7
+ YARD::Tags::Library.define_tag("API subtopic", :subtopic)
8
+ YARD::Tags::Library.define_tag("API Object Definition", :object)
9
+ YARD::Tags::Library.define_tag("API Return Type", :returns)
10
+ YARD::Tags::Library.define_tag("API resource is beta", :beta)
11
+ YARD::Tags::Library.define_tag("API resource is internal", :internal)
12
+ YARD::Tags::Library.define_tag("API empty response", :no_content)
13
+ YARD::Tags::Library.define_tag("API error", :throws)
14
+ YARD::Tags::Library.define_tag("API warning", :warning)
15
+ YARD::Tags::Library.define_tag("API note", :note)
16
+ YARD::Tags::Library.define_tag("API message", :emits)
@@ -0,0 +1,108 @@
1
+ require 'yard/templates/helpers/base_helper'
2
+
3
+ module YARD::Templates::Helpers::BaseHelper
4
+ def api_options()
5
+ YARD::APIPlugin.options
6
+ end
7
+
8
+ def linkify_with_api(*args)
9
+ # References to controller actions
10
+ #
11
+ # Syntax: api:ControllerName#method_name [TITLE OVERRIDE]
12
+ #
13
+ # @example Explicit reference with title defaulting to the action
14
+ # # @see api:Assignments#create
15
+ # # => <a href="assignments.html#method.assignments_api.create">create</a>
16
+ #
17
+ # @example Inline reference with an overriden title
18
+ # # Here's a link to absolute {api:Assignments#destroy destruction}
19
+ # # => <a href="assignments.html#method.assignments_api.destroy">destruction</a>
20
+ #
21
+ # @note Action links inside the All Resources section will be relative.
22
+ if args.first.is_a?(String) && args.first =~ %r{^api:([^#]+)#(.*)}
23
+ topic, controller = *lookup_topic($1.to_s)
24
+ if topic
25
+ html_file = "#{topicize topic.first}.html"
26
+ action = $2
27
+ link_url("#{html_file}#method.#{topicize(controller.name.to_s).sub("_controller", "")}.#{action}", args[1])
28
+ else
29
+ raise "couldn't find API link for #{args.first}"
30
+ end
31
+
32
+ # References to API objects defined by @object
33
+ #
34
+ # Syntax: api:ControllerName:Object+Name [TITLE OVERRIDE]
35
+ #
36
+ # @example Explicit resource reference with title defaulting to its name
37
+ # # @see api:Assignments:Assignment
38
+ # # => <a href="assignments.html#Assignment">Assignment</a>
39
+ #
40
+ # @example Explicit resource reference with an overriden title
41
+ # # @return api:Assignments:AssignmentOverride An Assignment Override
42
+ # # => <a href="assignments.html#Assignment">An Assignment Override</a>
43
+ elsif args.first.is_a?(String) && args.first =~ %r{^api:([^:]+):(.*)}
44
+ scope_name, resource_name = $1.downcase, $2.gsub('+', ' ')
45
+ link_url("#{scope_name}.html##{resource_name}", args[1] || resource_name)
46
+ elsif args.first.is_a?(String) && args.first == 'Appendix:' && args.size > 1
47
+ __errmsg = "unable to locate referenced appendix '#{args[1]}'"
48
+
49
+ unless appendix = lookup_appendix(args[1].to_s)
50
+ raise __errmsg
51
+ end
52
+
53
+ topic, controller = *lookup_topic(appendix.namespace.to_s)
54
+
55
+ if topic
56
+ html_file = "#{topicize topic.first}.html"
57
+ bookmark = "#{appendix.name.to_s.gsub(' ', '+')}-appendix"
58
+ ret = link_url("#{html_file}##{bookmark}", appendix.title)
59
+ else
60
+ raise __errmsg
61
+ end
62
+
63
+ # A non-API link, delegate to YARD's HTML linker
64
+ else
65
+ linkify_without_api(*args)
66
+ end
67
+ end
68
+
69
+ alias_method :linkify_without_api, :linkify
70
+ alias_method :linkify, :linkify_with_api
71
+
72
+ def lookup_topic(controller_name)
73
+ controller = nil
74
+ topic = options[:resources].find { |r,cs|
75
+ cs.any? { |c|
76
+ controller = c if c.name.to_s == controller_name
77
+ !controller.nil?
78
+ }
79
+ }
80
+
81
+ [ topic, controller ]
82
+ end
83
+
84
+ def lookup_appendix(title)
85
+ appendix = nil
86
+
87
+ puts "looking up appendix: #{title}"
88
+
89
+ if object
90
+ # try in the object scope
91
+ appendix = YARD::Registry.at(".appendix.#{object.path}.#{title}")
92
+
93
+ # try in the object's namespace scope
94
+ if appendix.nil? && object.respond_to?(:namespace)
95
+ appendix = YARD::Registry.at(".appendix.#{object.namespace.path}.#{title}")
96
+ end
97
+ end
98
+
99
+ appendix
100
+ end
101
+
102
+ def tag_partial(name, tag)
103
+ options[:tag] = tag
104
+ out = erb(name)
105
+ options.delete(:tag)
106
+ out
107
+ end
108
+ end
@@ -0,0 +1,87 @@
1
+ require 'yard/templates/helpers/html_helper'
2
+
3
+ module YARD::Templates::Helpers::HtmlHelper
4
+ def topicize(str)
5
+ str.gsub(' ', '_').underscore
6
+ end
7
+
8
+ def url_for_file(filename, anchor = nil)
9
+ link = filename.filename
10
+ link += (anchor ? '#' + urlencode(anchor) : '')
11
+ link
12
+ end
13
+
14
+ def static_pages()
15
+ options = YARD::APIPlugin.options
16
+
17
+ paths = Array(options.static).map do |entry|
18
+ pages = if entry.is_a?(Hash)
19
+ glob = entry['glob']
20
+ blacklist = Array(entry['exclude'])
21
+
22
+ unless glob
23
+ raise "Invalid static page entry, expected Hash to contain a 'glob' parameter: #{entry}"
24
+ end
25
+
26
+ pages = Dir.glob(entry['glob'])
27
+
28
+ if blacklist.any?
29
+ pages.delete_if { |p| blacklist.any? { |filter| p.match(filter) } }
30
+ end
31
+
32
+ pages
33
+ elsif entry.is_a?(Array)
34
+ entry.map(&:to_s)
35
+ elsif entry.is_a?(String)
36
+ [ entry ]
37
+ end
38
+ end.flatten.compact
39
+
40
+ markdown_exts = YARD::Templates::Helpers::MarkupHelper::MARKUP_EXTENSIONS[:markdown]
41
+ readme_page = options.readme
42
+ pages = Dir.glob(paths)
43
+
44
+ if readme_page.present?
45
+ pages.delete_if { |page| page.match(readme_page) }
46
+ end
47
+
48
+ pages.map do |page|
49
+ filename = 'file.' + File.split(page).last.sub(/\..*$/, '.html')
50
+
51
+ # extract page title if it's a markdown document; title is expected to
52
+ # be an h1 on the very first line:
53
+ title = if markdown_exts.include?(File.extname(page).sub('.', ''))
54
+ (File.open(page, &:gets) || '').strip.sub('# ', '')
55
+ else
56
+ # otherwise we'll just sanitize the file name
57
+ File.basename(page).sub(/\.\w+$/, '').gsub(/\W/, ' ').gsub(/\s+/, ' ').capitalize
58
+ end
59
+
60
+ {
61
+ src: page,
62
+ filename: filename,
63
+ title: title
64
+ }
65
+ end
66
+ end
67
+
68
+ # override yard-appendix link_appendix
69
+ def link_appendix(ref)
70
+ __errmsg = "unable to locate referenced appendix '#{ref}'"
71
+
72
+ puts "looking up appendix: #{ref}"
73
+ unless appendix = lookup_appendix(ref.to_s)
74
+ raise __errmsg
75
+ end
76
+
77
+ topic, controller = *lookup_topic(appendix.namespace.to_s)
78
+
79
+ unless topic
80
+ raise __errmsg
81
+ end
82
+
83
+ html_file = "#{topicize topic.first}.html"
84
+ bookmark = "#{appendix.name.to_s.gsub(' ', '+')}-appendix"
85
+ link_url("#{html_file}##{bookmark}", appendix.title)
86
+ end
87
+ end
@@ -0,0 +1,19 @@
1
+ module YARD::Templates::Helpers
2
+ module RouteHelper
3
+ def self.routes_for(prefix)
4
+ Rails.application.routes.set
5
+ end
6
+
7
+ def self.matches_controller_and_action?(route, controller, action)
8
+ route.requirements[:controller] == controller &&
9
+ route.requirements[:action] == action
10
+ end
11
+
12
+ def self.api_methods_for_controller_and_action(controller, action)
13
+ @routes ||= self.routes_for('/')
14
+ controller_path = [ YARD::APIPlugin.options.route_namespace, controller ].join('/')
15
+ controller_path.gsub!(/^\/|_controller$/, '')
16
+ @routes.find_all { |r| matches_controller_and_action?(r, controller_path, action) }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ module YARD
2
+ module APIPlugin
3
+ class Verifier < ::YARD::Verifier
4
+ def initialize(verbose=false)
5
+ @verbose = verbose
6
+ super()
7
+ end
8
+
9
+ def run(list)
10
+ relevant = list.select { |o| relevant_object?(o) }
11
+
12
+ if @verbose && relevant.any?
13
+ puts "#{relevant.length}/#{list.length} objects are relevant:"
14
+ relevant.each do |object|
15
+ puts "\t- #{object.path}"
16
+ end
17
+ end
18
+
19
+ relevant
20
+ end
21
+
22
+ def relevant_object?(object)
23
+ case object.type
24
+ when :root, :module, :constant
25
+ false
26
+ when :method, :class
27
+ !object.tags('API').empty? && object.tags('internal').empty?
28
+ else
29
+ object.parent.nil? && relevant_object?(object.parent)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module YARD
2
+ module APIPlugin
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,78 @@
1
+ require 'fileutils'
2
+
3
+ module YARD::APIPlugin
4
+ class YardocTask < ::YARD::Rake::YardocTask
5
+ attr_reader :config
6
+
7
+ def initialize()
8
+ super(:yard_api, &:run)
9
+ end
10
+
11
+ def run
12
+ @config = load_config
13
+ t = self
14
+
15
+ YARD::APIPlugin.options.update(@config)
16
+
17
+ t.verifier = YARD::APIPlugin::Verifier.new(config['verbose'])
18
+ t.before = proc { FileUtils.rm_rf(config['output']) }
19
+ t.files = config['files']
20
+
21
+ config['debug'] ||= ENV['DEBUG']
22
+ config['verbose'] ||= ENV['VERBOSE']
23
+
24
+ set_option('template', 'api')
25
+ set_option('no-yardopts')
26
+ set_option('no-document')
27
+
28
+ set_option('markup', config['markup']) if config['markup']
29
+ set_option('markup-provider', config['markup_provider']) if config['markup_provider']
30
+
31
+ if config['markup_provider'] == 'redcarpet'
32
+ require 'yard-api/markup/redcarpet'
33
+ end
34
+
35
+ set_option('title', config['title'])
36
+ set_option('output-dir', config['output'])
37
+ set_option('readme', config['readme']) if File.exists?(config['readme'])
38
+ set_option('verbose') if config['verbose']
39
+ set_option('debug') if config['debug']
40
+
41
+ get_assets(config).each_pair do |asset_id, rpath|
42
+ asset_path = File.join(config['source'], rpath)
43
+
44
+ if File.directory?(asset_path)
45
+ set_option 'asset', [ asset_path, asset_id ].join(':')
46
+ elsif config['strict']
47
+ raise <<-Error
48
+ Expected assets of type "#{asset_id}" to be found within
49
+ "#{asset_path}", but they are not.
50
+ Error
51
+ end
52
+ end
53
+
54
+ if config['debug']
55
+ puts "Invoking YARD with options: #{self.options.to_json}"
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def load_config
62
+ path = Rails.root.join('config', 'yard_api.yml')
63
+
64
+ # load defaults
65
+ config = YAML.load_file(File.join(YARD::APIPlugin::CONFIG_PATH, 'yard_api.yml'))
66
+ config.merge!(YAML.load_file(path)) if File.exists?(path)
67
+ config
68
+ end
69
+
70
+ def set_option(k, *vals)
71
+ self.options.concat(["--#{k}", *vals])
72
+ end
73
+
74
+ def get_assets(config)
75
+ config['assets'] || {}
76
+ end
77
+ end
78
+ end
data/lib/yard-api.rb ADDED
@@ -0,0 +1,48 @@
1
+ # yard-api - a YARD plugin for generating API documentation in Rails.
2
+ #
3
+ # Copyright (C) 2014 Ahmad Amireh <ahmad@instructure.com>
4
+ # Copyright (C) 2011 Instructure, Inc.
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as
8
+ # published by the Free Software Foundation, either version 3 of the
9
+ # License, or (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
20
+
21
+ require 'yard'
22
+ require 'yard-appendix'
23
+
24
+ module YARD
25
+ module APIPlugin
26
+ ROOT = File.dirname(__FILE__)
27
+ CONFIG_PATH = File.join(%W[#{ROOT} .. config])
28
+ TEMPLATE_PATH = File.join(%W[#{ROOT} .. templates])
29
+ TASK_PATH = File.join(%W[#{ROOT} .. tasks])
30
+
31
+ def self.options
32
+ @@options ||= Options.new
33
+ end
34
+ end
35
+
36
+ require 'yard-api/version'
37
+ require 'yard-api/options'
38
+ require 'yard-api/tags'
39
+ require 'yard-api/verifier'
40
+ require 'yard-api/templates/helpers/base_helper'
41
+ require 'yard-api/templates/helpers/html_helper'
42
+ require 'yard-api/templates/helpers/route_helper'
43
+ require 'yard-api/railtie' if defined?(Rails)
44
+
45
+ module Templates
46
+ Engine.register_template_path YARD::APIPlugin::TEMPLATE_PATH
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # Copyright (c) 2013 Instructure, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a
5
+ # copy of this software and associated documentation files (the "Software"),
6
+ # to deal in the Software without restriction, including without limitation
7
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ # and/or sell copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ # SOFTWARE.
21
+ #
22
+
23
+ require 'yard'
24
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'yard-api')
25
+
26
+ # This file was generated by the `rspec --init` command. Conventionally, all
27
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
28
+ # Require this file using `require "spec_helper"` to ensure that it is only
29
+ # loaded once.
30
+ #
31
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
32
+ RSpec.configure do |config|
33
+ config.treat_symbols_as_metadata_keys_with_true_values = true
34
+ config.run_all_when_everything_filtered = true
35
+ config.filter_run :focus
36
+
37
+ # Run specs in random order to surface order dependencies. If you find an
38
+ # order dependency and want to debug it, you can fix the order by providing
39
+ # the seed, which is printed after each run.
40
+ # --seed 1234
41
+ config.order = 'random'
42
+
43
+ include YARD
44
+ end
@@ -0,0 +1,13 @@
1
+ require 'fileutils'
2
+ require 'yard-api/yardoc_task'
3
+
4
+ runner = YARD::APIPlugin::YardocTask.new
5
+
6
+ desc 'generate YARD API docs'
7
+ task :yard_api => :environment do |t|
8
+ output = runner.config['output']
9
+ puts <<-Message
10
+ API Documentation successfully generated in #{output}
11
+ See #{output}/index.html
12
+ Message
13
+ end
@@ -0,0 +1,19 @@
1
+ include T('default/appendix/html')
2
+
3
+ def init
4
+ super
5
+ end
6
+
7
+ def appendix
8
+ controllers = options[:controllers]
9
+
10
+ unless controllers && controllers.is_a?(Array)
11
+ return
12
+ end
13
+
14
+ @appendixes = controllers.collect { |c|
15
+ c.children.select { |o| :appendix == o.type }
16
+ }.flatten
17
+
18
+ super
19
+ end
@@ -0,0 +1,3 @@
1
+ def init
2
+ sections :text, T('tags')
3
+ end
@@ -0,0 +1,6 @@
1
+ <% untagged = object.tags.reject { |tag| tag.tag_name == 'API' }.empty? %>
2
+
3
+ <% text = object.docstring.strip %>
4
+ <% text = '*No documentation available yet.*' if text.empty? && untagged %>
5
+
6
+ <%= html_markup_markdown(text) %>
@@ -0,0 +1,78 @@
1
+ require 'pathname'
2
+
3
+ include YARD::Templates::Helpers::ModuleHelper
4
+ include YARD::Templates::Helpers::FilterHelper
5
+
6
+ def init
7
+ options[:resources] = options[:objects].
8
+ group_by { |o| o.tags('API').first.text }.
9
+ sort_by { |o| o.first }
10
+
11
+ build_json_objects_map
12
+ generate_assets
13
+ serialize_index
14
+ serialize_static_pages
15
+
16
+ options.delete(:objects)
17
+
18
+ options[:resources].each do |resource, controllers|
19
+ serialize_resource(resource, controllers)
20
+ end
21
+ end
22
+
23
+ def serialize(object)
24
+ options[:object] = object
25
+ Templates::Engine.with_serializer(object, options[:serializer]) do
26
+ T('layout').run(options)
27
+ end
28
+ end
29
+
30
+ def serialize_resource(resource, controllers)
31
+ options[:object] = resource
32
+ options[:controllers] = controllers
33
+ Templates::Engine.with_serializer("#{topicize resource}.html", options[:serializer]) do
34
+ T('layout').run(options)
35
+ end
36
+ options.delete(:controllers)
37
+ end
38
+
39
+ def serialize_index
40
+ options[:file] = api_options['readme']
41
+ serialize('index.html')
42
+ options.delete(:file)
43
+ end
44
+
45
+ def asset(path, content)
46
+ options[:serializer].serialize(path, content) if options[:serializer]
47
+ end
48
+
49
+ def generate_assets
50
+ asset_root = Pathname.new(File.dirname(__FILE__))
51
+ (Dir[asset_root + "css/**/*.css"] + Dir[asset_root + "js/**/*.js"]).each do |file|
52
+ file = Pathname.new(file).relative_path_from(asset_root).to_s
53
+ asset(file, file(file, true))
54
+ end
55
+ end
56
+
57
+ def serialize_static_pages
58
+ static_pages.each do |page|
59
+ options[:file] = page[:src]
60
+ serialize(page[:filename])
61
+ options.delete(:file)
62
+ end
63
+ end
64
+
65
+ def build_json_objects_map
66
+ options[:json_objects_map] = {}
67
+ options[:json_objects] = {}
68
+ options[:resources].each do |r,cs|
69
+ cs.each do |controller|
70
+ (controller.tags(:object) + controller.tags(:model)).each do |obj|
71
+ name, json = obj.text.split(%r{\n+}, 2).map(&:strip)
72
+ options[:json_objects_map][name] = topicize r
73
+ options[:json_objects][r] ||= []
74
+ options[:json_objects][r] << [name, json]
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,11 @@
1
+ <div id="footer">
2
+ <p>
3
+ <% if api_options['footer_copyright'] %>
4
+ <%= api_options['footer_copyright'] %>
5
+ <% end %>
6
+
7
+ Generated on <%= Time.now.strftime("%c") %>
8
+ </p>
9
+
10
+ <%= api_options['footer_note'].to_s %>
11
+ </div>