d-mark 0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|