lib/rtfdoc.rb in rtfdoc-0.1.3 vs lib/rtfdoc.rb in rtfdoc-0.1.4
- old
+ new
@@ -5,19 +5,33 @@
require 'rtfdoc/version'
module RTFDoc
class AttributesComponent
+ # Needed because we can't call the same rendered within itself.
+ def self.private_renderer
+ @renderer ||= Redcarpet::Markdown.new(::RTFDoc::Renderer, {
+ underline: true,
+ space_after_headers: true,
+ fenced_code_blocks: true,
+ no_intra_emphasis: true
+ })
+ end
+
def initialize(raw_attrs, title)
@attributes = YAML.load(raw_attrs)
@title = title
end
template = Erubi::Engine.new(File.read(File.expand_path('../src/attributes.erb', __dir__)))
class_eval <<-RUBY
define_method(:output) { #{template.src} }
RUBY
+
+ def to_html(text)
+ self.class.private_renderer.render(text) if text
+ end
end
class Renderer < Redcarpet::Render::Base
attr_reader :rouge_formatter, :rouge_lexer
@@ -37,10 +51,14 @@
def paragraph(text)
"<p>#{text}</p>"
end
+ def link(link, title, content)
+ %(<a title="#{title}" href="#{link}">#{content}</a>)
+ end
+
def header(text, level)
if level == 4
%(<div class="header-table">#{text}</div>)
else
"<h#{level}>#{text}</h#{level}>"
@@ -111,21 +129,53 @@
end
class Template
attr_reader :app_name, :page_title
- def initialize(sections, config)
- @content = sections.map(&:output).join
- @menu_content = sections.map(&:menu_output).join
+ def initialize(nodes, config)
+ @content = nodes.flat_map(&:output).join
+ # @menu_content = nodes.map(&:menu_output).join
@app_name = config['app_name']
@page_title = config['title']
+
+ generate_grouped_menu_content(nodes)
end
def output
template = Erubi::Engine.new(File.read(File.expand_path('../src/index.html.erb', __dir__)))
eval(template.src)
end
+
+ private
+
+ # Transform a list of nodes into a list of groups. If all nodes already are groups, it will
+ # return the same list. Otherwise, it will build group from consecutives single resources.
+ def generate_grouped_menu_content(nodes)
+ i = 0
+ res = []
+
+ while i < nodes.length
+ node = nodes[i]
+ if node.is_a?(Group)
+ res << node
+ i += 1
+ else
+ inner = []
+ j = i
+ while node && !node.is_a?(Group)
+ inner << node
+ j += 1
+ node = nodes[j]
+ end
+
+ res << Group.new(nil, inner)
+ i = j
+ end
+ end
+
+ @menu_content = res.map(&:menu_output).join
+ end
end
module RenderAsSection
def self.included(other)
other.attr_accessor(:include_show_button)
@@ -245,20 +295,22 @@
def anchor_id
"#{resource_name}-desc"
end
def generate_example(sections)
- endpoints = sections.reject { |s| s.name == 'desc' || s.name == 'object' }
+ endpoints = sections.reject { |s| s.is_a?(Scope) || s.name == 'desc' || s.name == 'object' }
signatures = endpoints.each_with_object("") do |e, res|
res << %(<div class="resource-sig">#{e.signature}</div>)
end
+ scopes = sections.select { |s| s.is_a?(Scope) }.map!(&:generate_example).join("\n")
@example = <<-HTML
<div class="section-response">
<div class="response-topbar">ENDPOINTS</div>
<div class="section-endpoints">#{signatures}</div>
</div>
+ #{scopes}
HTML
end
def example_to_html
@example
@@ -271,10 +323,29 @@
def self.build(name, paths, endpoints: nil)
endpoints ||= DEFAULT
desc = nil
sections = endpoints.each_with_object([]) do |endpoint, res|
+ if endpoint.is_a?(Hash)
+ n, values = endpoint.each_pair.first
+ next unless n.start_with?('scope|')
+ dir_name = n.slice(6..-1)
+
+ scope_name = values['title'] || dir_name
+ scoped_endpoints = values['endpoints']
+
+ subsections = scoped_endpoints.each_with_object([]) do |e, r|
+ filename = paths.dig(dir_name, e)
+ next unless filename
+ content = File.read(filename)
+ r << Section.new(e, content, resource: name)
+ end
+
+ res << Scope.new(scope_name, subsections)
+ next res
+ end
+
filename = paths[endpoint]
next unless filename
content = File.read(filename)
@@ -298,53 +369,133 @@
def output
head, *tail = sections
head.include_show_button = true
- inner = sections.map(&:output).join("\n")
+ inner = sections.flat_map(&:output).join("\n")
%(<section class="head-section">#{inner}</section>)
end
def menu_output
head, *tail = sections
<<-HTML
<li data-anchor="#{name}">
- #{head.anchor(name.capitalize, class_list: 'expandable')}
+ #{head.anchor(human_name, class_list: 'expandable')}
<ul>#{tail.map(&:menu_output).join}</ul>
</li>
HTML
end
+
+ private
+
+ def human_name
+ name.tr('_', ' ').split.map!(&:capitalize).join(' ')
+ end
end
+ class Group
+ attr_reader :name, :resources
+
+ def initialize(name, resources, options = {})
+ @name = name
+ @resources = resources
+
+ sorted = true
+ sorted = options['sort'] if options.key?('sort')
+ @resources.sort! { |a, b| a.name <=> b.name } if sorted
+ end
+
+ def output
+ resources.map(&:output)
+ end
+
+ def menu_output
+ title = "<h5 class=\"nav-group-title\">#{name}</h5>" if name && name.length > 0
+
+ <<-HTML
+ <div class="sidebar-nav-group">
+ #{title}
+ <ul>#{resources.map(&:menu_output).join}</ul>
+ </div>
+ HTML
+ end
+ end
+
+ class Scope
+ attr_reader :name, :sections
+
+ def initialize(name, sections)
+ @name = name
+ @sections = sections
+ end
+
+ def output
+ sections.map(&:output)
+ end
+
+ def menu_output
+ <<-HTML
+ <li>
+ <div class="scope-title">#{name}</div>
+ <ul class="scoped">#{sections.map(&:menu_output).join}</ul>
+ </li>
+ HTML
+ end
+
+ def generate_example
+ signatures = sections.each_with_object("") do |s, res|
+ res << %(<div class="resource-sig">#{s.signature}</div>)
+ end
+
+ <<-HTML
+ <div class="section-response">
+ <div class="response-topbar">#{name} ENDPOINTS</div>
+ <div class="section-endpoints">#{signatures}</div>
+ </div>
+ HTML
+ end
+ end
+
class Generator
attr_reader :renderer, :config
def initialize(config_path)
@config = YAML.load_file(config_path)
@content_dir = @config['content_dir']
@parts = {}
end
def run
- tree = build_content_tree
+ @tree = build_content_tree
+ nodes = build_nodes(config['resources'])
- nodes = config['resources'].map do |rs|
- if rs.is_a?(Hash)
- name, endpoints = rs.each_pair.first
- paths = tree[name]
- Resource.build(name, paths, endpoints: endpoints)
- else
- paths = tree[rs]
- paths.is_a?(Hash) ? Resource.build(rs, paths) : Section.new(rs, File.read(paths))
- end
- end
-
out = File.new("#{Dir.tmpdir}/rtfdoc_output.html", 'w')
out.write(Template.new(nodes, config).output)
out.close
end
private
+
+ def build_nodes(ary, allow_groups: true)
+ ary.map do |rs|
+ if rs.is_a?(Hash)
+ name, values = rs.each_pair.first
+
+ if name.start_with?('group|')
+ raise 'Nested groups are not yet supported' if !allow_groups
+
+ group_name = values.key?('title') ? values['title'] : name.slice(6..-1)
+ Group.new(group_name, build_nodes(values['resources'], allow_groups: false), values)
+ else
+ paths = @tree[name]
+ Resource.build(name, paths, endpoints: values)
+ end
+ else
+ paths = @tree[rs]
+ paths.is_a?(Hash) ? Resource.build(rs, paths) : Section.new(rs, File.read(paths))
+ end
+ end
+ end
def build_content_tree
tree = {}
slicer = (@content_dir.length + 1)..-1
ext_slicer = -3..-1