yard-api 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/LICENSE +674 -0
- data/README.md +27 -0
- data/lib/yard-api/markup/redcarpet.rb +42 -0
- data/lib/yard-api/options.rb +13 -0
- data/lib/yard-api/railtie.rb +11 -0
- data/lib/yard-api/tags.rb +16 -0
- data/lib/yard-api/templates/helpers/base_helper.rb +108 -0
- data/lib/yard-api/templates/helpers/html_helper.rb +87 -0
- data/lib/yard-api/templates/helpers/route_helper.rb +19 -0
- data/lib/yard-api/verifier.rb +34 -0
- data/lib/yard-api/version.rb +5 -0
- data/lib/yard-api/yardoc_task.rb +78 -0
- data/lib/yard-api.rb +48 -0
- data/spec/spec_helper.rb +44 -0
- data/tasks/yard_api.rake +13 -0
- data/templates/api/appendix/html/setup.rb +19 -0
- data/templates/api/docstring/html/setup.rb +3 -0
- data/templates/api/docstring/html/text.erb +6 -0
- data/templates/api/fulldoc/html/setup.rb +78 -0
- data/templates/api/layout/html/footer.erb +11 -0
- data/templates/api/layout/html/headers.erb +19 -0
- data/templates/api/layout/html/layout.erb +17 -0
- data/templates/api/layout/html/scripts.erb +35 -0
- data/templates/api/layout/html/setup.rb +63 -0
- data/templates/api/layout/html/sidebar.erb +29 -0
- data/templates/api/method_details/html/header.erb +12 -0
- data/templates/api/method_details/html/method_signature.erb +19 -0
- data/templates/api/method_details/html/setup.rb +35 -0
- data/templates/api/tags/html/_example_code_block.erb +8 -0
- data/templates/api/tags/html/argument.erb +32 -0
- data/templates/api/tags/html/emits.erb +7 -0
- data/templates/api/tags/html/example_request.erb +13 -0
- data/templates/api/tags/html/example_response.erb +14 -0
- data/templates/api/tags/html/generic_tag.erb +20 -0
- data/templates/api/tags/html/index.erb +3 -0
- data/templates/api/tags/html/no_content.erb +3 -0
- data/templates/api/tags/html/note.erb +6 -0
- data/templates/api/tags/html/returns.erb +10 -0
- data/templates/api/tags/html/see.erb +8 -0
- data/templates/api/tags/html/throws.erb +49 -0
- data/templates/api/tags/html/warning.erb +6 -0
- data/templates/api/tags/setup.rb +83 -0
- data/templates/api/topic/html/header.erb +7 -0
- data/templates/api/topic/html/method_details_list.erb +5 -0
- data/templates/api/topic/html/setup.rb +58 -0
- data/templates/api/topic/html/topic_doc.erb +27 -0
- data/yard-api.gemspec +22 -0
- 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,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,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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
data/tasks/yard_api.rake
ADDED
@@ -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,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
|