yard-api 0.1.10 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f894b7c9e0efdee454a068de0105e061b713784
4
- data.tar.gz: a5eb169d8372bcea684866395a2a4ecddda65385
3
+ metadata.gz: 867bf4c5f7af54dcfe89527e5aa33b3028573ae0
4
+ data.tar.gz: 55bee11b6e7fbf8a94f43e17750f908ca0ea286b
5
5
  SHA512:
6
- metadata.gz: 297b3d21420a0a60052d77f4d2748ed252e32298e78b3e87d2b7f13f6229efe389483b52bc4f309399b87eb5b816befe0f91c7be4fa479aa81f383890b453479
7
- data.tar.gz: fea346e1cee3d55253920f2fba306f797a5a86c41e74418e42958ace2d96dd2269499808df1f345080716f002ee4afd8816c93686cec1b9235e1d1459e9d7cc0
6
+ metadata.gz: 855c761049489fe7c9f22fc786093580ee7de47ecd93a1f4945e70e35e64be2d1a1d4c780e0997101ea81fdfb4e48acb7b90a41f9b46acc1daa2ebcb172104fc
7
+ data.tar.gz: 3a0efa005c097a27e400ad6b00189aa8a3f57469929a9f37199766f00cb928f0a22004dca2f6daabf8dd7f66af284957e0be0a377f36aae533fa54d0ea089f0d
data/config/yard_api.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  # config/yard_api.yml
3
3
  output: public/doc/api
4
- source: doc/api
5
4
  readme: doc/api/README.md
6
5
 
7
6
  # Title of the project. This will be displayed in the browser title bar as well
@@ -32,6 +31,8 @@ markup_provider:
32
31
  files:
33
32
  - app/controllers/**/*.rb
34
33
 
34
+ route_namespace:
35
+
35
36
  # YARD assets that you want to reference from your docs. The key is the
36
37
  # reference key you use in the docs, while the value is the path to where
37
38
  # the assets are located relative to the doc source.
@@ -40,8 +41,8 @@ files:
40
41
  #
41
42
  # See "source" and "output".
42
43
  assets:
43
- images: images
44
- examples: examples
44
+ # images: images
45
+ # examples: examples
45
46
 
46
47
  # Debug option. YARD and YARD-API verbosity option.
47
48
  verbose: true
@@ -57,7 +58,9 @@ strict: false
57
58
  #
58
59
  # Just specify the url to your repository and the branch the documentation has
59
60
  # been generated for and things "should work".
60
- github_url: https://github.com/amireh/yard-api
61
+ #
62
+ # Example: https://github.com/amireh/yard-api
63
+ github_url:
61
64
  github_branch: master
62
65
 
63
66
  # Set to true if you want @argument tags to show up in a table instead of a list.
@@ -1,10 +1,12 @@
1
1
  module YARD::APIPlugin
2
2
  # See config/yard_api.yml for documentation for the options.
3
3
  class Options < YARD::Options
4
+ default_attr :format, 'html'
5
+ default_attr :no_save, false
6
+
4
7
  default_attr :title, 'Rails API Project'
5
8
  default_attr :window_title, 'Rails API Project Documentation'
6
9
  default_attr :version, ''
7
- default_attr :source, 'doc/api'
8
10
  default_attr :static, []
9
11
  default_attr :files, []
10
12
  default_attr :route_namespace, ''
@@ -15,6 +17,7 @@ module YARD::APIPlugin
15
17
  default_attr :footer_note, ''
16
18
 
17
19
  default_attr :one_file, false
20
+ default_attr :strict, false
18
21
  default_attr :verbose, false
19
22
  default_attr :debug, false
20
23
  default_attr :theme, 'default'
@@ -7,6 +7,7 @@ module YARD::APIPlugin::Tags
7
7
  RE_NAME = /^([\S]+)/
8
8
  RE_ARRAY_LITERAL = /\[[^\]]+\]/
9
9
  RE_ARRAY_TYPE = /^#{RE_ARRAY_LITERAL}$/
10
+ RE_REQUIRED_OPTIONAL = /required|optional/i
10
11
  RE_ACCEPTED_VALUES_PREFIXES = /
11
12
  accepted\svalues |
12
13
  accepts |
@@ -38,18 +39,19 @@ module YARD::APIPlugin::Tags
38
39
  YARD::Tags::Library.instance.tag_create(:attr, buf).tap do |tag|
39
40
  super(:argument, tag.text, tag.types, name || tag.name)
40
41
 
42
+ @types ||= []
43
+ @text ||= ''
44
+
41
45
  @is_required = parse_is_required(@types)
42
46
  @accepted_values = parse_accepted_values(@types, @text)
43
47
  end
44
48
  end
45
49
 
46
50
  def unscoped_name
47
- if scope_tag = @object.tag(:argument_scope)
48
- if @name =~ /^#{scope_tag.text}\[([^\]]+)\]$/
49
- $1
50
- else
51
- @name
52
- end
51
+ scope_tag = @object.tag(:argument_scope)
52
+
53
+ if scope_tag && @name =~ /^#{scope_tag.text.gsub(/\[\]/, '')}\[([^\]]+)\]$/
54
+ $1
53
55
  else
54
56
  @name
55
57
  end
@@ -57,36 +59,51 @@ module YARD::APIPlugin::Tags
57
59
 
58
60
  private
59
61
 
60
- def parse_is_required(types)
62
+ def parse_is_required(types=[])
61
63
  strict = !!YARD::APIPlugin.options.strict_arguments
62
- specifier = types.detect { |typestr| typestr.match(/optional|required/i) }
64
+ specifier = Array(types).detect { |typestr| typestr.match(RE_REQUIRED_OPTIONAL) }
63
65
 
64
66
  if specifier
65
67
  types.delete(specifier)
66
68
 
67
- return true if specifier.downcase == 'required'
68
- return false if specifier.downcase == 'optional'
69
+ if specifier.downcase == 'required'
70
+ return true
71
+ elsif specifier.downcase == 'optional'
72
+ return false
73
+ end
69
74
  end
70
75
 
71
76
  strict
72
77
  end
73
78
 
74
- def parse_accepted_values(types, text)
75
- str = if types.last.match(RE_ARRAY_TYPE)
79
+ def parse_accepted_values(types=[], text='')
80
+ # values specified after the type, i.e.:
81
+ #
82
+ # @argument [String, ["S","M","L"]] size
83
+ #
84
+ str = if Array(types).any? && types.last.match(RE_ARRAY_TYPE)
76
85
  types.pop
77
- elsif text.match(RE_ACCEPTED_VALUES_STR)
86
+ # otherwise, look for them in the docstring, e.g.:
87
+ #
88
+ # @argument [String] size
89
+ # Accepts ["S","M","L"]
90
+ #
91
+ elsif text && text.match(RE_ACCEPTED_VALUES_STR)
78
92
  $1
79
93
  end
80
94
 
81
95
  if str
82
96
  begin
83
- YAML.load(str)
97
+ # some people prefer to use the pipe (|) to separate the values
98
+ YAML.load(str.to_s.gsub('|', ','))
84
99
  rescue Exception => e
85
100
  YARD::APIPlugin.on_error <<-Error
86
101
  Unable to parse accepted values for @argument tag.
87
- Error: #{exception}
102
+ Error:
103
+ #{e.class}: #{e.message}
88
104
  Offending docstring:
89
105
  #{text}
106
+ Accepted values string: '#{str}'
90
107
  Error
91
108
 
92
109
  return nil
data/lib/yard-api/tags.rb CHANGED
@@ -16,4 +16,5 @@ YARD::Tags::Library.define_tag("API empty response", :no_content)
16
16
  YARD::Tags::Library.define_tag("API error", :throws)
17
17
  YARD::Tags::Library.define_tag("API warning", :warning)
18
18
  YARD::Tags::Library.define_tag("API note", :note)
19
- YARD::Tags::Library.define_tag("API message", :emits)
19
+ YARD::Tags::Library.define_tag("API message", :emits)
20
+ YARD::Tags::Library.define_tag("API model", :model)
@@ -85,7 +85,7 @@ module YARD::Templates::Helpers::BaseHelper
85
85
  def lookup_appendix(title)
86
86
  appendix = nil
87
87
 
88
- puts "Looking up appendix: #{title}" if api_options.verbose
88
+ YARD::APIPlugin.log("Looking up appendix: #{title}") if api_options.verbose
89
89
 
90
90
  if object
91
91
  # try in the object scope
@@ -2,7 +2,7 @@ require 'yard/templates/helpers/html_helper'
2
2
 
3
3
  module YARD::Templates::Helpers::HtmlHelper
4
4
  def topicize(str)
5
- str.gsub(' ', '_').underscore
5
+ str.split("\n")[0].gsub(' ', '_').underscore
6
6
  end
7
7
 
8
8
  def url_for_file(filename, anchor = nil)
@@ -12,55 +12,53 @@ module YARD::Templates::Helpers::HtmlHelper
12
12
  end
13
13
 
14
14
  def static_pages()
15
- return @static_pages if @static_pages
15
+ @@static_pages ||= begin
16
+ locate_static_pages(YARD::APIPlugin.options)
17
+ end
18
+ end
16
19
 
17
- options = YARD::APIPlugin.options
20
+ def locate_static_pages(options)
21
+ title_overrides = {}
18
22
 
19
23
  paths = Array(options.static).map do |entry|
20
24
  pages = if entry.is_a?(Hash)
21
- glob = entry['glob']
22
- blacklist = Array(entry['exclude'])
23
-
24
- unless glob
25
- raise "Invalid static page entry, expected Hash to contain a 'glob' parameter: #{entry}"
25
+ if !entry.has_key?('path')
26
+ raise "Static page entry must contain a 'path' parameter: #{entry}"
27
+ elsif !entry.has_key?('title')
28
+ raise "Static page entry must contain a 'title' parameter: #{entry}"
26
29
  end
27
30
 
28
- pages = Dir.glob(entry['glob'])
29
-
30
- if blacklist.any?
31
- pages.delete_if { |p| blacklist.any? { |filter| p.match(filter) } }
32
- end
31
+ title_overrides[entry['path']] = entry['title']
33
32
 
34
- pages
33
+ entry['path']
35
34
  elsif entry.is_a?(Array)
36
35
  entry.map(&:to_s)
37
36
  elsif entry.is_a?(String)
38
- [ entry ]
37
+ entry
39
38
  end
40
- end.flatten.compact.uniq.map { |path| File.join(options.source, path) }
39
+ end
41
40
 
42
- markdown_exts = YARD::Templates::Helpers::MarkupHelper::MARKUP_EXTENSIONS[:markdown]
43
- readme_page = options.readme
44
- pages = Dir.glob(paths)
41
+ pages = Dir.glob(paths.flatten.compact)
45
42
 
46
- if readme_page.present? && !options.one_file
47
- pages.delete_if { |page| page.match(readme_page) }
43
+ if options.readme && !options.one_file
44
+ pages.delete_if { |page| page.match(options.readme) }
48
45
  end
49
46
 
50
- @static_pages = pages.map do |page|
47
+ pages.uniq.map do |page|
51
48
  filename = 'file.' + File.split(page).last.sub(/\..*$/, '.html')
52
49
 
53
- # extract page title if it's a markdown document; title is expected to
54
- # be an h1 on the very first line:
55
- title = if markdown_exts.include?(File.extname(page).sub('.', ''))
56
- (File.open(page, &:gets) || '').strip.sub('# ', '')
57
- else
58
- # otherwise we'll just sanitize the file name
59
- File.basename(page).sub(/\.\w+$/, '').gsub(/\W/, ' ').gsub(/\s+/, ' ').capitalize
60
- end
50
+ title = (
51
+ title_overrides[page] ||
52
+ File.basename(page)
53
+ .sub(/\.\w+$/, '')
54
+ .gsub('_', ' ')
55
+ .gsub(/\W/, ' ')
56
+ .gsub(/\s+/, ' ')
57
+ .capitalize
58
+ )
61
59
 
62
60
  if options.verbose
63
- puts "Serializing static page #{page}"
61
+ puts "Serializing static page #{page} (#{title})"
64
62
  end
65
63
 
66
64
  {
@@ -68,8 +66,9 @@ module YARD::Templates::Helpers::HtmlHelper
68
66
  filename: filename,
69
67
  title: title
70
68
  }
71
- end
69
+ end.sort_by { |page| page[:title] }
72
70
  end
71
+ protected :locate_static_pages
73
72
 
74
73
  # override yard-appendix link_appendix
75
74
  def link_appendix(ref)
@@ -10,9 +10,10 @@ module YARD
10
10
  relevant = list.select { |o| relevant_object?(o) }
11
11
 
12
12
  if @verbose && relevant.any?
13
- puts "#{relevant.length}/#{list.length} objects are relevant:"
13
+ log "#{relevant.length}/#{list.length} objects are relevant:"
14
+
14
15
  relevant.each do |object|
15
- puts "\t- #{object.path}"
16
+ log "\t- #{object.path}"
16
17
  end
17
18
  end
18
19
 
@@ -24,11 +25,22 @@ module YARD
24
25
  when :root, :module, :constant
25
26
  false
26
27
  when :method, :class
27
- !object.tags('API').empty? && object.tags('internal').empty?
28
+ is_api = !object.tags('API').empty?
29
+ is_internal = !object.tags('internal').empty?
30
+
31
+ if @verbose && !is_api && !is_internal
32
+ log "Resource #{object} will be ignored as it contains no @API tag."
33
+ end
34
+
35
+ is_api && !is_internal
28
36
  else
29
37
  object.parent.nil? && relevant_object?(object.parent)
30
38
  end
31
39
  end
40
+
41
+ def log(*args)
42
+ ::YARD::APIPlugin.log(*args)
43
+ end
32
44
  end
33
45
  end
34
46
  end
@@ -1,5 +1,5 @@
1
1
  module YARD
2
2
  module APIPlugin
3
- VERSION = "0.1.10"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
@@ -14,7 +14,7 @@ module YARD::APIPlugin
14
14
  @config = load_config
15
15
  t = self
16
16
 
17
- YARD::APIPlugin.options.update(@config)
17
+ api_options = YARD::APIPlugin.options.update(@config)
18
18
 
19
19
  t.verifier = YARD::APIPlugin::Verifier.new(config['verbose'])
20
20
  t.before = proc { FileUtils.rm_rf(config['output']) }
@@ -41,8 +41,11 @@ module YARD::APIPlugin
41
41
  set_option('verbose') if config['verbose']
42
42
  set_option('debug') if config['debug']
43
43
 
44
+ set_option('no-save') if config['no_save']
45
+ set_option('format', config['format'] || 'html')
46
+
44
47
  get_assets(config).each_pair do |asset_id, rpath|
45
- asset_path = File.join(config['source'], rpath)
48
+ asset_path = rpath
46
49
 
47
50
  if File.directory?(asset_path)
48
51
  set_option 'asset', [ asset_path, asset_id ].join(':')
@@ -62,7 +65,7 @@ module YARD::APIPlugin
62
65
  private
63
66
 
64
67
  def load_config
65
- path = Rails.root.join('config', 'yard_api.yml')
68
+ path = ENV.fetch('YARD_API_CONFIG') { Rails.root.join('config', 'yard_api.yml') }
66
69
 
67
70
  # load defaults
68
71
  config = YAML.load_file(File.join(YARD::APIPlugin::CONFIG_PATH, 'yard_api.yml'))
@@ -78,4 +81,4 @@ module YARD::APIPlugin
78
81
  config['assets'] || {}
79
82
  end
80
83
  end
81
- end
84
+ end
data/lib/yard-api.rb CHANGED
@@ -39,9 +39,9 @@ module YARD
39
39
 
40
40
  def self.on_error(message)
41
41
  if self.options.strict
42
- raise error
42
+ raise message
43
43
  else
44
- self.log(error, ::Logger::WARN)
44
+ self.log(message, ::Logger::WARN)
45
45
  end
46
46
  end
47
47
  end
data/spec/spec_helper.rb CHANGED
@@ -108,6 +108,7 @@ RSpec.configure do |config|
108
108
  @options.send("#{key}=", value)
109
109
  end
110
110
 
111
+ @options.reset_defaults
111
112
  @overridden_options.clear
112
113
  end
113
114
  end
@@ -16,7 +16,6 @@ describe YARD::APIPlugin::Tags::ArgumentTag do
16
16
  end
17
17
 
18
18
  it 'should work like an @attr tag' do
19
- ENV['DO'] = '1'
20
19
  populate <<-'eof'
21
20
  # @argument [String] name
22
21
  # Your full name.
@@ -0,0 +1,25 @@
1
+ # include T('default/appendix/html')
2
+
3
+ def init
4
+ super
5
+ end
6
+
7
+ def appendix
8
+ controllers = options[:controllers]
9
+
10
+ if options[:all_resources]
11
+ controllers = options[:resources].flatten.select { |o|
12
+ o.is_a?(YARD::CodeObjects::NamespaceObject)
13
+ }
14
+ end
15
+
16
+ unless controllers && controllers.is_a?(Array)
17
+ return
18
+ end
19
+
20
+ @appendixes = controllers.collect do |controller|
21
+ controller.children.select { |tag| :appendix == tag.type }
22
+ end.flatten.uniq
23
+
24
+ super
25
+ end
@@ -0,0 +1,4 @@
1
+ def init
2
+ puts "> HI from docstring!"
3
+ # sections :text, T('tags')
4
+ end
@@ -5,7 +5,7 @@ include YARD::Templates::Helpers::FilterHelper
5
5
 
6
6
  def init
7
7
  options[:resources] = options[:objects].
8
- group_by { |o| o.tags('API').first.text }.
8
+ group_by { |o| o.tags('API').first.text.split("\n").first }.
9
9
  sort_by { |o| o.first }
10
10
 
11
11
  build_json_objects_map
@@ -0,0 +1,112 @@
1
+ require 'pathname'
2
+
3
+ include YARD::Templates::Helpers::ModuleHelper
4
+ include YARD::Templates::Helpers::FilterHelper
5
+ include YARD::Templates::Helpers::HtmlHelper
6
+
7
+ RouteHelper = YARD::Templates::Helpers::RouteHelper
8
+
9
+ def init
10
+ resources = options[:objects]
11
+ .group_by { |o| o.tags('API').first.text }
12
+ .sort_by { |o| o.first }
13
+ .each { |resource, controllers| serialize_resource(resource, controllers) }
14
+ end
15
+
16
+ def serialize_resource(resource, controllers)
17
+ Templates::Engine.with_serializer("#{topicize resource}.json", options[:serializer]) do
18
+ JSON.pretty_generate({
19
+ object: resource,
20
+ api_objects: controllers.map do |controller|
21
+ dump_api_objects(controller)
22
+ end.flatten,
23
+ methods: method_details_list(controllers)
24
+ })
25
+ end
26
+ end
27
+
28
+ def method_details_list(controllers)
29
+ @meths = controllers.map do |controller|
30
+ controller.meths(:inherited => false, :included => false)
31
+ end.flatten
32
+
33
+ @meths = run_verifier(@meths)
34
+
35
+ @meths.map do |object, i|
36
+ dump_object(object).tap do |object_info|
37
+ object_info[:tags] = dump_object_tags(object)
38
+ end
39
+ end
40
+ end
41
+
42
+ def dump_api_objects(controller)
43
+ (controller.tags(:object) + controller.tags(:model)).map do |obj|
44
+ name, schema = obj.text.split(%r{\n+}, 2).map(&:strip)
45
+
46
+ {
47
+ controller: controller.name,
48
+ name: name,
49
+ schema: schema
50
+ }
51
+ end
52
+ end
53
+
54
+ def dump_object(object)
55
+ {
56
+ name: object.name,
57
+ route: get_route(object),
58
+ title: object.title,
59
+ type: object.type,
60
+ path: object.path,
61
+ namespace: object.namespace.path,
62
+ source: object.source,
63
+ source_type: object.source_type,
64
+ signature: object.signature,
65
+ files: object.files,
66
+ docstring: object.base_docstring,
67
+ dynamic: object.dynamic,
68
+ group: object.group,
69
+ visibility: object.visibility
70
+ }
71
+ end
72
+
73
+ def dump_object_tags(object)
74
+ object.tags.map do |tag|
75
+ tag.instance_variables.reduce({}) do |out, var|
76
+ key = var.to_s.sub('@', '')
77
+
78
+ if tag.respond_to?(key) && key != 'object'
79
+ out[key] = tag.send(key)
80
+ end
81
+
82
+ out
83
+ end
84
+ end
85
+ end
86
+
87
+ def get_route(object)
88
+ controller = object.parent.path.underscore
89
+ controller.sub!("_controller", '') unless controller.include?('/')
90
+
91
+ action = object.path.sub(/^.*#/, '')
92
+ action = action.sub(/_with_.*$/, '')
93
+ routes = RouteHelper.api_methods_for_controller_and_action(controller, action)
94
+ route = routes.first
95
+
96
+ if route.present?
97
+ # controller_path = "app/controllers/#{route.requirements[:controller]}_controller.rb"
98
+ # controller_path = nil unless File.file?(Rails.root+controller_path)
99
+
100
+ route_path = route.path.spec.to_s.gsub("(.:format)", "")
101
+ verb = if route.verb.source =~ /\^?(\w*)\$/
102
+ $1.upcase
103
+ else
104
+ route.verb.source
105
+ end
106
+
107
+ {
108
+ path: route_path,
109
+ verb: verb
110
+ }
111
+ end
112
+ end
@@ -0,0 +1 @@
1
+ <%= yieldall %>
@@ -0,0 +1,10 @@
1
+ def init
2
+ puts "> LAYOUT"
3
+ # puts options[:object]
4
+
5
+ if options[:controllers]
6
+ sections :layout, [T('topic'), T('appendix')]
7
+ else
8
+ sections :layout, [:contents]
9
+ end
10
+ end
@@ -1,13 +1,24 @@
1
- <div class="method_details <%= @index == 0 ? 'first' : '' %>">
2
- <h2 class='api_method_name' name='<%= @method_link %>' data-subtopic='<%= @subtopic %>'>
3
- <a name='<%= @method_link %>' href='#<%= @method_link %>'>
4
- <%= object.tag("API").try(:text) %>
1
+ <div class='method_details'>
2
+ <h2
3
+ class='api_method_name'
4
+ name='<%= @props[:method_link] %>'
5
+ data-subtopic='<%= @props[:subtopic] %>'
6
+ >
7
+ <a
8
+ name='<%= @props[:method_link] %>'
9
+ href='#<%= @props[:method_link] %>'
10
+ >
11
+ <%= object.tag('API').text %>
5
12
  </a>
6
13
 
7
- <% if @controller_path && !api_options.github_url.to_s.empty? %>
14
+ <% if @props[:path] && !api_options.github_url.to_s.empty? %>
8
15
  <span class='defined-in'>
9
- <a href="<%= api_options.github_url %>/blob/<%= api_options.github_branch %>/<%= @controller_path %>"><%= "#{@route.requirements[:controller].camelize}Controller\##{@route.requirements[:action]}" %></a></span>
16
+ <a href="<%= api_options.github_url %>/blob/<%= api_options.github_branch %>/<%= @props[:path] %>">
17
+ <%= "#{@props[:controller]}Controller\##{@props[:action]}" %>
18
+ </a>
19
+ </span>
10
20
  <% end %>
11
21
  </h2>
22
+
12
23
  <%= yieldall %>
13
24
  </div>
@@ -1,19 +1,13 @@
1
- <% @routes.each do |route| %>
2
- <% route_path = route.path.spec.to_s.gsub("(.:format)", "")
3
- if route.verb.source =~ /\^?(\w*)\$/
4
- verb = $1.upcase
5
- else
6
- verb = route.verb.source
7
- end
8
- %>
1
+ <% @props[:routes].each do |route| %>
2
+ <%
3
+ formatted_route_path = route[:path].split('/').map do |fragment|
4
+ is_id = fragment =~ /^\:[\w|_]+/
5
+ "<span #{'class="id-fragment"' if is_id}>#{fragment}</span>"
6
+ end.join('/')
7
+ %>
8
+
9
9
  <h3 class='endpoint'>
10
- <span class="verb <%= verb.downcase %>"><%= verb %></span>
11
- <%
12
- formatted_route_path = route_path.split('/').map do |fragment|
13
- is_id = fragment =~ /^\:[\w|_]+/
14
- "<span #{'class="id-fragment"' if is_id}>#{fragment}</span>"
15
- end.join('/')
16
- %>
10
+ <span class="verb <%= route[:verb].downcase %>"><%= route[:verb] %></span>
17
11
  <%= formatted_route_path %>
18
12
  </h3>
19
13
  <% end %>
@@ -1,35 +1,58 @@
1
1
  # require 'route_helper'
2
2
 
3
3
  RouteHelper = YARD::Templates::Helpers::RouteHelper
4
+
4
5
  def init
5
- get_routes
6
6
  sections :header, [:method_signature, T('docstring')]
7
7
  end
8
8
 
9
9
  def header
10
- get_routes
11
- @subtopic = (object.parent.tag('subtopic') || object.parent.tag('API')).text
10
+ routes = get_current_routes
11
+
12
+ unless route = routes.first
13
+ ::YARD::APIPlugin.log(
14
+ "[error] Unable to find route for object: #{object}",
15
+ ::Logger::ERROR
16
+ )
12
17
 
13
- unless route = @routes.first
14
- puts "[error] Unable to find route for object: #{object}"
15
18
  return
16
19
  end
17
20
 
18
- @method_link = "method.#{route.requirements[:controller]}.#{route.requirements[:action]}"
19
- @beta = object.tag('beta') || object.parent.tag('beta')
21
+ @props = {}
22
+ @props[:method_link] = [
23
+ 'method',
24
+ route.requirements[:controller],
25
+ route.requirements[:action]
26
+ ].join('.')
27
+
28
+ @props[:subtopic] = (object.parent.tag('subtopic') || object.parent.tag('API')).text
29
+
30
+ controller_path = "app/controllers/#{route.requirements[:controller]}_controller.rb"
31
+
32
+ # TODO: can't we just test using object.file instead of relying on Rails ?
33
+ controller_path = nil unless File.file?(Rails.root+controller_path)
34
+
35
+ if controller_path
36
+ @props[:path] = controller_path
37
+ @props[:controller] = route.requirements[:controller].camelize
38
+ @props[:action] = route.requirements[:action]
39
+ end
40
+
41
+ @props[:routes] = routes.map do |route|
42
+ {}.tap do |spec|
43
+ spec[:path] = route.path.spec.to_s.gsub("(.:format)", "")
44
+ spec[:verb] = route.verb.source =~ /\^?(\w*)\$/ ? $1.upcase : route.verb.source
45
+ end
46
+ end
47
+
20
48
  erb(:header)
21
49
  end
22
50
 
23
- def get_routes
24
- @controller = object.parent.path.underscore
25
- @controller.sub!("_controller", '') unless @controller.include?('/')
26
-
27
- @action = object.path.sub(/^.*#/, '')
28
- @action = @action.sub(/_with_.*$/, '')
29
- @routes = RouteHelper.api_methods_for_controller_and_action(@controller, @action)
30
- @route = @routes.first
31
- if @route.present?
32
- @controller_path = "app/controllers/#{@route.requirements[:controller]}_controller.rb"
33
- @controller_path = nil unless File.file?(Rails.root+@controller_path)
34
- end
51
+ def get_current_routes
52
+ controller_name = object.parent.path.underscore
53
+ controller_name.sub!("_controller", '') unless controller_name.include?('/')
54
+
55
+ action = object.path.sub(/^.*#/, '').sub(/_with_.*$/, '')
56
+
57
+ RouteHelper.api_methods_for_controller_and_action(controller_name, action)
35
58
  end
@@ -0,0 +1,9 @@
1
+ def init
2
+ sections :main
3
+ end
4
+
5
+ def main
6
+ {
7
+ text: object.tag("API").try(:text)
8
+ }
9
+ end
@@ -1,28 +1,20 @@
1
1
  <ul class="argument">
2
2
  <% @argument_tags.each do |tag| %>
3
- <%
4
- tag.text ||= ''
5
- desc = tag.text.strip.sub(/^\[([^\]]+)\]/, '').strip
6
- type = $1
7
- desc = desc.sub(/(\(optional\))/, '').strip
8
- is_optional = $1.present?
9
- name, desc = desc.split(/\s/, 2).map(&:strip)
10
- desc = desc.sub(/[A|a]ccepted values:\s*\[([^\]]+)\]/, '').strip
11
- accepted_values = $1
12
- %>
13
3
  <li>
14
- <code class="argument-name"><%= h name %></code>
15
- <span class="argument-type"><%= type %></span>
16
- <span class="argument-values fade">
17
- <em><%= "[#{accepted_values}]" if accepted_values.present? %></em>
18
- </span>
4
+ <code class="argument-name"><%= h tag.unscoped_name %></code>
5
+ <span class="argument-type"><%= tag.type %></span>
6
+ <% if (tag.accepted_values || []).any? %>
7
+ <span class="argument-values fade">
8
+ <em>[ <%= tag.accepted_values.join(', ') %> ]</em>
9
+ </span>
10
+ <% end %>
19
11
 
20
- <% unless is_optional %>
12
+ <% if tag.is_required %>
21
13
  <em class="argument-required">Required</em>
22
14
  <% end %>
23
15
 
24
- <% if !desc.empty? %>
25
- <%= html_markup_markdown(desc) %>
16
+ <% if !tag.text.empty? %>
17
+ <%= html_markup_markdown(tag.text) %>
26
18
  <% end %>
27
19
  </li>
28
20
  <% end %>
@@ -1,9 +1,11 @@
1
+ <% has_accepted_values = @argument_tags.any? { |e| Array(e.accepted_values).any? } %>
2
+
1
3
  <table>
2
4
  <thead>
3
5
  <tr>
4
6
  <th>Name</th>
5
7
  <th>Type</th>
6
- <th>Accepted Values</th>
8
+ <% if has_accepted_values %><th>Accepted Values</th><% end %>
7
9
  <th>Required?</th>
8
10
  <th>Description</th>
9
11
  </tr>
@@ -14,13 +16,16 @@
14
16
  <tr>
15
17
  <td><code class="argument-name"><%= h tag.unscoped_name %></code></td>
16
18
  <td><span class="argument-type"><%= tag.type %></span></td>
17
- <td>
18
- <ul class="argument-values">
19
- <% (tag.accepted_values || []).each do |value| %>
20
- <li><%= value %></li>
21
- <% end %>
22
- </ul>
23
- </td>
19
+
20
+ <% if has_accepted_values %>
21
+ <td>
22
+ <ul class="argument-values">
23
+ <% (tag.accepted_values || []).each do |value| %>
24
+ <li><%= value %></li>
25
+ <% end %>
26
+ </ul>
27
+ </td>
28
+ <% end %>
24
29
 
25
30
  <td>
26
31
  <% if tag.is_required %>
@@ -1,5 +1,6 @@
1
1
  def init
2
2
  super
3
+
3
4
  sections *[
4
5
  :emits,
5
6
  :note,
@@ -1,3 +1,5 @@
1
+ require 'json'
2
+
1
3
  def init
2
4
  sections :header, [:topic_doc, :method_details_list, [T('method_details')]]
3
5
  @resource = object
@@ -19,16 +21,17 @@ def topic_doc
19
21
  end
20
22
 
21
23
  def properties_of_model(json)
22
- require 'json'
23
- JSON::parse(json)['properties']
24
- rescue JSON::ParserError
25
- nil
24
+ begin
25
+ JSON::parse(json || '')['properties']
26
+ rescue JSON::ParserError
27
+ nil
28
+ end
26
29
  end
27
30
 
28
31
  def word_wrap(text, col_width=80)
29
- text.gsub!( /(\S{#{col_width}})(?=\S)/, '\1 ' )
30
- text.gsub!( /(.{1,#{col_width}})(?:\s+|$)/, "\\1\n" )
31
- text
32
+ text.gsub!( /(\S{#{col_width}})(?=\S)/, '\1 ' )
33
+ text.gsub!( /(.{1,#{col_width}})(?:\s+|$)/, "\\1\n" )
34
+ text
32
35
  end
33
36
 
34
37
  def indent(str, amount = 2, char = ' ')
@@ -36,7 +39,7 @@ def indent(str, amount = 2, char = ' ')
36
39
  end
37
40
 
38
41
  def render_comment(string, wrap = 75)
39
- indent(word_wrap(string), 2, '/')
42
+ string ? indent(word_wrap(string), 2, '/') : ''
40
43
  end
41
44
 
42
45
  def render_value(value, type = 'string')
@@ -0,0 +1,25 @@
1
+ def init
2
+ # sections :header, [:topic_doc, :method_details_list, [T('method_details')]]
3
+ sections :method_details_list, [T('method_details')]
4
+ @resource = object
5
+ # @beta = options[:controllers].any? { |c| c.tag('beta') }
6
+ puts "Topic: HEE? #{@resource}"
7
+ end
8
+
9
+ def method_details_list
10
+ @meths = options[:controllers].map { |c| c.meths(:inherited => false, :included => false) }.flatten
11
+ @meths = run_verifier(@meths)
12
+
13
+ # puts "Methods: #{@meths}"
14
+
15
+ buffer = [];
16
+
17
+ @meths.each_with_index do |meth, i|
18
+ # puts "#{i} => #{meth.tags}"
19
+ buffer.push(yieldall :object => meth, :index => i)
20
+ end
21
+
22
+ puts "Buffer: #{buffer.to_json}"
23
+
24
+ buffer.to_json
25
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ahmad Amireh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-16 00:00:00.000000000 Z
11
+ date: 2015-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -93,8 +93,10 @@ files:
93
93
  - spec/tags/argument_spec.rb
94
94
  - tasks/yard_api.rake
95
95
  - templates/api/appendix/html/setup.rb
96
+ - templates/api/appendix/json/setup.rb
96
97
  - templates/api/docstring/html/setup.rb
97
98
  - templates/api/docstring/html/text.erb
99
+ - templates/api/docstring/json/setup.rb
98
100
  - templates/api/fulldoc/html/css/common.css
99
101
  - templates/api/fulldoc/html/css/highlight.css
100
102
  - templates/api/fulldoc/html/js/highlight.zip
@@ -157,6 +159,7 @@ files:
157
159
  - templates/api/fulldoc/html/js/highlight/styles/zenburn.css
158
160
  - templates/api/fulldoc/html/js/jquery-1.11.1.min.js
159
161
  - templates/api/fulldoc/html/setup.rb
162
+ - templates/api/fulldoc/json/setup.rb
160
163
  - templates/api/layout/html/_dynamic_styles.erb
161
164
  - templates/api/layout/html/footer.erb
162
165
  - templates/api/layout/html/headers.erb
@@ -164,9 +167,12 @@ files:
164
167
  - templates/api/layout/html/scripts.erb
165
168
  - templates/api/layout/html/setup.rb
166
169
  - templates/api/layout/html/sidebar.erb
170
+ - templates/api/layout/json/layout.erb
171
+ - templates/api/layout/json/setup.rb
167
172
  - templates/api/method_details/html/header.erb
168
173
  - templates/api/method_details/html/method_signature.erb
169
174
  - templates/api/method_details/html/setup.rb
175
+ - templates/api/method_details/json/setup.rb
170
176
  - templates/api/onefile/html/setup.rb
171
177
  - templates/api/onefile/html/sidebar.erb
172
178
  - templates/api/tags/html/_example_code_block.erb
@@ -189,6 +195,7 @@ files:
189
195
  - templates/api/topic/html/method_details_list.erb
190
196
  - templates/api/topic/html/setup.rb
191
197
  - templates/api/topic/html/topic_doc.erb
198
+ - templates/api/topic/json/setup.rb
192
199
  - yard-api.gemspec
193
200
  homepage: https://github.com/amireh/yard-api
194
201
  licenses: