yard-api 0.3.0 → 0.3.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: 4174d158765fdfb8f72c2625f74d77e6bff1cf27
4
- data.tar.gz: e50d4045d98142419848d2898b6a4fcf0989d9dc
3
+ metadata.gz: 57a2787c3ce762f1d68efe7aba2d1407443a7fb0
4
+ data.tar.gz: 9abaebf7932f1dffbaa3f84fe8c43cce1cf7c266
5
5
  SHA512:
6
- metadata.gz: da95663074496a8b87e5ffaa29e922b95a6d2a75f04fd64165bd9f635ea79333777f196d8ecc8f0d6725b32603b27f0bf138a518e6bf6700afec4075e6fd99db
7
- data.tar.gz: b6672a201e37c8f16829dd9f19a6836c956fb530799dbcab0cdd335a730008732a7f3d0bc8665c9bd2162f9ee991d8ee8c97946125dd977a962a1c8ddd8933c8
6
+ metadata.gz: b41c9b4518e06b4a772b846004c9f8b849526091604e6d3051d855d14caaf6ebc5ec34b557e83c4b1edd3e9b60242c670d4e345204a18a42b80a397a0930c17a
7
+ data.tar.gz: ec814f8e0e70e29a2ec528f08a1f434def22383fc41f159e25cd31eda57cd67496b1b0f8e4565c424c59125a9a75b2d6296ae33235b19a2f0ca827e027b5c98c
data/README.md CHANGED
@@ -40,6 +40,11 @@ Read that file to view all the available options.
40
40
 
41
41
  ## Changelog
42
42
 
43
+ **30/7/2015 [0.3.1]**
44
+
45
+ - Fixed a bug that was listing all the endpoints of a certain controller even if they do not have a route defined. Now, YARD-API will warn about endpoints that have an `@API` tag but could not be routed.
46
+ - Greatly improved the performance of generating the Quicklinks table.
47
+
43
48
  **29/7/2015 [0.3.0]**
44
49
 
45
50
  - major rework of the linking logic, much improvements but some stuff is broken now
@@ -1,19 +1,17 @@
1
- require 'yard/code_objects/class_object'
1
+ require 'yard/code_objects/method_object'
2
2
 
3
3
  module YARD::CodeObjects
4
4
  class APIObject < Base
5
- def path
6
- super().gsub(/\s/, '')
5
+ def self.sanitize_id(text)
6
+ text.gsub(/\s/, '')
7
7
  end
8
8
 
9
- def title
10
- [ object.title, name ].join('::')
9
+ def path
10
+ self.class.sanitize_id(super)
11
11
  end
12
- end
13
12
 
14
- class ClassObject < NamespaceObject
15
13
  def title
16
- self[:api_id] || super
14
+ [ object.title, name ].join(NSEP)
17
15
  end
18
16
  end
19
17
  end
@@ -0,0 +1,19 @@
1
+ require 'yard/code_objects/class_object'
2
+
3
+ module YARD::CodeObjects
4
+ class ClassObject < NamespaceObject
5
+ attr_reader :api_id
6
+
7
+ def api_id
8
+ @api_id ||= begin
9
+ if tag = tag('API')
10
+ tag.text.lines.first
11
+ end
12
+ end
13
+ end
14
+
15
+ def title
16
+ api_id
17
+ end
18
+ end
19
+ end
@@ -1,20 +1,14 @@
1
1
  module YARD::APIPlugin
2
- class Serializer < ::YARD::Serializers::FileSystemSerializer
3
- USNSEP = '__' # url-safe namespace separator
4
- FSSEP = '/'
2
+ class Serializer < ::YARD::Serializers::FileSystemSerializer
3
+ USNSEP = '__' # url-safe namespace separator
4
+ FSSEP = '/'
5
5
 
6
- def self.topicize(str)
7
- str.lines.first.gsub(/\W+/, '_').downcase
8
- end
6
+ def self.topicize(str)
7
+ str.lines.first.gsub(/\W+/, '_').downcase
8
+ end
9
9
 
10
10
  def serialize(object, data)
11
11
  path = File.join(basepath, serialized_path(object))
12
-
13
- if path.include?(' ')
14
- debugger
15
- end
16
-
17
- log.debug "Serializing to #{path}"
18
12
  File.open!(path, "wb") {|f| f.write data }
19
13
  end
20
14
 
@@ -27,35 +21,31 @@ module YARD::APIPlugin
27
21
  fspath = 'file.' + object.name + (extension.empty? ? '' : ".#{extension}")
28
22
  else
29
23
  fspath = if object == YARD::Registry.root
30
- "top-level-namespace"
24
+ "top-level-namespace"
31
25
  else
32
- self.class.topicize(get_api_id(object))
26
+ self.class.topicize(get_api_id(object))
33
27
  end
34
28
 
35
29
  if object.is_a?(YARD::CodeObjects::MethodObject)
36
- fspath += '_' + object.scope.to_s[0,1]
30
+ fspath += '_' + object.scope.to_s[0,1]
37
31
  end
38
32
 
39
33
  unless extension.empty?
40
- fspath += ".#{extension}"
41
- end
42
- end
43
-
44
- if (fspath.include?(' '))
45
- debugger
34
+ fspath += ".#{extension}"
35
+ end
46
36
  end
47
37
 
48
38
  fspath.gsub(/[^\w\.\-_\/]+/, '-')
49
39
  end
50
40
 
51
- def get_api_id(object)
52
- if object[:api_id]
53
- object.api_id
54
- elsif tag = object.tag(:API)
55
- tag.text.lines.first.strip
56
- else
57
- object.name.to_s
58
- end
59
- end
60
- end
41
+ def get_api_id(object)
42
+ if object[:api_id]
43
+ object.api_id
44
+ elsif tag = object.tag(:API)
45
+ tag.text.lines.first.strip
46
+ else
47
+ object.to_s
48
+ end
49
+ end
50
+ end
61
51
  end
data/lib/yard-api/tags.rb CHANGED
@@ -6,13 +6,12 @@ YARD::Tags::Library.define_tag("API response field", :request_field)
6
6
  YARD::Tags::Library.define_tag("API response field", :response_field)
7
7
  YARD::Tags::Library.define_tag("API example request", :example_request, :with_title_and_text)
8
8
  YARD::Tags::Library.define_tag("API example response", :example_response, :with_title_and_text)
9
- YARD::Tags::Library.define_tag("API subtopic", :subtopic)
10
9
  YARD::Tags::Library.define_tag("API Object Definition", :object)
11
10
  YARD::Tags::Library.define_tag("API Return Type", :returns)
12
11
  YARD::Tags::Library.define_tag("API resource is beta", :beta)
13
12
  YARD::Tags::Library.define_tag("API resource is internal", :internal)
14
13
  YARD::Tags::Library.define_tag("API empty response", :no_content)
15
- YARD::Tags::Library.define_tag("API error", :throws)
14
+ YARD::Tags::Library.define_tag("API error", :throws, :with_types)
16
15
  YARD::Tags::Library.define_tag("API warning", :warning)
17
16
  YARD::Tags::Library.define_tag("API note", :note)
18
17
  YARD::Tags::Library.define_tag("API message", :emits)
@@ -5,100 +5,23 @@ module YARD::Templates::Helpers::BaseHelper
5
5
  YARD::APIPlugin.options
6
6
  end
7
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
8
+ def lookup_appendix(title)
9
+ appendix = nil
31
10
 
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]}'"
11
+ logger.debug("Looking up appendix: #{title}")
48
12
 
49
- # unless appendix = lookup_appendix(args[1].to_s)
50
- # raise __errmsg
51
- # end
13
+ if object
14
+ # try in the object scope
15
+ appendix = YARD::Registry.at(".appendix.#{object.path}.#{title}")
52
16
 
53
- # topic, controller = *lookup_topic(appendix.namespace.to_s)
17
+ # try in the object's namespace scope
18
+ if appendix.nil? && object.respond_to?(:namespace)
19
+ appendix = YARD::Registry.at(".appendix.#{object.namespace.path}.#{title}")
20
+ end
21
+ end
54
22
 
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 do |resource, controllers|
75
- # controllers.detect do |_controller|
76
- # if _controller.path.to_s == controller_name
77
- # controller = _controller
78
- # end
79
- # end
80
- # end
81
-
82
- # [ topic, controller ]
83
- # end
84
-
85
- # def lookup_appendix(title)
86
- # appendix = nil
87
-
88
- # YARD::APIPlugin.log("Looking up appendix: #{title}") if api_options.verbose
89
-
90
- # if object
91
- # # try in the object scope
92
- # appendix = YARD::Registry.at(".appendix.#{object.path}.#{title}")
93
-
94
- # # try in the object's namespace scope
95
- # if appendix.nil? && object.respond_to?(:namespace)
96
- # appendix = YARD::Registry.at(".appendix.#{object.namespace.path}.#{title}")
97
- # end
98
- # end
99
-
100
- # appendix
101
- # end
23
+ appendix
24
+ end
102
25
 
103
26
  def tag_partial(name, tag, locals={})
104
27
  options[:tag] = tag
@@ -110,12 +33,7 @@ module YARD::Templates::Helpers::BaseHelper
110
33
  end
111
34
 
112
35
  def get_current_routes
113
- controller_name = object.parent.path.underscore
114
- controller_name.sub!("_controller", '') unless controller_name.include?('/')
115
-
116
- action = object.path.sub(/^.*#/, '').sub(/_with_.*$/, '')
117
-
118
- YARD::Templates::Helpers::RouteHelper.api_methods_for_controller_and_action(controller_name, action)
36
+ YARD::Templates::Helpers::RouteHelper.routes_for_yard_object(object)
119
37
  end
120
38
 
121
39
  def get_current_route
@@ -125,4 +43,8 @@ module YARD::Templates::Helpers::BaseHelper
125
43
  def schema_is_model?(schema)
126
44
  schema.has_key?('description') && schema.has_key?('properties')
127
45
  end
46
+
47
+ def logger
48
+ YARD::APIPlugin.logger
49
+ end
128
50
  end
@@ -5,16 +5,12 @@ module YARD::Templates::Helpers::HtmlHelper
5
5
  ::YARD::APIPlugin::Serializer.topicize(str)
6
6
  end
7
7
 
8
- def url_for_file(filename, anchor = nil)
9
- link = filename.filename
8
+ def url_for_file(file, anchor = nil)
9
+ link = file.filename
10
10
  link += (anchor ? '#' + urlencode(anchor) : '')
11
11
  link
12
12
  end
13
13
 
14
- # def url_for_api_object(name, object)
15
- # "#{object.parent.path}::#{name}"
16
- # end
17
-
18
14
  def static_pages()
19
15
  @@static_pages ||= begin
20
16
  locate_static_pages(YARD::APIPlugin.options)
@@ -61,9 +57,7 @@ module YARD::Templates::Helpers::HtmlHelper
61
57
  .capitalize
62
58
  )
63
59
 
64
- if options.verbose
65
- puts "Serializing static page #{page} (#{title})"
66
- end
60
+ logger.debug "Serializing static page #{page} (#{title})"
67
61
 
68
62
  {
69
63
  src: page,
@@ -76,10 +70,11 @@ module YARD::Templates::Helpers::HtmlHelper
76
70
 
77
71
  # override yard-appendix link_appendix
78
72
  def link_appendix(ref)
79
- puts "Linking appendix: #{ref}" if api_options.verbose
73
+ logger.debug "Linking appendix: #{ref}"
80
74
 
81
75
  unless appendix = lookup_appendix(ref.to_s)
82
- raise "Unable to locate referenced appendix '#{ref}'"
76
+ YARD::APIPlugin.on_error "Unable to locate referenced appendix '#{ref}'"
77
+ return ref
83
78
  end
84
79
 
85
80
  html_file = if options[:all_resources] && api_options.one_file
@@ -87,39 +82,23 @@ module YARD::Templates::Helpers::HtmlHelper
87
82
  elsif options[:all_resources]
88
83
  'all_resources.html'
89
84
  else
90
- topic, controller = *lookup_topic(appendix.namespace.to_s)
91
-
92
- unless topic
93
- raise "Unable to locate topic for appendix: #{ref}"
94
- end
95
-
96
- "#{topicize(topic.first)}.html"
85
+ url_for(appendix.namespace)
97
86
  end
98
87
 
99
88
  bookmark = "#{appendix.name.to_s.gsub(' ', '+')}-appendix"
100
89
  link_url("#{html_file}##{bookmark}", appendix.title).tap do |link|
101
- puts "\tAppendix link: #{link}" if api_options.verbose
90
+ logger.debug "\tAppendix link: #{link}"
102
91
  end
103
92
  end
104
93
 
105
- # TODO: this has to work with the All Resources page.
106
- def sidebar_link(title, href, options={})
107
- options[:class_name] ||= begin
108
- if object.is_a?(String) && "#{url_for(topicize(object))}.html" == href
109
- options[:class_name] = 'active'
110
- end
111
- end
112
-
113
- options[:class_name] ||= (object == href ? 'active' : nil)
114
-
115
- <<-HTML
116
- <a href="#{url_for(href)}" class="#{options[:class_name]}">#{title}</a>
117
- HTML
94
+ def sidebar_link(href, title, is_active)
95
+ link_url(href, title, { class: is_active ? 'active' : '' })
118
96
  end
119
97
 
120
98
  # Turns text into HTML using +markup+ style formatting.
121
99
  #
122
100
  # @override Syntax highlighting is not performed on the HTML block.
101
+ #
123
102
  # @param [String] text the text to format
124
103
  # @param [Symbol] markup examples are +:markdown+, +:textile+, +:rdoc+.
125
104
  # To add a custom markup type, see {MarkupHelper}
@@ -155,4 +134,23 @@ module YARD::Templates::Helpers::HtmlHelper
155
134
  tag.type
156
135
  end
157
136
  end
137
+
138
+ # @override
139
+ #
140
+ # Because we want the endpoints' URLs (an anchor part) to show up as
141
+ # "-endpoint" as opposed to "-instance_method"
142
+ def anchor_for_with_api(object)
143
+ case object
144
+ when YARD::CodeObjects::MethodObject
145
+ "#{object.name}-endpoint"
146
+ else
147
+ anchor_for_without_api(object)
148
+ end
149
+ end
150
+ alias_method :anchor_for_without_api, :anchor_for
151
+ alias_method :anchor_for, :anchor_for_with_api
152
+
153
+ def logger
154
+ YARD::APIPlugin.logger
155
+ end
158
156
  end
@@ -1,27 +1,38 @@
1
1
  module YARD::Templates::Helpers
2
2
  module RouteHelper
3
- def self.routes_for(prefix)
4
- Rails.application.routes.set
5
- end
3
+ class << self
4
+ def routes_for(prefix)
5
+ Rails.application.routes.set
6
+ end
6
7
 
7
- def self.matches_controller_and_action?(route, controller, action)
8
- route.requirements[:controller] == controller &&
9
- route.requirements[:action] == action
10
- end
8
+ def routes_for_yard_object(api_object)
9
+ controller_name = api_object.parent.path.underscore
10
+ controller_name.sub!('_controller', '') unless controller_name.include?('/')
11
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
12
+ action = api_object.path.sub(/^.*#/, '').sub(/_with_.*$/, '')
18
13
 
19
- def self.get_route_path(route)
20
- route.path.spec.to_s.gsub("(.:format)", "")
21
- end
14
+ api_methods_for_controller_and_action(controller_name, action)
15
+ end
16
+
17
+ def matches_controller_and_action?(route, controller, action)
18
+ route.requirements[:controller] == controller &&
19
+ route.requirements[:action] == action
20
+ end
21
+
22
+ def api_methods_for_controller_and_action(controller, action)
23
+ @routes ||= routes_for('/')
24
+ controller_path = [ YARD::APIPlugin.options.route_namespace, controller ].join('/')
25
+ controller_path.gsub!(/^\/|_controller$/, '')
26
+ @routes.find_all { |r| matches_controller_and_action?(r, controller_path, action) }
27
+ end
28
+
29
+ def get_route_path(route)
30
+ route.path.spec.to_s.gsub("(.:format)", "")
31
+ end
22
32
 
23
- def self.get_route_verb(route)
24
- route.verb.source =~ /\^?(\w*)\$/ ? $1.upcase : route.verb.source
33
+ def get_route_verb(route)
34
+ route.verb.source =~ /\^?(\w*)\$/ ? $1.upcase : route.verb.source
35
+ end
25
36
  end
26
37
  end
27
38
  end
@@ -3,6 +3,7 @@ module YARD
3
3
  class Verifier < ::YARD::Verifier
4
4
  def initialize(verbose=false)
5
5
  @verbose = verbose
6
+ @routes = {}
6
7
  super()
7
8
  end
8
9
 
@@ -10,10 +11,10 @@ module YARD
10
11
  relevant = list.select { |o| relevant_object?(o) }
11
12
 
12
13
  if @verbose && relevant.any?
13
- log "#{relevant.length}/#{list.length} objects are relevant:"
14
+ logger.debug "#{relevant.length}/#{list.length} objects are relevant:"
14
15
 
15
16
  relevant.each do |object|
16
- log "\t- #{object.path}"
17
+ logger.debug "\t- #{object.path}"
17
18
  end
18
19
  end
19
20
 
@@ -26,21 +27,31 @@ module YARD
26
27
  false
27
28
  when :api
28
29
  true
29
- when :method, :class
30
- return false if object.tags('internal').any?
30
+ when :method
31
+ return false if object.has_tag?(:internal) || !object.has_tag?(:API)
32
+ routes = @routes[object.object_id]
33
+ routes ||= begin
34
+ @routes[object.object_id] = YARD::Templates::Helpers::RouteHelper.routes_for_yard_object(object)
35
+ end
31
36
 
32
- object.tags('API').any?.tap do |is_api|
33
- if @verbose && !is_api
34
- log "Resource #{object} will be ignored as it contains no @API tag."
35
- end
37
+ if routes.empty?
38
+ logger.warn (
39
+ "API Endpoint #{object.path}# has no routes defined " +
40
+ "ib routes.rb and will be ignored."
41
+ )
36
42
  end
43
+
44
+ routes.any?
45
+ when :class
46
+ return false if object.has_tag?(:internal) || !object.has_tag?(:API)
47
+ true
37
48
  else
38
49
  object.parent.nil? && relevant_object?(object.parent)
39
50
  end
40
51
  end
41
52
 
42
- def log(*args)
43
- ::YARD::APIPlugin.log(*args)
53
+ def logger
54
+ ::YARD::APIPlugin.logger
44
55
  end
45
56
  end
46
57
  end
@@ -1,5 +1,5 @@
1
1
  module YARD
2
2
  module APIPlugin
3
- VERSION = "0.3.0"
3
+ VERSION = "0.3.1"
4
4
  end
5
5
  end
data/lib/yard-api.rb CHANGED
@@ -57,6 +57,7 @@ module YARD
57
57
  require 'yard-api/verifier'
58
58
  require 'yard-api/serializer'
59
59
  require 'yard-api/code_objects/api_object'
60
+ require 'yard-api/code_objects/class_object'
60
61
  require 'yard-api/templates/helpers/base_helper'
61
62
  require 'yard-api/templates/helpers/html_helper'
62
63
  require 'yard-api/templates/helpers/route_helper'
@@ -80,6 +81,8 @@ module YARD
80
81
  default_attr :argument_tags, []
81
82
  default_attr :output, nil
82
83
  default_attr :json_objects_map, {}
84
+ default_attr :endpoints, nil
85
+ default_attr :resource_name, nil
83
86
  end
84
87
  end
85
88
  end
@@ -294,6 +294,7 @@ h4 {
294
294
  .argument-listing__argument-values,
295
295
  .argument-listing__argument-required {
296
296
  display: block;
297
+ word-wrap: break-word;
297
298
  }
298
299
 
299
300
  code.argument-listing__argument-name {
@@ -380,4 +381,4 @@ code.argument-listing__argument-name {
380
381
 
381
382
  .object-synopsis__toggler:hover {
382
383
  text-decoration: underline;
383
- }
384
+ }
@@ -29,22 +29,6 @@ function makeObjectSynopsisBlocksTogglable() {
29
29
  }
30
30
 
31
31
  $(function() {
32
- $('.method-details__name').each(function(i, el) {
33
- var $a = $(el).find('a');
34
- var anchorText = $.trim($a[0].innerHTML);
35
-
36
- if (anchorText === '') {
37
- return;
38
- }
39
-
40
- var $row = $('#topicQuicklinks');
41
- var $link = $('<a/>', {
42
- href: '#' + $(el).attr('name')
43
- }).html(anchorText);
44
-
45
- $('<li>').append($link).appendTo($row);
46
- });
47
-
48
32
  $('#content pre').each(function(i, block) {
49
33
  var code;
50
34
  var $block = $(block);