├── Gemfile ├── test ├── test_helper.rb ├── fixtures │ ├── octicon.md │ ├── block_octicon.md │ ├── intro.md │ ├── block_intro.md │ ├── command_line.md │ ├── command_line_indented.md │ ├── os_blocks.md │ ├── block_os_blocks.md │ ├── command_line_nested.md │ ├── admonition.md │ ├── block_admonition.md │ └── helper.md └── test_extended_markdown_filter.rb ├── .rubocop.yml ├── .gitignore ├── lib ├── filters │ ├── post │ │ ├── octicon.rb │ │ ├── intro.rb │ │ ├── os-blocks.rb │ │ ├── admonition.rb │ │ └── command-line.rb │ ├── filters.rb │ └── pre │ │ └── helper.rb ├── jekyll-override.rb └── extended-markdown-filter.rb ├── Rakefile ├── .travis.yml ├── LICENSE.txt ├── extended-markdown-filter.gemspec └── README.md /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | require 'minitest/autorun' 4 | 5 | require 'extended-markdown-filter' 6 | 7 | require 'pry' 8 | -------------------------------------------------------------------------------- /test/fixtures/octicon.md: -------------------------------------------------------------------------------- 1 | {{ octicon-cat This is a cat }} 2 | 3 | {{ octicon dog This is nothing. }} 4 | 5 | [Click {{ octicon-gear Settings }}](http://alink.com) 6 | -------------------------------------------------------------------------------- /test/fixtures/block_octicon.md: -------------------------------------------------------------------------------- 1 | [[ octicon-cat This is a cat ]] 2 | 3 | [[ octicon dog This is nothing. ]] 4 | 5 | [Click [[ octicon-gear Settings ]]](http://alink.com) 6 | -------------------------------------------------------------------------------- /test/fixtures/intro.md: -------------------------------------------------------------------------------- 1 | {{#intro}} 2 | 3 | [Gists](https://gist.github.com) are a great way to share your work. You can share single files, parts of files, or full applications. 4 | 5 | {{/intro}} 6 | -------------------------------------------------------------------------------- /test/fixtures/block_intro.md: -------------------------------------------------------------------------------- 1 | [[#intro]] 2 | 3 | [Gists](https://gist.github.com) are a great way to share your work. You can share single files, parts of files, or full applications. 4 | 5 | [[/intro]] 6 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_gem: 2 | rubocop-github: 3 | - config/default.yml 4 | 5 | Style/StringLiterals: 6 | Enabled: true 7 | EnforcedStyle: single_quotes 8 | 9 | Naming/FileName: 10 | Enabled: false 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | .byebug_history 19 | -------------------------------------------------------------------------------- /lib/filters/post/octicon.rb: -------------------------------------------------------------------------------- 1 | module Filters 2 | module PostFilter 3 | def format_octicons!(html) 4 | html.gsub!(/#{@front_wrap}\s*octicon-(\S+)\s*([^\\#{@wrap_symbol}]+)\s*#{@end_wrap}/, %||) 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/filters/filters.rb: -------------------------------------------------------------------------------- 1 | module Filters 2 | CLOSE_DIV = '' 3 | end 4 | 5 | Dir[File.join(File.expand_path(File.dirname(__FILE__)), 'pre', '*.rb')].each do |file| 6 | require file 7 | end 8 | 9 | Dir[File.join(File.expand_path(File.dirname(__FILE__)), 'post', '*.rb')].each do |file| 10 | require file 11 | end 12 | -------------------------------------------------------------------------------- /test/fixtures/command_line.md: -------------------------------------------------------------------------------- 1 | # Header 2 | 3 | ``` command-line 4 | $ git remote add origin https://github.com/user/repo.git 5 | # Set a new remote 6 | > origin https://github.com/user/repo.git 7 | $ git remote add -f spoon-knife git@github.com:octocat/Spoon-Knife.git 8 | ``` 9 | 10 | next paragraph 11 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | 3 | task default: [:test] 4 | 5 | require 'rake/testtask' 6 | Rake::TestTask.new(:test) do |test| 7 | test.libs << 'lib' << 'test' 8 | test.pattern = 'test/**/test_*.rb' 9 | test.verbose = true 10 | end 11 | 12 | require 'rubocop/rake_task' 13 | 14 | RuboCop::RakeTask.new(:rubocop) 15 | -------------------------------------------------------------------------------- /lib/filters/post/intro.rb: -------------------------------------------------------------------------------- 1 | module Filters 2 | module PostFilter 3 | INTRO_HTML = '
' 4 | 5 | def format_intro!(html) 6 | html.gsub!(/

#{@front_wrap}#intro#{@end_wrap}<\/p>/, INTRO_HTML) 7 | html.gsub!(/

#{@front_wrap}\/intro#{@end_wrap}<\/p>/, Filters::CLOSE_DIV) 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/fixtures/command_line_indented.md: -------------------------------------------------------------------------------- 1 | # Header 2 | 3 | ``` command-line 4 | $ git remote add origin https://github.com/user/repo.git 5 | # Set a new remote 6 | > origin https://github.com/user/repo.git 7 | $ git remote add -f spoon-knife git@github.com:octocat/Spoon-Knife.git 8 | ``` 9 | 10 | next paragraph 11 | -------------------------------------------------------------------------------- /test/fixtures/os_blocks.md: -------------------------------------------------------------------------------- 1 | {{#mac}} 2 | 3 | 1. [Create a new repository](/articles/creating-a-new-repository). 4 | 5 | {{/mac}} 6 | 7 | {{#windows}} 8 | 9 | 1. [Try to create a new repository](/articles/creating-a-new-repository). 10 | 11 | {{/windows}} 12 | 13 | {{#linux}} 14 | 15 | 1. You *already* know what you're doing. 16 | 17 | {{/linux}} 18 | 19 | {{#all}} 20 | 21 | What? 22 | 23 | {{/all}} 24 | -------------------------------------------------------------------------------- /test/fixtures/block_os_blocks.md: -------------------------------------------------------------------------------- 1 | [[#mac]] 2 | 3 | 1. [Create a new repository](/articles/creating-a-new-repository). 4 | 5 | [[/mac]] 6 | 7 | [[#windows]] 8 | 9 | 1. [Try to create a new repository](/articles/creating-a-new-repository). 10 | 11 | [[/windows]] 12 | 13 | [[#linux]] 14 | 15 | 1. You *already* know what you're doing. 16 | 17 | [[/linux]] 18 | 19 | [[#all]] 20 | 21 | What? 22 | 23 | [[/all]] 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.3.6 4 | - 2.4.3 5 | - 2.5.0 6 | 7 | git: 8 | depth: 10 9 | 10 | sudo: false 11 | 12 | # we need a more recent cmake than travis/linux provides (at least 2.8.9): 13 | addons: 14 | apt: 15 | sources: 16 | - kalakris-cmake 17 | packages: 18 | - cmake 19 | 20 | cache: bundler 21 | 22 | matrix: 23 | include: 24 | - script: bundle exec rake rubocop 25 | rvm: 2.5.0 26 | -------------------------------------------------------------------------------- /test/fixtures/command_line_nested.md: -------------------------------------------------------------------------------- 1 | 2. Create a bare clone of the repository. 2 | ``` command-line 3 | $ git clone --bare https://{{ site.data.variables.command_line.codeblock }}/exampleuser/old-repository.git 4 | ``` 5 | 3. Mirror-push to the new repository. 6 | ``` command-line 7 | $ cd old-repository.git 8 | $ git push --mirror https://{{ site.data.variables.command_line.codeblock }}/exampleuser/new-repository.git 9 | ``` 10 | -------------------------------------------------------------------------------- /test/fixtures/admonition.md: -------------------------------------------------------------------------------- 1 | {{#tip}} 2 | 3 | Here's a hot tip: **line one** 4 | Here's a hot tip: line two 5 | 6 | {{/tip}} 7 | 8 | {{#note}} 9 | 10 | This is something you should know! line one 11 | This is something you should know! line two 12 | 13 | {{/note}} 14 | 15 | {{#warning}} 16 | 17 | Yo, check this out: line one 18 | Yo, check this out: line two 19 | 20 | {{/warning}} 21 | 22 | {{#danger}} 23 | 24 | Sheeeeit, this is a problem: ~~line one~~ 25 | Sheeeeit, this is a problem: line two 26 | 27 | {{/danger}} 28 | -------------------------------------------------------------------------------- /test/fixtures/block_admonition.md: -------------------------------------------------------------------------------- 1 | [[#tip]] 2 | 3 | Here's a hot tip: **line one** 4 | Here's a hot tip: line two 5 | 6 | [[/tip]] 7 | 8 | [[#note]] 9 | 10 | This is something you should know! line one 11 | This is something you should know! line two 12 | 13 | [[/note]] 14 | 15 | [[#warning]] 16 | 17 | Yo, check this out: line one 18 | Yo, check this out: line two 19 | 20 | [[/warning]] 21 | 22 | [[#danger]] 23 | 24 | Sheeeeit, this is a problem: ~~line one~~ 25 | Sheeeeit, this is a problem: line two 26 | 27 | [[/danger]] 28 | -------------------------------------------------------------------------------- /test/fixtures/helper.md: -------------------------------------------------------------------------------- 1 | 2 | ``` helper 3 | #### A note about Sync in GitHub for Mac 4 | 5 | Those that are already familiar with Git may notice that there are no "Push" or "Pull" buttons in GitHub for Mac. 6 | 7 | Instead of bringing in new changes from the remote copy with one command and pushing your unpublished commits with another, GitHub for Mac uses a single "Sync" button that quickly completes both operations at the same. Behind the scenes, we do the equivalent of a `git pull --rebase` (but make sure to never rewrite merges). 8 | ``` 9 | -------------------------------------------------------------------------------- /lib/filters/pre/helper.rb: -------------------------------------------------------------------------------- 1 | module Filters 2 | module PreFilter 3 | def format_helper(text) 4 | prefix = '#{@front_wrap}#mac#{@end_wrap}<\/p>/, MAC_HTML) 10 | html.gsub!(/

#{@front_wrap}#windows#{@end_wrap}<\/p>/, WIN_HTML) 11 | html.gsub!(/

#{@front_wrap}#linux#{@end_wrap}<\/p>/, LINUX_HTML) 12 | html.gsub!(/

#{@front_wrap}#all#{@end_wrap}<\/p>/, ALL_HTML) 13 | html.gsub!(/

#{@front_wrap}\/(mac|windows|linux|all)#{@end_wrap}<\/p>/, Filters::CLOSE_DIV) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/filters/post/admonition.rb: -------------------------------------------------------------------------------- 1 | module Filters 2 | module PostFilter 3 | TIP_HTML = '

' 4 | NOTE_HTML = '
' 5 | WARNING_HTML = '
' 6 | DANGER_HTML = '
' 7 | 8 | def format_admonitions!(html) 9 | html.gsub!(/

#{@front_wrap}#tip#{@end_wrap}<\/p>/, TIP_HTML) 10 | html.gsub!(/

#{@front_wrap}#note#{@end_wrap}<\/p>/, NOTE_HTML) 11 | html.gsub!(/

#{@front_wrap}#warning#{@end_wrap}<\/p>/, WARNING_HTML) 12 | html.gsub!(/

#{@front_wrap}#danger#{@end_wrap}<\/p>/, DANGER_HTML) 13 | html.gsub!(/

#{@front_wrap}\/(tip|note|warning|danger)#{@end_wrap}<\/p>/, Filters::CLOSE_DIV) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/filters/post/command-line.rb: -------------------------------------------------------------------------------- 1 | module Filters 2 | module PostFilter 3 | def format_command_line!(html) 4 | html.gsub!(/

``` command-line\n/, "
\n")
 5 |       html.gsub!(/
/, "
\n")
 6 | 
 7 |       html.gsub! /^\n?\s*
(.+?)<\/pre>/m do |block|
 8 |         block.gsub!(/<\/*code>/, '')
 9 |         block.gsub!(/```/, '')
10 |         block.gsub!(/^\s*\$ (.+)$/) { %(#{$1.rstrip}) }
11 |         block.gsub!(/^\s*(\# .+)$/) { %(#{$1.rstrip}) }
12 |         block.gsub!(/^\s*> (.+)$/) { %(#{$1.rstrip}) }
13 |         block.gsub!(/</, '<')
14 |         block.gsub!(/>/, '>')
15 | 
16 |         block
17 |       end
18 |     end
19 |   end
20 | end
21 | 


--------------------------------------------------------------------------------
/lib/jekyll-override.rb:
--------------------------------------------------------------------------------
 1 | # Liquid disregards tags it doesn't know,
 2 | # so rather than define a new format for additions like {{#tip}},
 3 | # we'll convert them to bracket form
 4 | module Jekyll
 5 |   class Renderer
 6 |     alias_method :old_run, :run
 7 | 
 8 |     def run
 9 |       if ExtendedMarkdownFilter.should_jekyll_replace?(site)
10 |         document.content = ExtendedMarkdownFilter.convert_curly_to_bracket(document.content)
11 |       end
12 |       old_run
13 |     end
14 | 
15 |   end
16 | end
17 | 
18 | module Jekyll
19 |   class Page
20 |     alias_method :old_render, :render
21 | 
22 |     def render(layouts, site_payload)
23 |       if ExtendedMarkdownFilter.should_jekyll_replace?(site)
24 |         self.content = ExtendedMarkdownFilter.convert_curly_to_bracket(content)
25 |       end
26 |       old_render(layouts, site_payload)
27 |     end
28 |   end
29 | end
30 | 


--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2014 Garen Torikian
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
 6 | this software and associated documentation files (the "Software"), to deal in
 7 | the Software without restriction, including without limitation the rights to
 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 | 


--------------------------------------------------------------------------------
/extended-markdown-filter.gemspec:
--------------------------------------------------------------------------------
 1 | Gem::Specification.new do |spec|
 2 |   spec.name          = 'extended-markdown-filter'
 3 |   spec.version       = '0.7.0'
 4 |   spec.authors       = ['Garen Torikian']
 5 |   spec.email         = ['gjtorikian@gmail.com']
 6 |   spec.summary       = %q{Add extended markup syntax to the HTML::Pipeline}
 7 |   spec.description   = %q{This is a custom Markdown processor to be used with GitHub's HTML::Pipeline. }
 8 |   spec.homepage      = ''
 9 |   spec.license       = 'MIT'
10 | 
11 |   spec.files         = `git ls-files`.split($/)
12 |   spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
13 |   spec.test_files    = spec.files.grep(%r{^(test)/})
14 |   spec.require_paths = ['lib']
15 | 
16 |   spec.add_dependency 'html-pipeline', '~> 2.9'
17 | 
18 |   spec.add_development_dependency 'bundler', '~> 1.4'
19 |   spec.add_development_dependency 'rake'
20 |   spec.add_development_dependency 'minitest', '~> 5.0'
21 |   spec.add_development_dependency 'commonmarker', '~> 0.18'
22 |   spec.add_development_dependency 'pry-byebug', '~> 3.6'
23 |   spec.add_development_dependency 'rubocop', '~> 0.60'
24 |   spec.add_development_dependency 'rubocop-github', '~> 0.12'
25 | end
26 | 


--------------------------------------------------------------------------------
/lib/extended-markdown-filter.rb:
--------------------------------------------------------------------------------
 1 | require 'html/pipeline'
 2 | require 'filters/filters'
 3 | require 'jekyll-override' unless defined?(Jekyll).nil?
 4 | 
 5 | class ExtendedMarkdownFilter < HTML::Pipeline::MarkdownFilter
 6 |   include Filters::PreFilter
 7 |   include Filters::PostFilter
 8 | 
 9 |   EMF_CURLY_TAGS = %w(intro mac windows linux all tip note warning danger).join('|')
10 | 
11 |   def initialize(text, context = nil, result = nil)
12 |     if context[:emf_use_blocks]
13 |       text = self.class.convert_curly_to_bracket(text)
14 |       @front_wrap = '\\[\\['
15 |       @end_wrap = '\\]\\]'
16 |       @wrap_symbol = '\\]'
17 |     else
18 |       @front_wrap = "\{\{"
19 |       @end_wrap = "\}\}"
20 |       @wrap_symbol = '}'
21 |     end
22 | 
23 |     # do preprocessing, then call HTML::Pipeline::Markdown
24 |     text = format_helper          text
25 | 
26 |     super text, context, result
27 |   end
28 | 
29 |   def self.convert_curly_to_bracket(text)
30 |     return text if text.nil?
31 |     text = text.gsub(/\{\{#(#{EMF_CURLY_TAGS})\}\}/, '[[#\1]]')
32 |     text = text.gsub(/\{\{\/(#{EMF_CURLY_TAGS})\}\}/, '[[/\1]]')
33 |     text = text.gsub(/\{\{ (octicon-\S+\s*[^\}]+) \}\}/,  '[[\1]]')
34 | 
35 |     text
36 |   end
37 | 
38 |   def self.should_jekyll_replace?(site)
39 |     html_pipeline_context = site.site_payload['site']['html_pipeline'] && site.site_payload['site']['html_pipeline']['context']
40 |     return false if html_pipeline_context.nil?
41 |     pipeline_emf_context = site.site_payload['site']['html_pipeline']['context'][:emf_use_blocks] || site.site_payload['site']['html_pipeline']['context']['emf_use_blocks']
42 |     site.site_payload['site']['markdown'] == 'HTMLPipeline' && html_pipeline_context && pipeline_emf_context
43 |   end
44 | 
45 |   def call
46 |     # initialize HTML::Pipeline::Markdown, then do post-processing
47 |     html = super
48 | 
49 |     format_intro!           html
50 |     format_os_blocks!       html
51 |     format_admonitions!     html
52 |     format_octicons!        html
53 |     format_command_line!    html
54 | 
55 |     html
56 |   end
57 | 
58 | end
59 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # extended-markdown-filter
  2 | 
  3 | Extended Markdown filters for the [HTML::Pipeline](https://github.com/jch/html-pipeline).
  4 | 
  5 | [![Build Status](https://travis-ci.org/gjtorikian/extended-markdown-filter.svg)](https://travis-ci.org/gjtorikian/extended-markdown-filter)
  6 | 
  7 | ## Installation
  8 | 
  9 | Add this line to your application's Gemfile:
 10 | 
 11 |     gem 'extended-markdown-filter'
 12 | 
 13 | And then execute:
 14 | 
 15 |     $ bundle
 16 | 
 17 | Or install it yourself as:
 18 | 
 19 |     $ gem install extended-markdown-filter
 20 | 
 21 | ## Usage
 22 | 
 23 | The simplest way to do this is
 24 | 
 25 | ``` ruby
 26 | require 'extended-markdown-filter'
 27 | ```
 28 | 
 29 | Then just use the HTML pipeline normally. With Jekyll, this is meant to be used with another plugin in conjunction, https://github.com/gjtorikian/jekyll-html-pipeline.
 30 | 
 31 | A minimum config file might look like:
 32 | ``` yaml
 33 | gems:
 34 |   - extended-markdown-filter
 35 |   - jekyll-html-pipeline
 36 | 
 37 | markdown: HTMLPipeline
 38 | html_pipeline:
 39 |   filters:
 40 |     - "ExtendedMarkdownFilter"
 41 |   context:
 42 |     emf_use_blocks: true
 43 | ```
 44 | 
 45 | ### Within Jekyll
 46 | 
 47 | Because of the Liquid template engine, if you use this filter with Jekyll, you might find that your curly brace tags--such as `{{#tip}}`--disappear.
 48 | 
 49 | You'll need to pass the context `emf_use_blocks` through your filter. This sets up a totally safe monkey-patch to convert the `{{ }}` blocks into `[[ ]]`, so that Liquid ignores them. Then, this renderer will convert the Markdown appropriately.
 50 | 
 51 | ## What does this add?
 52 | 
 53 | You may be wondering what features this filter adds to Markdown. Great question! Here's what we've got:
 54 | 
 55 | ### Command-line highlighting
 56 | 
 57 | A new pre block, `command-line`, adds some divs to allow for better highlighting for terminal code.
 58 | 
 59 | #### Example
 60 | 
 61 |     ``` command-line
 62 |     $ git remote add origin https://github.com/user/repo.git
 63 |     # Set a new remote
 64 |     > origin  https://github.com/user/repo.git
 65 |     ```
 66 | 
 67 | * `$` represents content a user enters
 68 | * `` highlights content for the user
 69 | * `#` represents comments
 70 | * `>` represents output as a result of a command
 71 | 
 72 | ### Helper
 73 | 
 74 | The `helper` notation wraps content in an [accordion fold](http://jqueryui.com/accordion/).
 75 | 
 76 | #### Example
 77 | 
 78 |     ``` helper
 79 |     I'm not really important enough to show.
 80 |     ```
 81 | 
 82 | ### Admonition blocks
 83 | 
 84 | You can create separate, priority-colored callouts with `{{#tip}}`, `{{#note}}`, `{{#warning}}`, and `{{#error}}` tags.
 85 | 
 86 | #### Example
 87 | 
 88 |     {{#tip}}
 89 | 
 90 |     Here's a hot tip: **line one**
 91 |     Here's a hot tip: line two
 92 | 
 93 |     {{/tip}}
 94 | 
 95 |     {{#note}}
 96 | 
 97 |     You should probably know this! line one
 98 |     You should probably know this! line two
 99 | 
100 |     {{/note}}
101 | 
102 |     {{#warning}}
103 | 
104 |     Yo, check this out: line one
105 |     Yo, check this out: line two
106 | 
107 |     {{/warning}}
108 | 
109 |     {{#danger}}
110 | 
111 |     Sheeeeit, this is a problem: ~~line one~~
112 |     Sheeeeit, this is a problem: line two
113 | 
114 |     {{/danger}}
115 | 
116 | ### Intro
117 | 
118 | The `intro` block demarcates a special section that provides a summary of the content to follow.
119 | 
120 | #### Example
121 | 
122 |     {{#intro}}
123 | 
124 |     [Gists](https://gist.github.com) are a great way to share your work. You can share single files, parts of files, or full applications.
125 | 
126 |     {{/intro}}
127 | 
128 | ### Octicon
129 | 
130 | The `{{ octicon }}` helper lets you easily render [any Octicon](https://octicons.github.com/) in the content, including an aria label.
131 | 
132 | #### Example
133 | 
134 |     {{ octicon-gear The Settings gear }}
135 | 
136 | ### Operating system blocks
137 | 
138 | Sometimes, certain content needs to be rendered for only a certain operating system. Use `{{#mac}}` of Mac OS specific content, `{{#windows}}` for Windows, `{{#linux}}` for Linux, and `{{#all}}` as a catch-all for everything else.
139 | 
140 | #### Example
141 | 
142 |     {{#mac}}
143 | 
144 |     1. Command-click on the option.
145 | 
146 |     {{/mac}}
147 | 
148 |     {{#windows}}
149 | 
150 |     1. Right click on the **Start** menu.
151 | 
152 |     {{/windows}}
153 | 
154 |     {{#linux}}
155 | 
156 |     1. Open the terminal.
157 | 
158 |     {{/linux}}
159 | 
160 |     {{#all}}
161 | 
162 |     1. Double-click on the icon.
163 | 
164 |     {{/all}}
165 | 


--------------------------------------------------------------------------------
/test/test_extended_markdown_filter.rb:
--------------------------------------------------------------------------------
  1 | require 'test_helper'
  2 | 
  3 | class HTML::Pipeline::ExtendedMarkdownFilterTest < Minitest::Test
  4 |   def fixture(name)
  5 |     File.open(File.join("#{File.expand_path(File.dirname(__FILE__))}", 'fixtures', name)).read
  6 |   end
  7 | 
  8 |   def test_command_line
  9 |     doc = ExtendedMarkdownFilter.to_document(fixture('command_line.md'), {})
 10 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 11 | 
 12 |     assert_equal 1, doc.css('pre.command-line').size
 13 |     assert_equal 2, doc.css('span.command').size
 14 |     assert_equal 1, doc.css('span.comment').size
 15 |     assert_equal 2, doc.css('em').size
 16 |     assert_equal 1, doc.css('span.output').size
 17 |     assert_equal 0, doc.css('code').size
 18 | 
 19 |     assert_equal 0, doc.css('.command-line a').size
 20 |     assert_equal 8, doc.to_html.lines.count
 21 |     refute_equal 0, doc.css('pre').inner_text.length
 22 |   end
 23 | 
 24 |   def test_command_line_indented
 25 |     doc = ExtendedMarkdownFilter.to_document(fixture('command_line_indented.md'), {})
 26 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 27 | 
 28 |     assert_equal 1, doc.css('pre.command-line').size
 29 |     assert_equal 2, doc.css('span.command').size
 30 |     assert_equal 1, doc.css('span.comment').size
 31 |     assert_equal 2, doc.css('em').size
 32 |     assert_equal 1, doc.css('span.output').size
 33 | 
 34 |     assert_equal 0, doc.css('.command-line a').size
 35 |     refute_equal 0, doc.css('pre').inner_text.length
 36 |   end
 37 | 
 38 |   def test_nested_command_line
 39 |     doc = ExtendedMarkdownFilter.to_document(fixture('command_line_nested.md'), {})
 40 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 41 | 
 42 |     assert_equal 1, doc.css('ol').size
 43 |     assert_equal 2, doc.css('li').size
 44 |     assert_equal 2, doc.css('pre').size
 45 | 
 46 |     list = doc.css('ol')[0]
 47 |     first_list_item = doc.css('li')[0]
 48 |     first_command_line_block = doc.css('pre')[0]
 49 |     second_list_item = doc.css('li')[1]
 50 |     second_command_line_block = doc.css('pre')[1]
 51 | 
 52 |     assert list.children.include?(first_list_item)
 53 |     assert list.children.include?(second_list_item)
 54 |     assert_equal first_command_line_block.parent, first_list_item
 55 |     assert_equal second_command_line_block.parent, second_list_item
 56 |   end
 57 | 
 58 |   def test_helper_works_and_requires_unsafe
 59 |     doc = ExtendedMarkdownFilter.to_document(fixture('helper.md'), { unsafe: false })
 60 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 61 | 
 62 |     assert_equal 0, doc.css('div.helper').size
 63 | 
 64 |     doc = ExtendedMarkdownFilter.to_document(fixture('helper.md'), { unsafe: true })
 65 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 66 | 
 67 |     assert_equal 1, doc.css('div.helper').size
 68 |     assert_equal 1, doc.css('h4.header').size
 69 |     assert_equal 1, doc.css('a').size
 70 |     assert_equal 1, doc.css('div.content').size
 71 |   end
 72 | 
 73 |   def test_intro
 74 |     doc = ExtendedMarkdownFilter.to_document(fixture('intro.md'), {})
 75 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 76 | 
 77 |     assert_equal 1, doc.css('div.intro').size
 78 |     assert_equal 1, doc.css('a').size # the inner Markdown converted!
 79 |   end
 80 | 
 81 |   def test_block_intro
 82 |     doc = ExtendedMarkdownFilter.to_document(fixture('block_intro.md'), {emf_use_blocks: true})
 83 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 84 | 
 85 |     assert_equal 1, doc.css('div.intro').size
 86 |     assert_equal 1, doc.css('a').size # the inner Markdown converted!
 87 |   end
 88 | 
 89 |   def test_intro_conversion
 90 |     doc = ExtendedMarkdownFilter.to_document(fixture('intro.md'), {emf_use_blocks: true})
 91 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
 92 | 
 93 |     assert_equal 1, doc.css('div.intro').size
 94 |     assert_equal 1, doc.css('a').size # the inner Markdown converted!
 95 |   end
 96 | 
 97 |   def test_os_blocks
 98 |     doc = ExtendedMarkdownFilter.to_document(fixture('os_blocks.md'), {})
 99 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
100 | 
101 |     assert_equal 1, doc.css('div.platform-mac').size
102 |     assert_equal 1, doc.css('div.platform-windows').size
103 |     assert_equal 1, doc.css('div.platform-linux').size
104 |     assert_equal 1, doc.css('div.platform-all').size
105 |     # the inner Markdown converted!
106 |     assert_equal 3, doc.css('ol').size
107 |     assert_equal 2, doc.css('a').size
108 |     assert_equal 1, doc.css('em').size
109 |   end
110 | 
111 |   def test_block_os_blocks
112 |     doc = ExtendedMarkdownFilter.to_document(fixture('block_os_blocks.md'), {emf_use_blocks: true})
113 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
114 | 
115 |     assert_equal 1, doc.css('div.platform-mac').size
116 |     assert_equal 1, doc.css('div.platform-windows').size
117 |     assert_equal 1, doc.css('div.platform-linux').size
118 |     assert_equal 1, doc.css('div.platform-all').size
119 |     # the inner Markdown converted!
120 |     assert_equal 3, doc.css('ol').size
121 |     assert_equal 2, doc.css('a').size
122 |     assert_equal 1, doc.css('em').size
123 |   end
124 | 
125 |   def test_block_conversion
126 |     doc = ExtendedMarkdownFilter.to_document(fixture('os_blocks.md'), {emf_use_blocks: true})
127 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
128 | 
129 |     assert_equal 1, doc.css('div.platform-mac').size
130 |     assert_equal 1, doc.css('div.platform-windows').size
131 |     assert_equal 1, doc.css('div.platform-linux').size
132 |     assert_equal 1, doc.css('div.platform-all').size
133 |     # the inner Markdown converted!
134 |     assert_equal 3, doc.css('ol').size
135 |     assert_equal 2, doc.css('a').size
136 |     assert_equal 1, doc.css('em').size
137 |   end
138 | 
139 |   def test_admonition
140 |     doc = ExtendedMarkdownFilter.to_document(fixture('admonition.md'), {})
141 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
142 | 
143 |     assert_equal 1, doc.css('div.tip').size
144 |     assert_equal 1, doc.css('div.note').size
145 |     assert_equal 1, doc.css('div.warning').size
146 |     assert_equal 1, doc.css('div.danger').size
147 |     # the inner Markdown converted!
148 |     assert_equal 1, doc.css('strong').size
149 |     assert_equal 1, doc.css('del').size
150 |   end
151 | 
152 |   def test_block_admonition
153 |     doc = ExtendedMarkdownFilter.to_document(fixture('block_admonition.md'), {emf_use_blocks: true})
154 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
155 | 
156 |     assert_equal 1, doc.css('div.tip').size
157 |     assert_equal 1, doc.css('div.note').size
158 |     assert_equal 1, doc.css('div.warning').size
159 |     assert_equal 1, doc.css('div.danger').size
160 |     # the inner Markdown converted!
161 |     assert_equal 1, doc.css('strong').size
162 |     assert_equal 1, doc.css('del').size
163 |   end
164 | 
165 |   def test_admonition_conversion
166 |     doc = ExtendedMarkdownFilter.to_document(fixture('admonition.md'), {emf_use_blocks: true})
167 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
168 | 
169 |     assert_equal 1, doc.css('div.tip').size
170 |     assert_equal 1, doc.css('div.note').size
171 |     assert_equal 1, doc.css('div.warning').size
172 |     assert_equal 1, doc.css('div.danger').size
173 |     # the inner Markdown converted!
174 |     assert_equal 1, doc.css('strong').size
175 |     assert_equal 1, doc.css('del').size
176 |   end
177 | 
178 |   def test_octicon
179 |     doc = ExtendedMarkdownFilter.to_document(fixture('octicon.md'), {})
180 |     assert doc.kind_of?(HTML::Pipeline::DocumentFragment)
181 | 
182 |     assert_equal 1, doc.css('span.octicon-cat').size
183 |     assert_match '{{ octicon dog', doc.to_s
184 |     assert_match '

Click

', doc.to_s 185 | end 186 | 187 | def test_block_octicon 188 | doc = ExtendedMarkdownFilter.to_document(fixture('block_octicon.md'), {emf_use_blocks: true}) 189 | assert doc.kind_of?(HTML::Pipeline::DocumentFragment) 190 | 191 | assert_equal 1, doc.css('span.octicon-cat').size 192 | assert_match '[[ octicon dog', doc.to_s 193 | assert_match '

Click

', doc.to_s 194 | end 195 | 196 | def test_oction_conversion 197 | doc = ExtendedMarkdownFilter.to_document(fixture('octicon.md'), {emf_use_blocks: true}) 198 | assert doc.kind_of?(HTML::Pipeline::DocumentFragment) 199 | 200 | assert_equal 1, doc.css('span.octicon-cat').size 201 | assert_match '{{ octicon dog', doc.to_s 202 | assert_match '

Click

', doc.to_s 203 | end 204 | 205 | end 206 | --------------------------------------------------------------------------------