Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrated markdown parsing and guide support #523

Merged
merged 1 commit into from
Jun 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ Icon
Network Trash Folder
Temporary Items
.apdisk
vendor
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
url = https://github.com/jpsim/SourceKitten.git
[submodule "spec/integration_specs"]
path = spec/integration_specs
url = https://github.com/Realm/jazzy-integration-specs.git
url = https://github.com/agentk/jazzy-integration-specs.git
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,38 @@ You can specify which theme to use by passing in the `--theme` option. You can
also provide your own custom theme by passing in the path to your theme
directory.

### Guides

| -- | -- |
| Command line option | `--documentation={file pattern}` |
| Example | `--documentation=Docs/*.md` |
| jazzy.yaml example | `documentation: Docs/*.md` |

Using the `--documentation` option, extra markdown files can be integrated into the generated docs and sidebar navigation.

Any files found matching the file pattern will be parsed and included as a document with the type 'Guide' when generated. If the files are not included using the `custom_categories` config option, they will be grouped under 'Other Guides' in the sidebar navigation.

There are a few limitations:
- File names must be unique from source files.
- Readme should be specified separately using the `readme_path` option.

### Section description abstracts

| -- | -- |
| Command line option | `--abstract={file pattern}` |
| Example | `--abstract=Docs/Sections/*.md` |
| jazzy.yaml example | `abstract: Docs/Sections/*.md` |

Using the `--abstract` options, extra markdown can be included after the heading of section overview pages. Think of it as a template include.

The list of files matching the pattern is compared against the list of sections generated and if a match is found, it's contents will be included in that section before listing source output.

Unlike the `--documentation` option, these files are not included in navigation and if a file does not match a section title, it is not included at all.

This is very helpful when using `custom_categories` for grouping types and including relevant documentation in those sections.

For an example of a project using both `--documentation` and `--abstract` see: [http://reswift.github.io/ReSwift/](http://reswift.github.io/ReSwift/)

## Troubleshooting

#### Swift
Expand Down
10 changes: 10 additions & 0 deletions lib/jazzy/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@ def expand_path(path)
description: 'The path to a markdown README file',
parse: ->(rp) { expand_path(rp) }

config_attr :documentation_glob,
command_line: '--documentation GLOB',
description: 'Glob that matches available documentation',
parse: ->(dg) { Pathname.glob(dg) }

config_attr :abstract_glob,
command_line: '--abstract GLOB',
description: 'Glob that matches available abstracts for categories',
parse: ->(ag) { Pathname.glob(ag) }

config_attr :podspec,
command_line: '--podspec FILEPATH',
parse: ->(ps) { PodspecDocumenter.create_podspec(Pathname(ps)) if ps },
Expand Down
26 changes: 16 additions & 10 deletions lib/jazzy/doc_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
require 'jazzy/config'
require 'jazzy/doc'
require 'jazzy/docset_builder'
require 'jazzy/documentation_generator'
require 'jazzy/jazzy_markdown'
require 'jazzy/podspec_documenter'
require 'jazzy/readme_generator'
require 'jazzy/source_declaration'
require 'jazzy/source_document'
require 'jazzy/source_module'
require 'jazzy/sourcekitten'

Expand Down Expand Up @@ -91,7 +93,7 @@ def self.build_docs(output_dir, docs, source_module)

def self.each_doc(output_dir, docs, &block)
docs.each do |doc|
next if doc.name != 'index' && doc.children.count == 0
next unless doc.render?
# Assuming URL is relative to documentation root:
path = output_dir + (doc.url || "#{doc.name}.html")
block.call(doc, path)
Expand All @@ -109,9 +111,11 @@ def self.build_site(docs, coverage, options)

structure = doc_structure_for_docs(docs)

docs << SourceDeclaration.new.tap do |sd|
docs << SourceDocument.new.tap do |sd|
sd.name = 'index'
sd.children = []
sd.type = SourceDeclaration::Type.new 'document.markdown'
sd.readme_path = options.readme_path
end

source_module = SourceModule.new(options, docs, structure, coverage)
Expand All @@ -138,7 +142,7 @@ def self.build_docs_for_sourcekitten_output(sourcekitten_output, options)
sourcekitten_output,
options.min_acl,
options.skip_undocumented,
)
DocumentationGenerator.source_docs)

prepare_output_dir(options.output, options.clean)
write_lint_report(undocumented, options)
Expand Down Expand Up @@ -238,15 +242,17 @@ def self.copy_assets(destination)
end
end

# Build index Mustache document
# Build Mustache document from a markdown source file
# @param [Config] options Build options
# @param [Hash] doc_model Parsed doc. @see SourceKitten.parse
# @param [String] path_to_root
# @param [Array] doc_structure doc structure comprised of section names and
# child names and URLs. @see doc_structure_for_docs
def self.document_index(source_module, path_to_root)
def self.document_markdown(source_module, doc_model, path_to_root)
doc = Doc.new # Mustache model instance
doc[:name] = source_module.name
doc[:overview] = ReadmeGenerator.generate(source_module)
name = doc_model.name == 'index' ? source_module.name : doc_model.name
doc[:name] = name
doc[:overview] = Jazzy.markdown.render(doc_model.content(source_module))
doc[:custom_head] = Config.instance.custom_head
doc[:doc_coverage] = source_module.doc_coverage unless
Config.instance.hide_documentation_coverage
Expand Down Expand Up @@ -326,7 +332,7 @@ def self.make_task(mark, uid, items)
# @param [Config] options Build options
# @param [Hash] doc_model Parsed doc. @see SourceKitten.parse
def self.render_tasks(source_module, children)
marks = children.map(&:mark).uniq
marks = children.map(&:mark).uniq.compact
mark_names_counts = {}
marks.map do |mark|
mark_children = children.select { |child| child.mark == mark }
Expand All @@ -349,8 +355,8 @@ def self.render_tasks(source_module, children)
# @param [Array] doc_structure doc structure comprised of section names and
# child names and URLs. @see doc_structure_for_docs
def self.document(source_module, doc_model, path_to_root)
if doc_model.name == 'index'
return document_index(source_module, path_to_root)
if doc_model.type.kind == 'document.markdown'
return document_markdown(source_module, doc_model, path_to_root)
end

doc = Doc.new # Mustache model instance
Expand Down
38 changes: 38 additions & 0 deletions lib/jazzy/documentation_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'pathname'

require 'jazzy/jazzy_markdown'
require 'jazzy/source_document'

module Jazzy
module DocumentationGenerator
extend Config::Mixin

def self.source_docs
documentation_entries.map do |file_path|
SourceDocument.new.tap do |sd|
sd.name = File.basename(file_path, '.md')
sd.url = sd.name.downcase.strip
.tr(' ', '-').gsub(/[^\w-]/, '') + '.html'
sd.type = SourceDeclaration::Type.new 'document.markdown'
sd.children = []
sd.overview = overview Pathname(file_path)
sd.usr = 'documentation.' + sd.name
sd.abstract = ''
sd.return = ''
sd.parameters = []
end
end
end

def self.overview(file_path)
return '' unless file_path && file_path.exist?
file_path.read
end

def self.documentation_entries
return [] unless
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it would make sense to filter files named index.* here too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably wouldn't hurt, but I'm not sure if it's necessary there. Without it, it makes it possible to override the readme and have it included in the Dash Guides section.

config.documentation_glob_configured && config.documentation_glob
config.documentation_glob.select { |e| File.file? e }
end
end
end
29 changes: 28 additions & 1 deletion lib/jazzy/source_declaration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ class SourceDeclaration
# static type of declared element (e.g. String.Type -> ())
attr_accessor :typename

def type?(type_kind)
respond_to?(:type) && type.kind == type_kind
end

def render?
type?('document.markdown') || children.count != 0
end

# Element containing this declaration in the code
attr_accessor :parent_in_code

Expand Down Expand Up @@ -69,7 +77,26 @@ def objc_category_name
attr_accessor :nav_order

def overview
"#{abstract}\n\n#{discussion}".strip
alternative_abstract || "#{abstract}\n\n#{discussion}".strip
end

def alternative_abstract
if file = alternative_abstract_file
Pathname(file).read
end
end

def alternative_abstract_file
abstract_glob.select do |f|
File.basename(f).split('.').first == name
end.first
end

def abstract_glob
return [] unless
Config.instance.abstract_glob_configured &&
Config.instance.abstract_glob
Config.instance.abstract_glob.select { |e| File.file? e }
end
end
end
7 changes: 6 additions & 1 deletion lib/jazzy/source_declaration/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,13 @@ def ==(other)
end

TYPES = {
# Objective-C
# Markdown
'document.markdown' => {
jazzy: 'Guide',
dash: 'Guide',
}.freeze,

# Objective-C
'sourcekitten.source.lang.objc.decl.unexposed' => {
jazzy: 'Unexposed',
dash: 'Unexposed',
Expand Down
72 changes: 72 additions & 0 deletions lib/jazzy/source_document.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
require 'pathname'

require 'jazzy/jazzy_markdown'

module Jazzy
class SourceDocument < SourceDeclaration
attr_accessor :overview
attr_accessor :readme_path

def config
Config.instance
end

def url
name.downcase.strip.tr(' ', '-').gsub(/[^\w-]/, '') + '.html'
end

def content(source_module)
return readme_content(source_module) if name == 'index'
overview
end

def readme_content(source_module)
config_readme || fallback_readme || generated_readme(source_module)
end

def config_readme
readme_path.read if readme_path && readme_path.exist?
end

def fallback_readme
%w(README.md README.markdown README.mdown README).each do |potential_name|
file = config.source_directory + potential_name
return file.read if file.exist?
end
false
end

def generated_readme(source_module)
if podspec = config.podspec
### License

# <a href="#{license[:url]}">#{license[:license]}</a>
<<-EOS
# #{podspec.name}

### #{podspec.summary}

#{podspec.description}

### Installation

```ruby
pod '#{podspec.name}'
```

### Authors

#{source_module.author_name}
EOS
else
<<-EOS
# #{source_module.name}

### Authors

#{source_module.author_name}
EOS
end
end
end
end
2 changes: 1 addition & 1 deletion lib/jazzy/source_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def all_declarations
d.map(&:children).each { |c| visitor[c] }
end
visitor[docs]
all_declarations
all_declarations.select { |doc| doc.name != 'index' }
end
end
end
4 changes: 2 additions & 2 deletions lib/jazzy/sourcekitten.rb
Original file line number Diff line number Diff line change
Expand Up @@ -493,11 +493,11 @@ def self.reject_objc_enum_typedefs(docs)

# Parse sourcekitten STDOUT output as JSON
# @return [Hash] structured docs
def self.parse(sourcekitten_output, min_acl, skip_undocumented)
def self.parse(sourcekitten_output, min_acl, skip_undocumented, inject_docs)
@min_acl = min_acl
@skip_undocumented = skip_undocumented
sourcekitten_json = filter_excluded_files(JSON.parse(sourcekitten_output))
docs = make_source_declarations(sourcekitten_json)
docs = make_source_declarations(sourcekitten_json).concat inject_docs
docs = ungrouped_docs = deduplicate_declarations(docs)
docs = group_docs(docs)
if Config.instance.objc_mode
Expand Down
2 changes: 1 addition & 1 deletion spec/integration_specs