marko 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.dockerignore +12 -0
- data/.rubocop.yml +45 -0
- data/CHANGELOG.md +10 -4
- data/Dockerfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +17 -31
- data/Rakefile +2 -11
- data/exe/marko +4 -22
- data/lib/basic.rb +27 -0
- data/lib/marko/chain.rb +44 -0
- data/lib/marko/cli.rb +119 -129
- data/lib/marko/config.rb +30 -20
- data/lib/marko/errors.rb +38 -0
- data/lib/marko/model/markup.rb +33 -0
- data/lib/marko/model/topic.rb +126 -0
- data/lib/marko/model/tree_node.rb +34 -0
- data/lib/marko/model.rb +10 -0
- data/lib/marko/parser/metadata.rb +28 -0
- data/lib/marko/parser/source.rb +52 -0
- data/lib/marko/parser/topic.rb +33 -0
- data/lib/marko/parser.rb +8 -19
- data/lib/marko/renderers/artifact.rb +29 -0
- data/lib/marko/renderers/content.rb +37 -0
- data/lib/marko/renderers/link.rb +19 -0
- data/lib/marko/renderers/metadata.rb +34 -0
- data/lib/marko/renderers/nested_list.rb +21 -0
- data/lib/marko/renderers/nested_tree.rb +22 -0
- data/lib/marko/renderers/renderer.rb +17 -0
- data/lib/marko/renderers/title.rb +16 -0
- data/lib/marko/renderers/topic.rb +24 -0
- data/lib/marko/renderers/url.rb +16 -0
- data/lib/marko/renderers.rb +17 -0
- data/lib/marko/scanner.rb +39 -0
- data/lib/marko/tasks/assemble.rb +52 -0
- data/lib/marko/tasks/compile.rb +19 -0
- data/lib/marko/tasks/load.rb +13 -0
- data/lib/marko/tasks/parse.rb +27 -0
- data/lib/marko/tasks/scan.rb +18 -0
- data/lib/marko/tasks/validate.rb +32 -0
- data/lib/marko/tasks.rb +13 -0
- data/lib/marko/validators/lost_index.rb +21 -0
- data/lib/marko/validators/lost_links.rb +25 -0
- data/lib/marko/validators/lost_parent.rb +21 -0
- data/lib/marko/validators/non_unique_id.rb +23 -0
- data/lib/marko/validators.rb +11 -0
- data/lib/marko/version.rb +1 -3
- data/lib/marko.rb +11 -43
- metadata +47 -85
- data/Gemfile +0 -10
- data/Gemfile.lock +0 -23
- data/STORY.md +0 -44
- data/_layouts/footer.md +0 -4
- data/_layouts/header.md +0 -3
- data/_layouts/layout.html +0 -73
- data/_layouts/robots.txt.erb +0 -4
- data/_layouts/sitemap.xml.erb +0 -20
- data/_layouts/styles.css +0 -92
- data/docs/changelog.html +0 -74
- data/docs/css/styles.css +0 -92
- data/docs/index.html +0 -297
- data/docs/readme.html +0 -297
- data/docs/robots.txt +0 -4
- data/docs/sitemap.xml +0 -30
- data/docs/story.html +0 -132
- data/lib/assets/demo/README.md +0 -13
- data/lib/assets/demo/src/fr/assemble.md +0 -27
- data/lib/assets/demo/src/fr/compile.md +0 -25
- data/lib/assets/demo/src/fr/markup.md +0 -111
- data/lib/assets/demo/src/fr/storage.md +0 -16
- data/lib/assets/demo/src/fr/treenode.md +0 -34
- data/lib/assets/demo/src/index.md +0 -34
- data/lib/assets/demo/src/intro.md +0 -98
- data/lib/assets/demo/src/ui/cli.md +0 -26
- data/lib/assets/demo/src/ui/gem.md +0 -14
- data/lib/assets/demo/src/ur/uc.create.project.md +0 -8
- data/lib/assets/demo/src/ur/uc.general.flow.md +0 -14
- data/lib/assets/init/README.md +0 -61
- data/lib/assets/init/Rakefile +0 -100
- data/lib/assets/init/tt/custom.md.tt +0 -19
- data/lib/assets/init/tt/default.md.tt +0 -4
- data/lib/assets/samples/0_index.md +0 -14
- data/lib/assets/samples/1_intro.md +0 -55
- data/lib/assets/samples/2_stakh.md +0 -21
- data/lib/assets/samples/3_actors.md +0 -10
- data/lib/assets/samples/4_cases.md +0 -53
- data/lib/assets/samples/5_entities.md +0 -18
- data/lib/assets/samples/6_concerns.md +0 -60
- data/lib/assets/samples/SRS-IEEE-830-1998.md +0 -293
- data/lib/assets/samples/SRS-RUP.md +0 -283
- data/lib/assets/samples/business-case.md +0 -116
- data/lib/assets/samples/ears.md +0 -112
- data/lib/assets/samples/gen_punch_domain.rb +0 -183
- data/lib/assets/samples/requirements.md +0 -105
- data/lib/assets/samples/stakeholders.png +0 -0
- data/lib/assets/samples/vision.md +0 -191
- data/lib/marko/artifact.rb +0 -5
- data/lib/marko/assembler.rb +0 -83
- data/lib/marko/compiler.rb +0 -16
- data/lib/marko/gadgets/pluggable.rb +0 -55
- data/lib/marko/gadgets/sentry.rb +0 -66
- data/lib/marko/gadgets/service.rb +0 -52
- data/lib/marko/gadgets.rb +0 -3
- data/lib/marko/loader.rb +0 -38
- data/lib/marko/markup/compiler.rb +0 -30
- data/lib/marko/markup/decorator.rb +0 -80
- data/lib/marko/markup/macro.rb +0 -176
- data/lib/marko/markup/parser.rb +0 -122
- data/lib/marko/markup/storage.rb +0 -118
- data/lib/marko/markup/validator.rb +0 -101
- data/lib/marko/markup.rb +0 -24
- data/lib/marko/services/assemble.rb +0 -16
- data/lib/marko/services/compile.rb +0 -30
- data/lib/marko/services.rb +0 -2
- data/lib/marko/storage.rb +0 -36
- data/lib/marko/tree_node.rb +0 -129
- data/lib/marko/validator.rb +0 -19
- data/marko.gemspec +0 -44
- data/sancho.yml +0 -6
data/lib/marko/errors.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Marko
|
2
|
+
|
3
|
+
# Marko error
|
4
|
+
class MarkoError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
# Parser error
|
8
|
+
class ParserError < MarkoError
|
9
|
+
attr_reader :filename
|
10
|
+
attr_reader :lineno
|
11
|
+
attr_reader :markup
|
12
|
+
|
13
|
+
def initialize(msg, filename, lineno, markup)
|
14
|
+
@filename = filename
|
15
|
+
@lineno = lineno
|
16
|
+
@markup = markup
|
17
|
+
super(msg)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Stage like load/compile errors
|
22
|
+
class StageError < MarkoError
|
23
|
+
attr_reader :errors
|
24
|
+
|
25
|
+
def initialize(msg, errors)
|
26
|
+
@errors = errors
|
27
|
+
super(msg)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class ValidatorError < MarkoError
|
32
|
+
end
|
33
|
+
|
34
|
+
# Compiler error
|
35
|
+
class CompilerError < MarkoError
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Marko
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Raw Markup
|
5
|
+
class Markup
|
6
|
+
# @return [String]
|
7
|
+
attr_reader :filename
|
8
|
+
# @return [Intger]
|
9
|
+
attr_reader :lineno
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :content
|
12
|
+
|
13
|
+
def initialize(filename, lineno, content)
|
14
|
+
@filename = filename
|
15
|
+
@lineno = lineno
|
16
|
+
@content = content
|
17
|
+
end
|
18
|
+
|
19
|
+
def header
|
20
|
+
@content.lines.first
|
21
|
+
end
|
22
|
+
|
23
|
+
def level
|
24
|
+
header.scan(/^#+/).first&.size
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#{filename}:#{lineno.to_s.rjust(2,'0')} >> #{header}".strip
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require_relative 'tree_node'
|
2
|
+
require_relative 'markup'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Marko
|
6
|
+
module Model
|
7
|
+
|
8
|
+
# Topic
|
9
|
+
class Topic
|
10
|
+
include TreeNode
|
11
|
+
extend Forwardable
|
12
|
+
def_delegators :metadata, :[], :[]=
|
13
|
+
def_delegator :markup, :level, :markup_level
|
14
|
+
def_delegator :markup, :filename, :markup_filename
|
15
|
+
def_delegator :markup, :content, :markup_content
|
16
|
+
def_delegator :markup, :lineno, :markup_lineno
|
17
|
+
|
18
|
+
# @return [String]
|
19
|
+
attr_reader :title
|
20
|
+
# @return [String]
|
21
|
+
attr_reader :content
|
22
|
+
# @return [Hash]
|
23
|
+
attr_reader :metadata
|
24
|
+
# @return [Markup]
|
25
|
+
attr_reader :markup
|
26
|
+
|
27
|
+
# @param title [String]
|
28
|
+
# @param content [String]
|
29
|
+
# @param metadata [Hash]
|
30
|
+
def initialize(title, content, **metadata)
|
31
|
+
@parent = nil
|
32
|
+
@items = []
|
33
|
+
@title = title
|
34
|
+
@content = content
|
35
|
+
@metadata = metadata
|
36
|
+
@markup = metadata.delete(:markup)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
to_a
|
41
|
+
.map{ "<#Topic id: #{it.id}, title: #{it.title}, level: #{it.nesting_level}>"}
|
42
|
+
.join(?\n)
|
43
|
+
end
|
44
|
+
|
45
|
+
def each(&block)
|
46
|
+
super(&block)
|
47
|
+
items.each do |e|
|
48
|
+
e.each(&block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def add(item)
|
53
|
+
item.parent = self
|
54
|
+
@items << item
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete(item)
|
59
|
+
@items.delete(item)
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Array<String>] macro links in content
|
63
|
+
def links
|
64
|
+
return [] if @content.empty?
|
65
|
+
@content.scan(/\[\[([\w\.]*)\]\]/).flatten.uniq
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_by_id(ref)
|
69
|
+
find{ it.id == ref } || root.find{ it.id == ref }
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Array<String>] ids in order_index but out of @items
|
73
|
+
def lost_order_index
|
74
|
+
order_index.reject{ item(it) }
|
75
|
+
end
|
76
|
+
|
77
|
+
# def parent_id
|
78
|
+
# @metdata[:parent_id]
|
79
|
+
# end
|
80
|
+
|
81
|
+
# sort of dynamic id
|
82
|
+
def id
|
83
|
+
@metadata.fetch(:id, '').then do |e|
|
84
|
+
e = parent.id + e if e.start_with?(?.) && parent
|
85
|
+
e
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def id=(id)
|
90
|
+
@metadata[:id] = id
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def parent=(parent)
|
96
|
+
@parent = parent
|
97
|
+
end
|
98
|
+
|
99
|
+
def order_index
|
100
|
+
@order_index = @metadata
|
101
|
+
.fetch(:order_index, '')
|
102
|
+
.strip
|
103
|
+
.split(/\s{1,}/)
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Array<Topic>] ordered list of child nodes
|
107
|
+
def items
|
108
|
+
return @items unless order_index.any?
|
109
|
+
[].tap do |ary|
|
110
|
+
src = @items.dup
|
111
|
+
order_index.each do |i|
|
112
|
+
node = item(i)
|
113
|
+
ary << src.delete(node) if node
|
114
|
+
end
|
115
|
+
ary.concat(src)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def item(id)
|
120
|
+
@items.find{|n| n.id == id || n.id.end_with?(id) }
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Marko
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Tree node
|
5
|
+
module TreeNode
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
# @return [TreeNode]
|
9
|
+
attr_reader :parent
|
10
|
+
|
11
|
+
def each(&block)
|
12
|
+
yield self
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(item)
|
16
|
+
fail "#{self.class}##{__method__} must be overridden"
|
17
|
+
end
|
18
|
+
|
19
|
+
def root
|
20
|
+
parent ? parent.root : self
|
21
|
+
end
|
22
|
+
|
23
|
+
def root?
|
24
|
+
parent.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def nesting_level
|
28
|
+
return 0 if root?
|
29
|
+
parent.nesting_level + 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/lib/marko/model.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Marko
|
2
|
+
module Parser
|
3
|
+
|
4
|
+
# Metadata parser
|
5
|
+
class Metadata
|
6
|
+
# @param text [String]
|
7
|
+
# @return [Hash]
|
8
|
+
def parse(text)
|
9
|
+
return {} if text&.empty?
|
10
|
+
|
11
|
+
text
|
12
|
+
.split(/[;,\n]/)
|
13
|
+
.map(&:strip)
|
14
|
+
.reject(&:empty?)
|
15
|
+
.map{ parse_attr(it) }
|
16
|
+
.to_h
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def parse_attr(text)
|
22
|
+
k, v = text.split(?:)
|
23
|
+
[k.strip.to_sym, v&.strip || true]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'topic'
|
2
|
+
require_relative '../errors'
|
3
|
+
|
4
|
+
module Marko
|
5
|
+
module Parser
|
6
|
+
|
7
|
+
# Source parser
|
8
|
+
class Source
|
9
|
+
def initialize
|
10
|
+
@topic = Topic.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param markups [Array<Model::Markup>]
|
14
|
+
# @return [Array<Model::Topic, ParserError>]
|
15
|
+
def parse(markups)
|
16
|
+
results = markups.map do |e|
|
17
|
+
begin
|
18
|
+
@topic.parse(e)
|
19
|
+
rescue => ex
|
20
|
+
puts ex.full_message
|
21
|
+
Marko::ParserError.new(ex.message, e.filename, e.lineno, e.content)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
errors = results.reject{ it.is_a?(Model::Topic) }
|
26
|
+
topics = results.select{ it.is_a?(Model::Topic) }
|
27
|
+
|
28
|
+
adjusted = []
|
29
|
+
topics.each do |e|
|
30
|
+
if e.markup_level == 1
|
31
|
+
adjusted << e
|
32
|
+
next
|
33
|
+
end
|
34
|
+
|
35
|
+
finder = proc{ it.markup_level == e.markup_level - 1 }
|
36
|
+
parent = adjusted.last&.select(&finder)&.last
|
37
|
+
|
38
|
+
unless parent
|
39
|
+
errors << Marko::ParserError.new('wrong header level',
|
40
|
+
e.markup_filename, e.markup_lineno, e.markup_content)
|
41
|
+
next
|
42
|
+
end
|
43
|
+
|
44
|
+
parent.add(e)
|
45
|
+
end
|
46
|
+
|
47
|
+
adjusted + errors
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../model'
|
2
|
+
require_relative 'metadata'
|
3
|
+
|
4
|
+
module Marko
|
5
|
+
module Parser
|
6
|
+
|
7
|
+
# Topic parser
|
8
|
+
class Topic
|
9
|
+
def initialize
|
10
|
+
@metadata = Metadata.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param markup [Model::Markup]
|
14
|
+
# @return [Model::Topic]
|
15
|
+
def parse(markup)
|
16
|
+
text = markup.content
|
17
|
+
first = text.lines.first
|
18
|
+
match = first.match(/\W+(.*)/)
|
19
|
+
title = match[1]&.strip || ''
|
20
|
+
|
21
|
+
rest = text.lines.drop(1).join
|
22
|
+
match = rest.match(/^({{([\s\S]*?)}})?(.*)?$/m)
|
23
|
+
metadata = match[2]&.strip || ''
|
24
|
+
content = match[3]&.strip || ''
|
25
|
+
metadata = @metadata.parse(metadata)
|
26
|
+
|
27
|
+
Model::Topic.new(title, content,
|
28
|
+
**{markup: markup}.merge(metadata))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/marko/parser.rb
CHANGED
@@ -1,19 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require_relative
|
4
|
-
|
5
|
-
module Marko
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
extend Pluggable
|
10
|
-
|
11
|
-
# @param content [String] content to parse
|
12
|
-
# @param source [String] content source
|
13
|
-
# @return [Array<TreeNode>, Array<String>] parsed nodes, errors
|
14
|
-
def call(content, source, &block)
|
15
|
-
fail "the abstract method must be overriden"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
1
|
+
require_relative 'parser/metadata'
|
2
|
+
require_relative 'parser/topic'
|
3
|
+
require_relative 'parser/source'
|
4
|
+
|
5
|
+
module Marko
|
6
|
+
module Parser
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'topic'
|
2
|
+
|
3
|
+
module Marko
|
4
|
+
module Renderers
|
5
|
+
|
6
|
+
# Artifact renderer
|
7
|
+
class Artifact < Renderer
|
8
|
+
def initialize
|
9
|
+
@topic = Topic.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param topic [Model::Topic]
|
13
|
+
def render(topic)
|
14
|
+
root = <<~STR
|
15
|
+
---
|
16
|
+
\% #{topic.title}
|
17
|
+
\% #{topic[:author]}
|
18
|
+
\% #{Time.now.strftime('%Y-%b-%d')}
|
19
|
+
...
|
20
|
+
STR
|
21
|
+
|
22
|
+
topic.to_a.drop(1)
|
23
|
+
.map{ @topic.render(it) }
|
24
|
+
.unshift(root)
|
25
|
+
.join(NN)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative 'link'
|
2
|
+
require_relative 'nested_list'
|
3
|
+
require_relative 'nested_tree'
|
4
|
+
|
5
|
+
module Marko
|
6
|
+
module Renderers
|
7
|
+
|
8
|
+
# Content renderer
|
9
|
+
class Content < Renderer
|
10
|
+
def initialize
|
11
|
+
@link = Link.new
|
12
|
+
@list = NestedList.new
|
13
|
+
@tree = NestedTree.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param topic [Model::Topic]
|
17
|
+
def render(topic)
|
18
|
+
String.new(topic.content).tap do |processed|
|
19
|
+
# links substitution
|
20
|
+
topic.links.uniq.each do |link|
|
21
|
+
ref = topic.root.find_by_id(link) || link
|
22
|
+
processed.gsub!("[[#{link}]]", @link.render(ref))
|
23
|
+
end
|
24
|
+
|
25
|
+
processed.gsub!(/@@list/, @list.render(topic)) \
|
26
|
+
if processed =~ /@@list/
|
27
|
+
|
28
|
+
processed.gsub!(/@@tree/, @tree.render(topic)) \
|
29
|
+
if processed =~ /@@tree/
|
30
|
+
|
31
|
+
processed.gsub!(/@@skip.*$/m, '') \
|
32
|
+
if processed =~ /@@skip/
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'url'
|
2
|
+
|
3
|
+
module Marko
|
4
|
+
module Renderers
|
5
|
+
|
6
|
+
# Link renderer
|
7
|
+
class Link < Renderer
|
8
|
+
def initialize
|
9
|
+
@url = Url.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(topic)
|
13
|
+
return "[#{topic}](#unknown)" unless topic.respond_to?(:title)
|
14
|
+
"[#{topic.title}](#{@url.render(topic.id)})"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'renderer'
|
2
|
+
|
3
|
+
module Marko
|
4
|
+
module Renderers
|
5
|
+
|
6
|
+
# Metadata renderer
|
7
|
+
class Metadata < Renderer
|
8
|
+
def render(topic)
|
9
|
+
metadata = topic.metadata
|
10
|
+
.except(:id, :parent, :origin, :order_index)
|
11
|
+
.then{ {id: topic.id}.merge(it) }
|
12
|
+
|
13
|
+
max_key_length = metadata.keys.map{ it.to_s.size }.max + 4
|
14
|
+
max_val_length = metadata.values.map{ it.to_s.size }.max
|
15
|
+
table_starter =
|
16
|
+
[ max_key_length, max_val_length
|
17
|
+
].map{ ?- * it }
|
18
|
+
.join(?\s)
|
19
|
+
|
20
|
+
make_row = proc{|k, v|
|
21
|
+
"__#{k.to_s.capitalize}__".ljust(max_key_length) + ?\s + v.to_s
|
22
|
+
}
|
23
|
+
|
24
|
+
metadata
|
25
|
+
.map(&make_row)
|
26
|
+
.unshift(table_starter)
|
27
|
+
.unshift(": Metadata\n")
|
28
|
+
.push(table_starter)
|
29
|
+
.join(?\n)
|
30
|
+
.then{ "\n#{it}\n" }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'link'
|
2
|
+
|
3
|
+
module Marko
|
4
|
+
module Renderers
|
5
|
+
|
6
|
+
# Nested topics list renderer
|
7
|
+
class NestedList < Renderer
|
8
|
+
def initialize
|
9
|
+
@link = Link.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param topic [Model::Topic]
|
13
|
+
def render(topic)
|
14
|
+
topic
|
15
|
+
.select{ it.parent == topic }
|
16
|
+
.map{"- #{@link.render(it)}"}
|
17
|
+
.join(?\n)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'link'
|
2
|
+
|
3
|
+
module Marko
|
4
|
+
module Renderers
|
5
|
+
|
6
|
+
# Nested topics tree renderer
|
7
|
+
class NestedTree < Renderer
|
8
|
+
def initialize
|
9
|
+
@link = Link.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param topic [Model::Topic]
|
13
|
+
def render(topic)
|
14
|
+
level = topic.nesting_level + 1
|
15
|
+
mkindent = proc{ ' ' * (it.nesting_level - level) }
|
16
|
+
topic.drop(1)
|
17
|
+
.map{"#{mkindent.(it)}- #{@link.render(it)}"}
|
18
|
+
.join(?\n)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Marko
|
2
|
+
module Renderers
|
3
|
+
|
4
|
+
# Renderer interface
|
5
|
+
class Renderer
|
6
|
+
# @param model [Object]
|
7
|
+
# @return [String]
|
8
|
+
def render(model)
|
9
|
+
fail "#{self.class}##{__method__} must be overridden"
|
10
|
+
end
|
11
|
+
|
12
|
+
NL = ?\n
|
13
|
+
NN = "\n\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'url'
|
2
|
+
|
3
|
+
module Marko
|
4
|
+
module Renderers
|
5
|
+
|
6
|
+
# Title renderer
|
7
|
+
class Title < Renderer
|
8
|
+
def render(topic)
|
9
|
+
head = ?# * topic.nesting_level
|
10
|
+
title = topic.title.empty? ? topic.id.split(/\./).last : topic.title
|
11
|
+
url = Url.new.render(topic.id)
|
12
|
+
"#{head} #{title} {#{url}}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'title'
|
2
|
+
require_relative 'metadata'
|
3
|
+
require_relative 'content'
|
4
|
+
|
5
|
+
module Marko
|
6
|
+
module Renderers
|
7
|
+
|
8
|
+
# Topic renderer
|
9
|
+
class Topic < Renderer
|
10
|
+
def initialize
|
11
|
+
@title = Title.new
|
12
|
+
@metadata = Metadata.new
|
13
|
+
@content = Content.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(topic)
|
17
|
+
[ @title, @metadata, @content
|
18
|
+
].map{ it.render(topic) }
|
19
|
+
.reject(&:empty?)
|
20
|
+
.join(?\n)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'renderers/renderer'
|
2
|
+
require_relative 'renderers/url'
|
3
|
+
require_relative 'renderers/link'
|
4
|
+
require_relative 'renderers/title'
|
5
|
+
require_relative 'renderers/metadata'
|
6
|
+
require_relative 'renderers/nested_list'
|
7
|
+
require_relative 'renderers/nested_tree'
|
8
|
+
require_relative 'renderers/content'
|
9
|
+
require_relative 'renderers/topic'
|
10
|
+
require_relative 'renderers/artifact'
|
11
|
+
|
12
|
+
module Marko
|
13
|
+
|
14
|
+
# Renderers
|
15
|
+
module Renderers
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'model'
|
2
|
+
|
3
|
+
module Marko
|
4
|
+
|
5
|
+
# Source scanner
|
6
|
+
class Scanner
|
7
|
+
# @param text [String]
|
8
|
+
# @return [Array<Model::Markup>]
|
9
|
+
def scan(filename)
|
10
|
+
@source = filename
|
11
|
+
content = File.read(filename)
|
12
|
+
scan_topics(content)
|
13
|
+
.select{ it.content.start_with?(?#) }
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def scan_topics(text)
|
19
|
+
quote, buffer, lineno = false, [], 0
|
20
|
+
origin = proc{
|
21
|
+
Model::Markup.new(@source,
|
22
|
+
lineno - buffer.size + 1, buffer.join)
|
23
|
+
}
|
24
|
+
|
25
|
+
[].tap{|ary|
|
26
|
+
text.each_line do |line|
|
27
|
+
if line =~ /^#/ && !quote && buffer.any?
|
28
|
+
ary << origin.()
|
29
|
+
buffer.clear
|
30
|
+
end
|
31
|
+
lineno += 1
|
32
|
+
buffer << line
|
33
|
+
quote = !quote if line.start_with?('```')
|
34
|
+
end
|
35
|
+
ary << origin.() if buffer.any?
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|