Skip to content

Instantly share code, notes, and snippets.

@reggieb
Last active June 18, 2020 14:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reggieb/f578c6f3b25cac919d9e55afc0445f86 to your computer and use it in GitHub Desktop.
Save reggieb/f578c6f3b25cac919d9e55afc0445f86 to your computer and use it in GitHub Desktop.
An experiment to try parsing markdown using parslet gem.
require 'parslet'
class Store
class << self
def headings
@headings ||= []
end
def links
@links ||= []
end
def add_heading(text)
headings << text.to_s
end
def add_link(label, link)
links << { label: label.to_s, link: link.to_s }
end
end
end
class MarkdownParser < Parslet::Parser
rule(:text) { match('.').repeat(1) }
rule(:space) { match('\s').repeat(1) }
rule(:space?) { space.maybe }
rule(:start_label) { str('(') }
rule(:end_label) { str(')') }
rule(:label_content) { match('[\s\w]').repeat(1) }
rule(:label) { start_label >> label_content.as(:label_text) >> end_label }
rule(:start_link) { str('[') }
rule(:end_link) { str(']') }
rule(:http_path) { match('[\s\w\/\.]').repeat(1) }
rule(:http_start) { str('http:') }
rule(:https_start) { str('https:') }
rule(:url) { http_start >> http_path }
rule(:secure_url) { https_start >> http_path }
rule(:link_content) { secure_url | url | http_path}
rule(:link) { start_link >> link_content.as(:link_text) >> end_link }
rule(:anchor) { label >> space? >> link }
rule(:header_flag) { str('#').repeat(1) }
rule(:header) { header_flag >> space? >> text.as(:header_text) }
rule(:content) { header | anchor }
root(:content)
def self.parse(text)
new.parse(text)
end
end
class MarkdownTransformer < Parslet::Transform
rule(header_text: simple(:header_text)) { Store.add_heading(header_text) }
rule(label_text: simple(:label_text), link_text: simple(:link_text)) { Store.add_link(label_text, link_text) }
def self.process(text)
parsed = MarkdownParser.parse(text)
new.apply(parsed)
end
end
MarkdownTransformer.process('###bbbb')
MarkdownTransformer.process('### Goodbye and thanks for all the fish')
MarkdownTransformer.process('(this link)[http://example.com]')
MarkdownTransformer.process('(that link)[https://example.com/foo/bar]')
MarkdownTransformer.process('(another link)[/example/ho/hum]')
p Store.headings
p Store.links
@reggieb
Copy link
Author

reggieb commented Jun 18, 2020

The script outputs:

["bbbb", "Goodbye and thanks for all the fish"]
[{:label=>"this link", :link=>"http://example.com"}, {:label=>"that link", :link=>"https://example.com/foo/bar"}, {:label=>"another link", :link=>"/example/ho/hum"}]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment