yard-api 0.1.1

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.
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>