plugin.rb 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. require 'yard'
  2. require 'yard-go'
  3. module GoLinksHelper
  4. def signature(obj, link = true, show_extras = true, full_attr_name = true)
  5. case obj
  6. when YARDGo::CodeObjects::FuncObject
  7. if link && obj.has_tag?(:service_operation)
  8. ret = signature_types(obj, !link)
  9. args = obj.parameters.map {|m| m[0].split(/\s+/).last }.join(", ")
  10. line = "<strong>#{obj.name}</strong>(#{args}) #{ret}"
  11. return link ? linkify(obj, line) : line
  12. end
  13. end
  14. super(obj, link, show_extras, full_attr_name)
  15. end
  16. def html_syntax_highlight(source, type = nil)
  17. src = super(source, type || :go)
  18. object.has_tag?(:service_operation) ? link_types(src) : src
  19. end
  20. end
  21. YARD::Templates::Helpers::HtmlHelper.send(:prepend, GoLinksHelper)
  22. YARD::Templates::Engine.register_template_path(File.dirname(__FILE__) + '/templates')
  23. YARD::Parser::SourceParser.after_parse_list do
  24. YARD::Registry.all(:struct).each do |obj|
  25. if obj.file =~ /\/?service\/(.+?)\/(service|api)\.go$/
  26. obj.add_tag YARD::Tags::Tag.new(:service, $1)
  27. obj.groups = ["Constructor Functions", "Service Operations", "Request Methods", "Pagination Methods"]
  28. end
  29. end
  30. YARD::Registry.all(:method).each do |obj|
  31. if obj.file =~ /service\/.+?\/api\.go$/ && obj.scope == :instance
  32. if obj.name.to_s =~ /Pages$/
  33. obj.group = "Pagination Methods"
  34. opname = obj.name.to_s.sub(/Pages$/, '')
  35. obj.docstring = <<-eof
  36. #{obj.name} iterates over the pages of a {#{opname} #{opname}()} operation, calling the `fn`
  37. function callback with the response data in each page. To stop iterating, return `false` from
  38. the function callback.
  39. @note This operation can generate multiple requests to a service.
  40. @example Iterating over at most 3 pages of a #{opname} operation
  41. pageNum := 0
  42. err := client.#{obj.name}(params, func(page *#{obj.parent.parent.name}.#{obj.parameters[1][0].split("*").last}, lastPage bool) bool {
  43. pageNum++
  44. fmt.Println(page)
  45. return pageNum <= 3
  46. })
  47. @see #{opname}
  48. eof
  49. obj.add_tag YARD::Tags::Tag.new(:paginator, '')
  50. elsif obj.name.to_s =~ /Request$/
  51. obj.group = "Request Methods"
  52. obj.signature = obj.name.to_s
  53. obj.parameters = []
  54. opname = obj.name.to_s.sub(/Request$/, '')
  55. obj.docstring = <<-eof
  56. #{obj.name} generates a {aws/request.Request} object representing the client request for
  57. the {#{opname} #{opname}()} operation. The `output` return value can be used to capture
  58. response data after {aws/request.Request.Send Request.Send()} is called.
  59. Creating a request object using this method should be used when you want to inject
  60. custom logic into the request lifecycle using a custom handler, or if you want to
  61. access properties on the request object before or after sending the request. If
  62. you just want the service response, call the {#{opname} service operation method}
  63. directly instead.
  64. @note You must call the {aws/request.Request.Send Send()} method on the returned
  65. request object in order to execute the request.
  66. @example Sending a request using the #{obj.name}() method
  67. req, resp := client.#{obj.name}(params)
  68. err := req.Send()
  69. if err == nil { // resp is now filled
  70. fmt.Println(resp)
  71. }
  72. eof
  73. obj.add_tag YARD::Tags::Tag.new(:request_method, '')
  74. else
  75. obj.group = "Service Operations"
  76. obj.add_tag YARD::Tags::Tag.new(:service_operation, '')
  77. if ex = obj.tag(:example)
  78. ex.name = "Calling the #{obj.name} operation"
  79. end
  80. end
  81. end
  82. end
  83. apply_docs
  84. end
  85. def apply_docs
  86. svc_pkg = YARD::Registry.at('service')
  87. return if svc_pkg.nil?
  88. pkgs = svc_pkg.children.select {|t| t.type == :package }
  89. pkgs.each do |pkg|
  90. svc = pkg.children.find {|t| t.has_tag?(:service) }
  91. ctor = P(svc, ".New")
  92. svc_name = ctor.source[/ServiceName:\s*"(.+?)",/, 1]
  93. api_ver = ctor.source[/APIVersion:\s*"(.+?)",/, 1]
  94. log.progress "Parsing service documentation for #{svc_name} (#{api_ver})"
  95. file = Dir.glob("apis/#{svc_name}/#{api_ver}/docs-2.json").sort.last
  96. next if file.nil?
  97. next if svc.nil?
  98. exmeth = svc.children.find {|s| s.has_tag?(:service_operation) }
  99. pkg.docstring += <<-eof
  100. @example Sending a request using the {#{svc.name}} client
  101. client := #{pkg.name}.New(nil)
  102. params := &#{pkg.name}.#{exmeth.parameters.first[0].split("*").last}{...}
  103. resp, err := client.#{exmeth.name}(params)
  104. @see #{svc.name}
  105. @version #{api_ver}
  106. eof
  107. ctor.docstring += <<-eof
  108. @example Constructing a client using default configuration
  109. client := #{pkg.name}.New(nil)
  110. @example Constructing a client with custom configuration
  111. config := aws.NewConfig().WithRegion("us-west-2")
  112. client := #{pkg.name}.New(config)
  113. eof
  114. json = JSON.parse(File.read(file))
  115. if svc
  116. apply_doc(svc, json["service"])
  117. end
  118. json["operations"].each do |op, doc|
  119. if doc && obj = svc.children.find {|t| t.name.to_s.downcase == op.downcase }
  120. apply_doc(obj, doc)
  121. end
  122. end
  123. json["shapes"].each do |shape, data|
  124. shape = shape_name(shape)
  125. if obj = pkg.children.find {|t| t.name.to_s.downcase == shape.downcase }
  126. apply_doc(obj, data["base"])
  127. end
  128. data["refs"].each do |refname, doc|
  129. refshape, member = *refname.split("$")
  130. refshape = shape_name(refshape)
  131. if refobj = pkg.children.find {|t| t.name.to_s.downcase == refshape.downcase }
  132. if m = refobj.children.find {|t| t.name.to_s.downcase == member.downcase }
  133. apply_doc(m, doc || data["base"])
  134. end
  135. end
  136. end if data["refs"]
  137. end
  138. end
  139. end
  140. def apply_doc(obj, doc)
  141. tags = obj.docstring.tags || []
  142. obj.docstring = clean_docstring(doc)
  143. tags.each {|t| obj.docstring.add_tag(t) }
  144. end
  145. def shape_name(shape)
  146. shape.sub(/Request$/, "Input").sub(/Response$/, "Output")
  147. end
  148. def clean_docstring(docs)
  149. return nil unless docs
  150. docs = docs.gsub(/<!--.*?-->/m, '')
  151. docs = docs.gsub(/<fullname>.+?<\/fullname?>/m, '')
  152. docs = docs.gsub(/<examples?>.+?<\/examples?>/m, '')
  153. docs = docs.gsub(/<note>\s*<\/note>/m, '')
  154. docs = docs.gsub(/<a>(.+?)<\/a>/, '\1')
  155. docs = docs.gsub(/<note>(.+?)<\/note>/m) do
  156. text = $1.gsub(/<\/?p>/, '')
  157. "<div class=\"note\"><strong>Note:</strong> #{text}</div>"
  158. end
  159. docs = docs.gsub(/\{(.+?)\}/, '`{\1}`')
  160. docs = docs.gsub(/\s+/, ' ').strip
  161. docs == '' ? nil : docs
  162. end