d-mark 0.1 → 0.2.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/Gemfile +4 -7
- data/Gemfile.lock +16 -12
- data/Guardfile +3 -0
- data/NEWS.md +11 -3
- data/README.adoc +218 -0
- data/Rakefile +13 -2
- data/d-mark.gemspec +5 -4
- data/lib/d-mark.rb +2 -0
- data/lib/d-mark/cli.rb +28 -0
- data/lib/d-mark/parser.rb +460 -0
- data/lib/{dmark → d-mark}/translator.rb +5 -3
- data/lib/d-mark/version.rb +3 -0
- data/samples/identifiers-and-patterns.dmark +418 -1
- data/samples/trivial.dmark +1 -0
- data/samples/trivial.rb +20 -0
- data/spec/d-mark/parser_spec.rb +271 -0
- data/spec/spec_helper.rb +2 -0
- metadata +30 -18
- data/README.md +0 -70
- data/lib/dmark.rb +0 -9
- data/lib/dmark/lexer.rb +0 -235
- data/lib/dmark/nodes.rb +0 -76
- data/lib/dmark/parser.rb +0 -28
- data/lib/dmark/tokens.rb +0 -49
- data/lib/dmark/version.rb +0 -3
- data/samples/identifiers-and-patterns.html +0 -59
- data/scripts/translate-to-html.rb +0 -46
- data/tasks/doc.rake +0 -13
- data/tasks/rubocop.rake +0 -6
- data/tasks/test.rake +0 -6
@@ -0,0 +1 @@
|
|
1
|
+
p. I’m a %em{trivial} example!
|
data/samples/trivial.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'd-mark'
|
2
|
+
|
3
|
+
class MyHTMLTranslator < DMark::Translator
|
4
|
+
def handle(node)
|
5
|
+
case node
|
6
|
+
when String
|
7
|
+
out << node
|
8
|
+
when DMark::Parser::ElementNode
|
9
|
+
out << "<#{node.name}>"
|
10
|
+
handle_children(node)
|
11
|
+
out << "</#{node.name}>"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
content = File.read('samples/trivial.dmark')
|
17
|
+
parser = DMark::Parser.new(content)
|
18
|
+
tree = parser.parse
|
19
|
+
|
20
|
+
puts MyHTMLTranslator.new(tree).run
|
@@ -0,0 +1,271 @@
|
|
1
|
+
def parse(s)
|
2
|
+
DMark::Parser.new(s).parse
|
3
|
+
end
|
4
|
+
|
5
|
+
def element(name, attributes, children)
|
6
|
+
DMark::Parser::ElementNode.new(name, attributes, children)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'DMark::Parser#parser' do
|
10
|
+
it 'parses' do
|
11
|
+
expect(parse('')).to eq []
|
12
|
+
expect(parse('p.')).to eq [element('p', {}, [])]
|
13
|
+
expect(parse('p. hi')).to eq [element('p', {}, ['hi'])]
|
14
|
+
expect(parse('p. hi %%')).to eq [element('p', {}, ['hi ', '%'])]
|
15
|
+
expect(parse('p. hi %}')).to eq [element('p', {}, ['hi ', '}'])]
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'parses escaped % in block' do
|
19
|
+
expect(parse('p. %%')).to eq [
|
20
|
+
element('p', {}, ['%'])
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'parses escaped } in block' do
|
25
|
+
expect(parse('p. %}')).to eq [
|
26
|
+
element('p', {}, ['}'])
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'parses escaped % in inline block' do
|
31
|
+
expect(parse('p. %foo{%%}')).to eq [
|
32
|
+
element(
|
33
|
+
'p', {},
|
34
|
+
[
|
35
|
+
element('foo', {}, ['%'])
|
36
|
+
]
|
37
|
+
)
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'parses escaped } in inline block' do
|
42
|
+
expect(parse('p. %foo{%}}')).to eq [
|
43
|
+
element(
|
44
|
+
'p', {},
|
45
|
+
[
|
46
|
+
element('foo', {}, ['}'])
|
47
|
+
])
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'parses block with text and element content' do
|
52
|
+
expect(parse('p. hi %em{ho}')).to eq [
|
53
|
+
element(
|
54
|
+
'p', {}, [
|
55
|
+
'hi ',
|
56
|
+
element('em', {}, ['ho'])
|
57
|
+
]
|
58
|
+
)
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'parses block with text and element content, followed by newline' do
|
63
|
+
expect(parse("p. hi %em{ho}\n")).to eq [
|
64
|
+
element(
|
65
|
+
'p', {}, [
|
66
|
+
'hi ',
|
67
|
+
element('em', {}, ['ho'])
|
68
|
+
]
|
69
|
+
)
|
70
|
+
]
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'parses children' do
|
74
|
+
expect(parse("p. hi %em{ho}\n p. child p")).to eq [
|
75
|
+
element(
|
76
|
+
'p', {}, [
|
77
|
+
'hi ',
|
78
|
+
element('em', {}, ['ho']),
|
79
|
+
element('p', {}, ['child p'])
|
80
|
+
]
|
81
|
+
)
|
82
|
+
]
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'parses children multiple levels deep' do
|
86
|
+
expect(parse("p. hi %em{ho}\n p. child p\n p. subchild p")).to eq [
|
87
|
+
element(
|
88
|
+
'p', {}, [
|
89
|
+
'hi ',
|
90
|
+
element('em', {}, ['ho']),
|
91
|
+
element(
|
92
|
+
'p', {}, [
|
93
|
+
'child p',
|
94
|
+
element(
|
95
|
+
'p', {}, [
|
96
|
+
'subchild p'
|
97
|
+
]
|
98
|
+
)
|
99
|
+
]
|
100
|
+
)
|
101
|
+
]
|
102
|
+
)
|
103
|
+
]
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'ignores blanks' do
|
107
|
+
expect(parse("p. foo\n \n p. bar\n \n\n p. qux")).to eq [
|
108
|
+
element(
|
109
|
+
'p', {}, [
|
110
|
+
'foo',
|
111
|
+
element(
|
112
|
+
'p', {}, [
|
113
|
+
'bar',
|
114
|
+
element(
|
115
|
+
'p', {}, [
|
116
|
+
'qux'
|
117
|
+
]
|
118
|
+
)
|
119
|
+
]
|
120
|
+
)
|
121
|
+
]
|
122
|
+
)
|
123
|
+
]
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'reads multiple consecutive blocks' do
|
127
|
+
expect(parse("p. foo\np. bar")).to eq [
|
128
|
+
element('p', {}, ['foo']),
|
129
|
+
element('p', {}, ['bar'])
|
130
|
+
]
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'includes raw content' do
|
134
|
+
expect(parse("p. foo\n donkey")).to eq [
|
135
|
+
element('p', {}, %W(foo \n donkey))
|
136
|
+
]
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'includes raw content including initial indentation' do
|
140
|
+
expect(parse("p. foo\n donkey")).to eq [
|
141
|
+
element('p', {}, ['foo', "\n", ' donkey'])
|
142
|
+
]
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'includes raw content from multiple lines' do
|
146
|
+
expect(parse("p. foo\n donkey\n giraffe\n zebra\n")).to eq [
|
147
|
+
element('p', {}, ['foo', "\n", ' donkey', "\n", 'giraffe', "\n", ' zebra'])
|
148
|
+
]
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'includes empty lines in raw content' do
|
152
|
+
expect(parse("p. foo\n\n donkey\n\n giraffe\n")).to eq [
|
153
|
+
element('p', {}, ['foo', "\n", "\n", 'donkey', "\n", "\n", ' giraffe'])
|
154
|
+
]
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'does not include line break after empty block element and before data lines' do
|
158
|
+
expect(parse("p.\n donkey\n")).to eq [
|
159
|
+
element('p', {}, ['donkey'])
|
160
|
+
]
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'parses inline element in data lines' do
|
164
|
+
expect(parse("p.\n %emph{donkey}\n")).to eq [
|
165
|
+
element('p', {}, [
|
166
|
+
element('emph', {}, ['donkey'])
|
167
|
+
])
|
168
|
+
]
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'parses empty attributes' do
|
172
|
+
expect(parse('p[]. hi')).to eq [
|
173
|
+
element('p', {}, ['hi'])
|
174
|
+
]
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'parses single attribute' do
|
178
|
+
expect(parse('p[foo=bar]. hi')).to eq [
|
179
|
+
element('p', { 'foo' => 'bar' }, ['hi'])
|
180
|
+
]
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'parses single value-less attribute' do
|
184
|
+
expect(parse('p[foo]. hi')).to eq [
|
185
|
+
element('p', { 'foo' => 'foo' }, ['hi'])
|
186
|
+
]
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'parses multiple attributes' do
|
190
|
+
expect(parse('p[foo=bar,qux=donkey]. hi')).to eq [
|
191
|
+
element('p', { 'foo' => 'bar', 'qux' => 'donkey' }, ['hi'])
|
192
|
+
]
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'parses multiple value-less attributes' do
|
196
|
+
expect(parse('p[foo,qux]. hi')).to eq [
|
197
|
+
element('p', { 'foo' => 'foo', 'qux' => 'qux' }, ['hi'])
|
198
|
+
]
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'parses escaped attributes' do
|
202
|
+
expect(parse('p[foo=%],bar=%%,donkey=%,]. hi')).to eq [
|
203
|
+
element('p', { 'foo' => ']', 'bar' => '%', 'donkey' => ',' }, ['hi'])
|
204
|
+
]
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'parses attributes in empty block' do
|
208
|
+
expect(parse("p[foo=bar].\n hi")).to eq [
|
209
|
+
element('p', { 'foo' => 'bar' }, ['hi'])
|
210
|
+
]
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'parses block start on next line properly' do
|
214
|
+
expect(parse("p.\n this is not a child block.")).to eq [
|
215
|
+
element('p', {}, ['this is not a child block.'])
|
216
|
+
]
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'parses block start on next line with spacey' do
|
220
|
+
expect(parse("p.\n foo.bar")).to eq [
|
221
|
+
element('p', {}, ['foo.bar'])
|
222
|
+
]
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'parses child block without content' do
|
226
|
+
expect(parse("ul.\n li.\n p. You can.")).to eq [
|
227
|
+
element(
|
228
|
+
'ul', {},
|
229
|
+
[
|
230
|
+
element(
|
231
|
+
'li', {},
|
232
|
+
[
|
233
|
+
element('p', {}, ['You can.'])
|
234
|
+
]
|
235
|
+
)
|
236
|
+
]
|
237
|
+
)
|
238
|
+
]
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'parses child block without content at end' do
|
242
|
+
expect(parse("ul.\n li.")).to eq [
|
243
|
+
element(
|
244
|
+
'ul', {},
|
245
|
+
[
|
246
|
+
element('li', {}, [])
|
247
|
+
]
|
248
|
+
)
|
249
|
+
]
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'parses child block with attributes' do
|
253
|
+
expect(parse("ul.\n li[foo].")).to eq [
|
254
|
+
element(
|
255
|
+
'ul', {},
|
256
|
+
[
|
257
|
+
element('li', { 'foo' => 'foo' }, [])
|
258
|
+
]
|
259
|
+
)
|
260
|
+
]
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'does not parse' do
|
264
|
+
expect { parse('p') }.to raise_error(DMark::Parser::ParserError)
|
265
|
+
expect { parse('0') }.to raise_error(DMark::Parser::ParserError)
|
266
|
+
expect { parse('p0') }.to raise_error(DMark::Parser::ParserError)
|
267
|
+
expect { parse('0.') }.to raise_error(DMark::Parser::ParserError)
|
268
|
+
expect { parse('p. %') }.to raise_error(DMark::Parser::ParserError)
|
269
|
+
expect { parse('p. }') }.to raise_error(DMark::Parser::ParserError)
|
270
|
+
end
|
271
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: d-mark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Defreyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: treetop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.4'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -37,29 +51,27 @@ executables: []
|
|
37
51
|
extensions: []
|
38
52
|
extra_rdoc_files:
|
39
53
|
- LICENSE
|
40
|
-
- README.
|
54
|
+
- README.adoc
|
41
55
|
- NEWS.md
|
42
56
|
files:
|
43
57
|
- Gemfile
|
44
58
|
- Gemfile.lock
|
59
|
+
- Guardfile
|
45
60
|
- LICENSE
|
46
61
|
- NEWS.md
|
47
|
-
- README.
|
62
|
+
- README.adoc
|
48
63
|
- Rakefile
|
49
64
|
- d-mark.gemspec
|
50
|
-
- lib/
|
51
|
-
- lib/
|
52
|
-
- lib/
|
53
|
-
- lib/
|
54
|
-
- lib/
|
55
|
-
- lib/dmark/translator.rb
|
56
|
-
- lib/dmark/version.rb
|
65
|
+
- lib/d-mark.rb
|
66
|
+
- lib/d-mark/cli.rb
|
67
|
+
- lib/d-mark/parser.rb
|
68
|
+
- lib/d-mark/translator.rb
|
69
|
+
- lib/d-mark/version.rb
|
57
70
|
- samples/identifiers-and-patterns.dmark
|
58
|
-
- samples/
|
59
|
-
-
|
60
|
-
-
|
61
|
-
-
|
62
|
-
- tasks/test.rake
|
71
|
+
- samples/trivial.dmark
|
72
|
+
- samples/trivial.rb
|
73
|
+
- spec/d-mark/parser_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
63
75
|
homepage: http://rubygems.org/gems/d-mark
|
64
76
|
licenses:
|
65
77
|
- MIT
|
@@ -67,7 +79,7 @@ metadata: {}
|
|
67
79
|
post_install_message:
|
68
80
|
rdoc_options:
|
69
81
|
- "--main"
|
70
|
-
- README.
|
82
|
+
- README.adoc
|
71
83
|
require_paths:
|
72
84
|
- lib
|
73
85
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -82,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
94
|
version: '0'
|
83
95
|
requirements: []
|
84
96
|
rubyforge_project:
|
85
|
-
rubygems_version: 2.5.
|
97
|
+
rubygems_version: 2.5.2
|
86
98
|
signing_key:
|
87
99
|
specification_version: 4
|
88
100
|
summary: markup language for writing text
|
data/README.md
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
D★Mark
|
2
|
-
======
|
3
|
-
|
4
|
-
**Status:** experimental — use at your own risk!
|
5
|
-
|
6
|
-
_D★Mark_ is a markup language for writing text.
|
7
|
-
|
8
|
-
It is aimed at being able to write semantically meaningful text without limiting itself to the semantics provided by HTML or Markdown.
|
9
|
-
|
10
|
-
## Usage
|
11
|
-
|
12
|
-
Handling a D★Mark file consists of three stages: lexing, parsing, and translating.
|
13
|
-
|
14
|
-
The lexing stage converts the data into a stream of tokens. Construct a lexer with the data as input, and call `#run` to get the tokens, catching any `DMark::Lexer::LexerError`:
|
15
|
-
|
16
|
-
begin
|
17
|
-
tokens = DMark::Lexer.new(File.read(ARGV[0])).run
|
18
|
-
rescue DMark::Lexer::LexerError => e
|
19
|
-
$stderr.puts e.message_for_tty
|
20
|
-
exit 1
|
21
|
-
end
|
22
|
-
|
23
|
-
The parsing stage converts the stream of tokens into a node tree. Construct a parser with the tokens as input, and call `#run` to get the tree.
|
24
|
-
|
25
|
-
tree = DMark::Parser.new(tokens).run
|
26
|
-
|
27
|
-
The translating stage is not the responsibility of D★Mark. A translator is part of the domain of the source text, and D★Mark only deals with syntax rather than semantics. A translator will run over the tree and convert it into something else (usually another string). To do so, handle each node type (`RootNode`, `TextNode`, `ElementNode`). For example, the following translator will convert the tree into something that resembles XML:
|
28
|
-
|
29
|
-
class MyXMLLikeTranslator < DMark::Translator
|
30
|
-
def handle(node)
|
31
|
-
case node
|
32
|
-
when DMark::Nodes::RootNode
|
33
|
-
handle_children(node)
|
34
|
-
when DMark::Nodes::TextNode
|
35
|
-
out << node.text
|
36
|
-
when DMark::Nodes::ElementNode
|
37
|
-
out << "<#{node.name}>"
|
38
|
-
handle_children(node)
|
39
|
-
out << "</#{node.name}>"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
result = MyXMLLikeTranslator.new(tree).run
|
45
|
-
puts result
|
46
|
-
|
47
|
-
## Samples
|
48
|
-
|
49
|
-
The `samples/` directory contains some sample D★Mark files. They can be converted to HTML by running the `scripts/translate-to-html.rb` Ruby script, passing in the name of the file. The resulting HTML will be printed to standard output. For example:
|
50
|
-
|
51
|
-
ruby scripts/translate-to-html.rb samples/identifiers-and-patterns.dmark
|
52
|
-
|
53
|
-
## Format
|
54
|
-
|
55
|
-
_D★Mark_ knows two constructs:
|
56
|
-
|
57
|
-
* Block-level elements. For example:
|
58
|
-
|
59
|
-
p. Patterns are used to find items and layouts based on their identifier. They come in three varieties.
|
60
|
-
|
61
|
-
* Inline elements. For example:
|
62
|
-
|
63
|
-
p. Identifiers come in two types: the %emph{full} type, new in Nanoc 4, and the %emph{legacy} type, used in Nanoc 3.
|
64
|
-
|
65
|
-
Block-level elements can be nested. For example:
|
66
|
-
|
67
|
-
ul.
|
68
|
-
li. glob patterns
|
69
|
-
li. regular expression patterns
|
70
|
-
li. legacy patterns
|