d-mark 1.0.0a1 → 1.0.0a2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/NEWS.md +6 -0
- data/README.adoc +5 -204
- data/Rakefile +4 -0
- data/lib/d-mark/parser.rb +7 -29
- data/lib/d-mark/version.rb +1 -1
- data/spec/d-mark/parser_spec.rb +55 -44
- metadata +2 -3
- data/samples/identifiers-and-patterns.dmark +0 -539
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 686fe4c2cf9132e4bfd42debaac837d66b911c40
|
4
|
+
data.tar.gz: 3649616bac8b3eccb25de17e433ecea93af77bc9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b419728d8c5bf01674fb87c1401f6a47c8a7d90883efce6fce0de6612f50060f5cb3dcf740e77ce6601df04992e7a2ad050a209631e8062fc2e1b5e89c63745b
|
7
|
+
data.tar.gz: 7404cc61b20b0c2fed2d7dd8fb76127e8c8ea30c6f42d2c6525297c027bf4d6b84a5deea1b311e621c305e9c82615f0ab0b8da187c6894ec690986e302edc166
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
d-mark (1.0.
|
4
|
+
d-mark (1.0.0a2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -11,7 +11,7 @@ GEM
|
|
11
11
|
json
|
12
12
|
simplecov
|
13
13
|
url
|
14
|
-
coderay (1.1.
|
14
|
+
coderay (1.1.1)
|
15
15
|
diff-lcs (1.2.5)
|
16
16
|
docile (1.1.5)
|
17
17
|
ffi (1.9.10)
|
@@ -38,7 +38,7 @@ GEM
|
|
38
38
|
notiffany (0.0.8)
|
39
39
|
nenv (~> 0.1)
|
40
40
|
shellany (~> 0.0)
|
41
|
-
parser (2.3.0.
|
41
|
+
parser (2.3.0.6)
|
42
42
|
ast (~> 2.2)
|
43
43
|
powerpack (0.1.1)
|
44
44
|
pry (0.10.3)
|
@@ -54,7 +54,7 @@ GEM
|
|
54
54
|
rspec-core (~> 3.4.0)
|
55
55
|
rspec-expectations (~> 3.4.0)
|
56
56
|
rspec-mocks (~> 3.4.0)
|
57
|
-
rspec-core (3.4.
|
57
|
+
rspec-core (3.4.3)
|
58
58
|
rspec-support (~> 3.4.0)
|
59
59
|
rspec-expectations (3.4.0)
|
60
60
|
diff-lcs (>= 1.2.0, < 2.0)
|
data/NEWS.md
CHANGED
data/README.adoc
CHANGED
@@ -8,214 +8,15 @@ image:http://img.shields.io/codecov/c/github/ddfreyne/d-mark.svg[Code Coverage,
|
|
8
8
|
|
9
9
|
_D★Mark_ is a language for marking up prose. It facilitates writing semantically meaningful text, without limiting itself to the semantics provided by HTML or Markdown.
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
[source]
|
14
|
-
----
|
15
|
-
h2. Patterns
|
16
|
-
|
17
|
-
para. Patterns are used to find items and layouts based on their identifier. They come in three varieties:
|
18
|
-
|
19
|
-
list[unordered].
|
20
|
-
item. glob patterns
|
21
|
-
item. regular expression patterns
|
22
|
-
item. legacy patterns
|
23
|
-
|
24
|
-
para. A glob pattern that matches every item is %pattern{/**/*}. A glob pattern that matches every item/layout with the extension %filename{md} is %glob{/**/*.md}.
|
25
|
-
----
|
26
|
-
|
27
|
-
== Samples
|
28
|
-
|
29
|
-
The `samples/` directory contains some sample D★Mark files. They can be processed by invoking the appropriate script with the same filename. For example:
|
30
|
-
|
31
|
-
....
|
32
|
-
% bundle exec ruby samples/trivial.rb
|
33
|
-
<p>I’m a <em>trivial</em> example!</p>
|
34
|
-
....
|
35
|
-
|
36
|
-
== Structure of a D★Mark document
|
37
|
-
|
38
|
-
_D★Mark_ knows two constructs:
|
39
|
-
|
40
|
-
Block-level elements::
|
41
|
-
Every non-blank line of a D★Mark document corresponds to a block. A block can be a paragraph, a list, a header, a source code listing, or more. They start with the name of the element, a period, a space character, followed by the content. For example:
|
42
|
-
+
|
43
|
-
[source]
|
44
|
-
----
|
45
|
-
para. Patterns are used to find items and layouts based on their identifier. They come in three varieties.
|
46
|
-
----
|
47
|
-
|
48
|
-
Inline elements::
|
49
|
-
Inside a block, text can be marked up using inline elements, which start with a percentage sign, the name of the element, and the content within braces. For example, `%emph{crazy}` is an `emph` element with the content `crazy`.
|
50
|
-
|
51
|
-
Block-level elements can be nested. To do so, indent the nested block two spaces deeper than the enclosing block. For example, the following defines a `list` element with three `item` elements inside it:
|
52
|
-
|
53
|
-
[source]
|
54
|
-
----
|
55
|
-
list[unordered].
|
56
|
-
item. glob patterns
|
57
|
-
item. regular expression patterns
|
58
|
-
item. legacy patterns
|
59
|
-
----
|
60
|
-
|
61
|
-
Block-level elements can also include plain text. In this case, the content is not wrapped inside a nested block-level element. This is particularly useful for source code listing. For example:
|
62
|
-
|
63
|
-
[source]
|
64
|
-
----
|
65
|
-
listing[lang=ruby].
|
66
|
-
identifier = Nanoc::Identifier.new('/about.md')
|
67
|
-
|
68
|
-
identifier.without_ext
|
69
|
-
# => "/about"
|
70
|
-
|
71
|
-
identifier.ext
|
72
|
-
# => "md"
|
73
|
-
----
|
74
|
-
|
75
|
-
Block-level elements and inline elements are identical in the tree representation of D★Mark. This means that any inline element can be rewritten as a block-level element.
|
76
|
-
|
77
|
-
NOTE: To do: Elaborate on the distinction and similarity of block-level and inline elements.
|
78
|
-
|
79
|
-
NOTE: To do: Describe escaping rules.
|
80
|
-
|
81
|
-
=== Attributes
|
82
|
-
|
83
|
-
Both block and inline elements can also have attributes. Attributes are enclosed in square brackets after the element name, as a comma-separated list of key-value pairs separated by an equal sign. The value part, along with the equal sign, can be omitted, in which case the value will be equal to the key name.
|
84
|
-
|
85
|
-
For example:
|
86
|
-
|
87
|
-
* `%code[lang=ruby]{Nanoc::VERSION}` is an inline `code` element with the `lang` attribute set to `ruby`.
|
88
|
-
|
89
|
-
* `%only[web]{Refer to the release notes for details.}` is an inline `only` element with the `web` attribute set to `web`.
|
90
|
-
|
91
|
-
* `h2[id=donkey]. All about donkeys` is a block-level `h2` element with the `id` attribute set to `donkey`.
|
92
|
-
|
93
|
-
* `p[print]. This is a paragraph that only readers of the book will see.` is a block-level `para` element with the `print` attribute set to `print`.
|
94
|
-
|
95
|
-
NOTE: The behavior of keys with missing values might change to default to booleans rather than to the key name.
|
11
|
+
If you’re a technical writer looking for a flexible markup language, D★Mark might be a good fit.
|
96
12
|
|
97
|
-
|
98
|
-
|
99
|
-
Be extensible::
|
100
|
-
D★Mark defines only the syntax of the markup language, and doesn’t bother with semantics. It does not prescribe which element names are valid in the context of a vocabulary, because it does not come with a vocabulary.
|
101
|
-
|
102
|
-
Be simple::
|
103
|
-
Simplicity implies being easy to write and easy to parse. D★Mark eschews ambiguity and aims to have a short formal syntactical definition. This also means that it is easy to syntax highlight.
|
104
|
-
|
105
|
-
Be compact::
|
106
|
-
Introduce as little extra syntax as possible.
|
107
|
-
|
108
|
-
== Comparison with other languages
|
109
|
-
|
110
|
-
D★Mark takes inspiration from a variety of other languages.
|
111
|
-
|
112
|
-
HTML::
|
113
|
-
HTML is syntactically unambiguous, but comparatively more verbose than other languages. It also prescribes only a small set of elements, which makes it awkward to use for prose that requires more thorough markup. It is possible use `span` or `div` elements with custom classes, but this approach turns an already verbose language into something even more verbose.
|
114
|
-
+
|
115
|
-
[source,html]
|
116
|
-
----
|
117
|
-
<p>A glob pattern that matches every item is <span class="pattern attr-kind-glob">/**/*</span>.</p>
|
118
|
-
----
|
119
|
-
+
|
120
|
-
[source,d-mark]
|
121
|
-
----
|
122
|
-
para. A glob pattern that matches every item is %pattern[glob]{/**/*}.
|
123
|
-
----
|
124
|
-
|
125
|
-
XML::
|
126
|
-
Similar to HTML, with the major difference that XML does not prescribe a set of elements.
|
127
|
-
+
|
128
|
-
[source,xml]
|
129
|
-
----
|
130
|
-
<para>A glob pattern that matches every item is <pattern kind="glob">/**/*</pattern>.</para>
|
131
|
-
----
|
132
|
-
+
|
133
|
-
[source,d-mark]
|
134
|
-
----
|
135
|
-
para. A glob pattern that matches every item is %pattern[glob]{/**/*}.
|
136
|
-
----
|
13
|
+
Here’s an example of D★Mark:
|
137
14
|
|
138
|
-
Markdown::
|
139
|
-
Markdown has a compact syntax, but is complex and ambiguous, as evidenced by the many different mutually incompatible implementations. It prescribes a small set of elements (smaller even than HTML). It supports embedding raw HTML, which in theory makes it possible to combine the best of both worlds, but in practice leads to markup that is harder to read than either Markdown or HTML separately, and occasionally trips up the parser and syntax highlighter.
|
140
|
-
+
|
141
15
|
[source]
|
142
16
|
----
|
143
|
-
|
144
|
-
----
|
145
|
-
+
|
146
|
-
[source,d-mark]
|
147
|
-
----
|
148
|
-
para. A glob pattern that matches every item is %pattern[glob]{/**/*}.
|
149
|
-
----
|
150
|
-
|
151
|
-
AsciiDoc::
|
152
|
-
AsciiDoc, along with its AsciiDoctor variant, are syntactically unambiguous, but complex languages. They prescribe a comparatively large set of elements which translates well to DocBook and HTML. They do not support custom markup or embedding raw HTML, which makes them harder t use for prose that requires more complex markup.
|
153
|
-
+
|
154
|
-
_(No example, as this example cannot be represented with AsciiDoc.)_
|
155
|
-
|
156
|
-
TeX, LaTeX::
|
157
|
-
TeX is a turing-complete programming language, as opposed to a markup language, intended for typesetting. This makes it impractical for using it as the source for converting it to other formats. Its syntax is simple and compact, and served as an inspiration for D★Mark.
|
158
|
-
+
|
159
|
-
[source,latex]
|
160
|
-
----
|
161
|
-
A glob pattern that matches every item is \pattern[glob]{/**/*}.
|
162
|
-
----
|
163
|
-
+
|
164
|
-
[source,d-mark]
|
165
|
-
----
|
166
|
-
para. A glob pattern that matches every item is %pattern[glob]{/**/*}.
|
167
|
-
----
|
168
|
-
|
169
|
-
JSON, YAML::
|
170
|
-
JSON and YAML are data interchange formats rather than markup languages, and thus are not well-suited for marking up prose.
|
171
|
-
+
|
172
|
-
[source,json]
|
173
|
-
----
|
174
|
-
[
|
175
|
-
"A glob pattern that matches every item is ",
|
176
|
-
["pattern", {"kind": "glob"}, ["/**/*"]],
|
177
|
-
"."
|
178
|
-
]
|
179
|
-
----
|
180
|
-
+
|
181
|
-
[source,d-mark]
|
182
|
-
----
|
183
|
-
para. A glob pattern that matches every item is %pattern[glob]{/**/*}.
|
184
|
-
----
|
17
|
+
para. This a paragraph; an element in block form containing some text.
|
185
18
|
|
186
|
-
|
187
|
-
|
188
|
-
NOTE: To do: write this section.
|
189
|
-
|
190
|
-
== Programmatic usage
|
191
|
-
|
192
|
-
Handling a D★Mark file consists of two stages: parsing and translating.
|
193
|
-
|
194
|
-
The parsing stage converts text into a list of nodes. Construct a parser with the tokens as input, and call `#run` to get the list of nodes.
|
195
|
-
|
196
|
-
[source,ruby]
|
19
|
+
note[only=web]. This is a note that will %emph{only} show up on web.
|
197
20
|
----
|
198
|
-
content = File.read(ARGV[0])
|
199
|
-
nodes = DMark::Parser.new(content).run
|
200
|
-
----
|
201
|
-
|
202
|
-
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 (`DMark::ElementNode` or `String`). For example, the following translator will convert the tree into something that resembles XML:
|
203
21
|
|
204
|
-
[
|
205
|
-
----
|
206
|
-
class MyXMLLikeTranslator < DMark::Translator
|
207
|
-
def handle(node)
|
208
|
-
case node
|
209
|
-
when String
|
210
|
-
out << node
|
211
|
-
when DMark::ElementNode
|
212
|
-
out << "<#{node.name}>"
|
213
|
-
handle_children(node)
|
214
|
-
out << "</#{node.name}>"
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
result = MyXMLLikeTranslator.new(nodes).run
|
220
|
-
puts result
|
221
|
-
----
|
22
|
+
For details, see the http://ddfreyne.github.io/d-mark/[D★Mark web page].
|
data/Rakefile
CHANGED
data/lib/d-mark/parser.rb
CHANGED
@@ -133,32 +133,11 @@ module DMark
|
|
133
133
|
|
134
134
|
# FIXME: ugly and duplicated
|
135
135
|
def try_read_block_start
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
case peek_char
|
143
|
-
when '['
|
144
|
-
true
|
145
|
-
when '.'
|
146
|
-
advance
|
147
|
-
[' ', "\n", nil].include?(peek_char)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
@pos = old_pos
|
152
|
-
success
|
153
|
-
end
|
154
|
-
|
155
|
-
# FIXME: ugly and duplicated
|
156
|
-
def try_read_identifier_head
|
157
|
-
char = peek_char
|
158
|
-
case char
|
159
|
-
when 'a'..'z'
|
160
|
-
advance
|
161
|
-
char
|
136
|
+
if peek_char == '#'
|
137
|
+
next_char = peek_char(@pos + 1)
|
138
|
+
('a'..'z').cover?(next_char)
|
139
|
+
else
|
140
|
+
false
|
162
141
|
end
|
163
142
|
end
|
164
143
|
|
@@ -187,6 +166,7 @@ module DMark
|
|
187
166
|
end
|
188
167
|
|
189
168
|
def read_single_block
|
169
|
+
read_char('#')
|
190
170
|
identifier = read_identifier
|
191
171
|
|
192
172
|
attributes =
|
@@ -196,8 +176,6 @@ module DMark
|
|
196
176
|
{}
|
197
177
|
end
|
198
178
|
|
199
|
-
read_char('.')
|
200
|
-
|
201
179
|
case peek_char
|
202
180
|
when nil, "\n"
|
203
181
|
advance
|
@@ -374,7 +352,7 @@ module DMark
|
|
374
352
|
def read_percent_body
|
375
353
|
char = peek_char
|
376
354
|
case char
|
377
|
-
when '%', '}'
|
355
|
+
when '%', '}', '#'
|
378
356
|
advance
|
379
357
|
char.to_s
|
380
358
|
when nil, "\n"
|
data/lib/d-mark/version.rb
CHANGED
data/spec/d-mark/parser_spec.rb
CHANGED
@@ -9,26 +9,26 @@ end
|
|
9
9
|
describe 'DMark::Parser#parser' do
|
10
10
|
it 'parses' do
|
11
11
|
expect(parse('')).to eq []
|
12
|
-
expect(parse('p
|
13
|
-
expect(parse('p
|
14
|
-
expect(parse('p
|
15
|
-
expect(parse('p
|
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
16
|
end
|
17
17
|
|
18
18
|
it 'parses escaped % in block' do
|
19
|
-
expect(parse('p
|
19
|
+
expect(parse('#p %%')).to eq [
|
20
20
|
element('p', {}, ['%'])
|
21
21
|
]
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'parses escaped } in block' do
|
25
|
-
expect(parse('p
|
25
|
+
expect(parse('#p %}')).to eq [
|
26
26
|
element('p', {}, ['}'])
|
27
27
|
]
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'parses escaped % in inline block' do
|
31
|
-
expect(parse('p
|
31
|
+
expect(parse('#p %foo{%%}')).to eq [
|
32
32
|
element(
|
33
33
|
'p', {},
|
34
34
|
[
|
@@ -39,7 +39,7 @@ describe 'DMark::Parser#parser' do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'parses escaped } in inline block' do
|
42
|
-
expect(parse('p
|
42
|
+
expect(parse('#p %foo{%}}')).to eq [
|
43
43
|
element(
|
44
44
|
'p', {},
|
45
45
|
[
|
@@ -49,7 +49,7 @@ describe 'DMark::Parser#parser' do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'parses block with text and element content' do
|
52
|
-
expect(parse('p
|
52
|
+
expect(parse('#p hi %em{ho}')).to eq [
|
53
53
|
element(
|
54
54
|
'p', {}, [
|
55
55
|
'hi ',
|
@@ -60,7 +60,7 @@ describe 'DMark::Parser#parser' do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'parses block with text and element content, followed by newline' do
|
63
|
-
expect(parse("p
|
63
|
+
expect(parse("#p hi %em{ho}\n")).to eq [
|
64
64
|
element(
|
65
65
|
'p', {}, [
|
66
66
|
'hi ',
|
@@ -71,7 +71,7 @@ describe 'DMark::Parser#parser' do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'parses children' do
|
74
|
-
expect(parse("p
|
74
|
+
expect(parse("#p hi %em{ho}\n #p child p")).to eq [
|
75
75
|
element(
|
76
76
|
'p', {}, [
|
77
77
|
'hi ',
|
@@ -83,7 +83,7 @@ describe 'DMark::Parser#parser' do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'parses children multiple levels deep' do
|
86
|
-
expect(parse("p
|
86
|
+
expect(parse("#p hi %em{ho}\n #p child p\n #p subchild p")).to eq [
|
87
87
|
element(
|
88
88
|
'p', {}, [
|
89
89
|
'hi ',
|
@@ -104,7 +104,7 @@ describe 'DMark::Parser#parser' do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'ignores blanks' do
|
107
|
-
expect(parse("p
|
107
|
+
expect(parse("#p foo\n \n #p bar\n \n\n #p qux")).to eq [
|
108
108
|
element(
|
109
109
|
'p', {}, [
|
110
110
|
'foo',
|
@@ -124,106 +124,104 @@ describe 'DMark::Parser#parser' do
|
|
124
124
|
end
|
125
125
|
|
126
126
|
it 'reads multiple consecutive blocks' do
|
127
|
-
expect(parse("p
|
127
|
+
expect(parse("#p foo\n#p bar")).to eq [
|
128
128
|
element('p', {}, ['foo']),
|
129
129
|
element('p', {}, ['bar'])
|
130
130
|
]
|
131
131
|
end
|
132
132
|
|
133
133
|
it 'includes raw content' do
|
134
|
-
expect(parse("p
|
134
|
+
expect(parse("#p foo\n donkey")).to eq [
|
135
135
|
element('p', {}, %W(foo \n donkey))
|
136
136
|
]
|
137
137
|
end
|
138
138
|
|
139
139
|
it 'includes raw content including initial indentation' do
|
140
|
-
expect(parse("p
|
140
|
+
expect(parse("#p foo\n donkey")).to eq [
|
141
141
|
element('p', {}, ['foo', "\n", ' donkey'])
|
142
142
|
]
|
143
143
|
end
|
144
144
|
|
145
145
|
it 'includes raw content from multiple lines' do
|
146
|
-
expect(parse("p
|
146
|
+
expect(parse("#p foo\n donkey\n giraffe\n zebra\n")).to eq [
|
147
147
|
element('p', {}, ['foo', "\n", ' donkey', "\n", 'giraffe', "\n", ' zebra'])
|
148
148
|
]
|
149
149
|
end
|
150
150
|
|
151
151
|
it 'includes empty lines in raw content' do
|
152
|
-
expect(parse("p
|
152
|
+
expect(parse("#p foo\n\n donkey\n\n giraffe\n")).to eq [
|
153
153
|
element('p', {}, ['foo', "\n", "\n", 'donkey', "\n", "\n", ' giraffe'])
|
154
154
|
]
|
155
155
|
end
|
156
156
|
|
157
157
|
it 'does not include line break after empty block element and before data lines' do
|
158
|
-
expect(parse("p
|
158
|
+
expect(parse("#p\n donkey\n")).to eq [
|
159
159
|
element('p', {}, ['donkey'])
|
160
160
|
]
|
161
161
|
end
|
162
162
|
|
163
163
|
it 'parses inline element in data lines' do
|
164
|
-
expect(parse("p
|
165
|
-
element('p', {}, [
|
166
|
-
element('emph', {}, ['donkey'])
|
167
|
-
])
|
164
|
+
expect(parse("#p\n %emph{donkey}")).to eq [
|
165
|
+
element('p', {}, [element('emph', {}, ['donkey'])])
|
168
166
|
]
|
169
167
|
end
|
170
168
|
|
171
169
|
it 'parses empty attributes' do
|
172
|
-
expect(parse('p[]
|
170
|
+
expect(parse('#p[] hi')).to eq [
|
173
171
|
element('p', {}, ['hi'])
|
174
172
|
]
|
175
173
|
end
|
176
174
|
|
177
175
|
it 'parses single attribute' do
|
178
|
-
expect(parse('p[foo=bar]
|
176
|
+
expect(parse('#p[foo=bar] hi')).to eq [
|
179
177
|
element('p', { 'foo' => 'bar' }, ['hi'])
|
180
178
|
]
|
181
179
|
end
|
182
180
|
|
183
181
|
it 'parses single value-less attribute' do
|
184
|
-
expect(parse('p[foo]
|
182
|
+
expect(parse('#p[foo] hi')).to eq [
|
185
183
|
element('p', { 'foo' => 'foo' }, ['hi'])
|
186
184
|
]
|
187
185
|
end
|
188
186
|
|
189
187
|
it 'parses multiple attributes' do
|
190
|
-
expect(parse('p[foo=bar,qux=donkey]
|
188
|
+
expect(parse('#p[foo=bar,qux=donkey] hi')).to eq [
|
191
189
|
element('p', { 'foo' => 'bar', 'qux' => 'donkey' }, ['hi'])
|
192
190
|
]
|
193
191
|
end
|
194
192
|
|
195
193
|
it 'parses multiple value-less attributes' do
|
196
|
-
expect(parse('p[foo,qux]
|
194
|
+
expect(parse('#p[foo,qux] hi')).to eq [
|
197
195
|
element('p', { 'foo' => 'foo', 'qux' => 'qux' }, ['hi'])
|
198
196
|
]
|
199
197
|
end
|
200
198
|
|
201
199
|
it 'parses escaped attributes' do
|
202
|
-
expect(parse('p[foo=%],bar=%%,donkey=%,]
|
200
|
+
expect(parse('#p[foo=%],bar=%%,donkey=%,] hi')).to eq [
|
203
201
|
element('p', { 'foo' => ']', 'bar' => '%', 'donkey' => ',' }, ['hi'])
|
204
202
|
]
|
205
203
|
end
|
206
204
|
|
207
205
|
it 'parses attributes in empty block' do
|
208
|
-
expect(parse("p[foo=bar]
|
206
|
+
expect(parse("#p[foo=bar]\n hi")).to eq [
|
209
207
|
element('p', { 'foo' => 'bar' }, ['hi'])
|
210
208
|
]
|
211
209
|
end
|
212
210
|
|
213
211
|
it 'parses block start on next line properly' do
|
214
|
-
expect(parse("p
|
212
|
+
expect(parse("#p\n this is not a child block.")).to eq [
|
215
213
|
element('p', {}, ['this is not a child block.'])
|
216
214
|
]
|
217
215
|
end
|
218
216
|
|
219
217
|
it 'parses block start on next line with spacey' do
|
220
|
-
expect(parse("p
|
218
|
+
expect(parse("#p\n foo.bar")).to eq [
|
221
219
|
element('p', {}, ['foo.bar'])
|
222
220
|
]
|
223
221
|
end
|
224
222
|
|
225
223
|
it 'parses child block without content' do
|
226
|
-
expect(parse("ul
|
224
|
+
expect(parse("#ul\n #li\n #p You can.")).to eq [
|
227
225
|
element(
|
228
226
|
'ul', {},
|
229
227
|
[
|
@@ -239,7 +237,7 @@ describe 'DMark::Parser#parser' do
|
|
239
237
|
end
|
240
238
|
|
241
239
|
it 'parses child block without content at end' do
|
242
|
-
expect(parse("ul
|
240
|
+
expect(parse("#ul\n #li")).to eq [
|
243
241
|
element(
|
244
242
|
'ul', {},
|
245
243
|
[
|
@@ -250,7 +248,7 @@ describe 'DMark::Parser#parser' do
|
|
250
248
|
end
|
251
249
|
|
252
250
|
it 'parses child block with attributes' do
|
253
|
-
expect(parse("ul
|
251
|
+
expect(parse("#ul\n #li[foo]")).to eq [
|
254
252
|
element(
|
255
253
|
'ul', {},
|
256
254
|
[
|
@@ -261,42 +259,55 @@ describe 'DMark::Parser#parser' do
|
|
261
259
|
end
|
262
260
|
|
263
261
|
it 'parses document starting with blank lines' do
|
264
|
-
expect(parse(" \n \
|
262
|
+
expect(parse(" \n \n#p Hi!")).to eq [
|
265
263
|
element('p', {}, ['Hi!'])
|
266
264
|
]
|
267
265
|
end
|
268
266
|
|
267
|
+
it 'parses escaped indented line' do
|
268
|
+
expect(parse("#listing\n %#h1 Foo\n")).to eq [
|
269
|
+
element('listing', {}, ['#', 'h1 Foo'])
|
270
|
+
]
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'parses escaped indented line with attributes' do
|
274
|
+
expect(parse("#listing\n %#h1[donkey] Foo\n")).to eq [
|
275
|
+
element('listing', {}, ['#', 'h1[donkey] Foo'])
|
276
|
+
]
|
277
|
+
end
|
278
|
+
|
269
279
|
it 'does not parse percent escapes' do
|
270
|
-
expect { parse('p
|
280
|
+
expect { parse('#p %ref[url=https://github.com/pulls?q=is%3Aopen+user%3Ananoc]{eek}') }
|
271
281
|
.to raise_error(DMark::Parser::ParserError, 'parse error at line 1, col 43: expected "%", "," or "]" after "%", but got "3"')
|
272
282
|
end
|
273
283
|
|
274
284
|
it 'does not parse attribute values ending with an end-of-file' do
|
275
|
-
expect { parse('p
|
285
|
+
expect { parse('#p %ref[url=hello') }
|
276
286
|
.to raise_error(DMark::Parser::ParserError, 'parse error at line 1, col 18: unexpected file end in attribute value')
|
277
287
|
end
|
278
288
|
|
279
289
|
it 'does not parse attribute values ending with a line break' do
|
280
|
-
expect { parse("p
|
290
|
+
expect { parse("#p %ref[url=hello\n") }
|
281
291
|
.to raise_error(DMark::Parser::ParserError, 'parse error at line 1, col 18: unexpected line break in attribute value')
|
282
292
|
end
|
283
293
|
|
284
294
|
it 'does not parse escaped attribute values ending with an end-of-file' do
|
285
|
-
expect { parse('p
|
295
|
+
expect { parse('#p %ref[url=hello%') }
|
286
296
|
.to raise_error(DMark::Parser::ParserError, 'parse error at line 1, col 19: unexpected file end in attribute value')
|
287
297
|
end
|
288
298
|
|
289
299
|
it 'does not parse escaped attribute values ending with a line break' do
|
290
|
-
expect { parse("p
|
300
|
+
expect { parse("#p %ref[url=hello%\n") }
|
291
301
|
.to raise_error(DMark::Parser::ParserError, 'parse error at line 1, col 19: unexpected line break in attribute value')
|
292
302
|
end
|
293
303
|
|
294
304
|
it 'does not parse' do
|
305
|
+
expect { parse('#') }.to raise_error(DMark::Parser::ParserError)
|
295
306
|
expect { parse('p') }.to raise_error(DMark::Parser::ParserError)
|
296
307
|
expect { parse('0') }.to raise_error(DMark::Parser::ParserError)
|
297
308
|
expect { parse('p0') }.to raise_error(DMark::Parser::ParserError)
|
298
|
-
expect { parse('0
|
299
|
-
expect { parse('p
|
300
|
-
expect { parse('p
|
309
|
+
expect { parse('#0') }.to raise_error(DMark::Parser::ParserError)
|
310
|
+
expect { parse('#p %') }.to raise_error(DMark::Parser::ParserError)
|
311
|
+
expect { parse('#p }') }.to raise_error(DMark::Parser::ParserError)
|
301
312
|
end
|
302
313
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: d-mark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.0a2
|
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-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -54,7 +54,6 @@ files:
|
|
54
54
|
- lib/d-mark/parser.rb
|
55
55
|
- lib/d-mark/translator.rb
|
56
56
|
- lib/d-mark/version.rb
|
57
|
-
- samples/identifiers-and-patterns.dmark
|
58
57
|
- samples/trivial.dmark
|
59
58
|
- samples/trivial.rb
|
60
59
|
- spec/d-mark/element_node_spec.rb
|
@@ -1,539 +0,0 @@
|
|
1
|
-
p. In Nanoc, every item (page or asset) and every layout has a unique %firstterm{identifier}: a string derived from the file’s path. A %firstterm{pattern} is an expression that is used to select items or layouts based on their identifier.
|
2
|
-
|
3
|
-
h2. Identifiers
|
4
|
-
|
5
|
-
p. Identifiers come in two types: the %emph{full} type, new in Nanoc 4, and the %emph{legacy} type, used in Nanoc 3.
|
6
|
-
|
7
|
-
dl.
|
8
|
-
dt. full
|
9
|
-
dd. An identifier with the full type is the filename, with the path to the content directory removed. For example, the file %filename{/Users/denis/stoneship/content/about.md} will have the full identifier %identifier{/about.md}.
|
10
|
-
|
11
|
-
dt. legacy
|
12
|
-
dd. An identifier with the legacy type is the filename, with the path to the content directory removed, the extension removed, and a slash appended. For example, the file %filename{/Users/denis/stoneship/content/about.md} will have the legacy identifier %identifier{/about/}. This corresponds closely with paths in clean URLs.
|
13
|
-
|
14
|
-
p. The following methods are useful for full identifiers:
|
15
|
-
|
16
|
-
dl.
|
17
|
-
dt. %code{identifier.without_ext} → %class{String}
|
18
|
-
dd. identifier with the last extension removed
|
19
|
-
|
20
|
-
dt. %code{identifier.without_exts} → %class{String}
|
21
|
-
dd. identifier with all extensions removed
|
22
|
-
|
23
|
-
dt. %code{identifier.ext} → %class{String}
|
24
|
-
dd. the last extension of this identifier
|
25
|
-
|
26
|
-
dt. %code{identifier.exts} → %class{String}
|
27
|
-
dd. all extensions of this identifier
|
28
|
-
|
29
|
-
dt. %code{identifier + string} → %class{String}
|
30
|
-
dd. identifier with the given string appended
|
31
|
-
|
32
|
-
p. Here are some examples:
|
33
|
-
|
34
|
-
listing[lang=ruby].
|
35
|
-
identifier = Nanoc::Identifier.new('/about.md')
|
36
|
-
|
37
|
-
identifier.without_ext
|
38
|
-
# => "/about"
|
39
|
-
|
40
|
-
identifier.ext
|
41
|
-
# => "md"
|
42
|
-
|
43
|
-
p. The following method is useful for legacy identifiers:
|
44
|
-
|
45
|
-
dl[legacy].
|
46
|
-
dt. %code{identifier.chop} → %class{String}
|
47
|
-
dd. identifier with the last character removed
|
48
|
-
|
49
|
-
p. Here are some examples:
|
50
|
-
|
51
|
-
listing[lang=ruby].
|
52
|
-
identifier = Nanoc::Identifier.new('/about/', type: :legacy)
|
53
|
-
|
54
|
-
identifier.chop
|
55
|
-
# => "/about"
|
56
|
-
|
57
|
-
identifier.chop + '.html'
|
58
|
-
# => "/about.html"
|
59
|
-
|
60
|
-
identifier + 'index.html'
|
61
|
-
# => "/about/index.html"
|
62
|
-
|
63
|
-
h2. Patterns
|
64
|
-
|
65
|
-
p. Patterns are used to find items and layouts based on their identifier. They come in three varieties:
|
66
|
-
|
67
|
-
ul.
|
68
|
-
li. glob patterns
|
69
|
-
li. regular expression patterns
|
70
|
-
li. legacy patterns
|
71
|
-
|
72
|
-
h3. Glob patterns
|
73
|
-
|
74
|
-
p. Glob patterns are strings that contain wildcard characters. Wildcard characters are characters that can be substituted for other characters in a identifier. An example of a glob pattern is %glob{/projects/*.md}, which matches all files with a %filename{md} extension in the %filename{/projects} directory.
|
75
|
-
|
76
|
-
p. Globs are commonplace in Unix-like environments. For example, the Unix command for listing all files with the %filename{md} extension in the current directory is %command{ls *.md}. In this example, the argument to the %command{ls} command is a wildcard.
|
77
|
-
|
78
|
-
p. Nanoc supports the following wildcards in glob patterns:
|
79
|
-
|
80
|
-
dl.
|
81
|
-
dt. %code{*}
|
82
|
-
dd. Matches any file or directory name. Does not cross directory boundaries. For example, %glob{/projects/*.md} matches %identifier{/projects/nanoc.md}, but not %identifier{/projects/cri.adoc} nor %identifier{/projects/nanoc/about.md}.
|
83
|
-
|
84
|
-
dt. %code{**/}
|
85
|
-
dd. Matches zero or more levels of nested directories. For example, %glob{/projects/**/*.md} matches both %identifier{/projects/nanoc.md} and %identifier{/projects/nanoc/history.md}.
|
86
|
-
|
87
|
-
dt. %code{?}
|
88
|
-
dd. Matches a single character.
|
89
|
-
|
90
|
-
dt. %code{[abc]}
|
91
|
-
dd. Matches any single character in the set. For example, %glob{/people/[kt]im.md} matches only %identifier{/people/kim.md} and %identifier{/people/tim.md}.
|
92
|
-
|
93
|
-
dt. %code{{foo,bar%}}
|
94
|
-
dd. Matches either string in the comma-separated list. More than two strings are possible. For example, %glob{/c{at,ub,ount%}s.txt} matches %identifier{/cats.txt}, %identifier{/cubs.txt} and %identifier{/counts.txt}, but not %identifier{/cabs.txt}.
|
95
|
-
|
96
|
-
p. A glob pattern that matches every item is %glob{/**/*}. A glob pattern that matches every item/layout with the extension %filename{md} is %glob{/**/*.md}.
|
97
|
-
|
98
|
-
h3. Regular expression patterns
|
99
|
-
|
100
|
-
p. You can use a regular expression to select items and layouts.
|
101
|
-
|
102
|
-
p. For matching identifiers, the %code{%%r{…%}} syntax is (arguably) nicer than the %code{/…/} syntax. The latter is not a good fit for identifiers (or filenames), because all slashes need to be escaped. The %code{\A} and %code{\z} anchors are also useful to make sure the entire identifier is matched.
|
103
|
-
|
104
|
-
p. An example of a regular expression pattern is %code{%%r{\A/projects/(cri|nanoc)\.md\z%}}, which matches both %identifier{/projects/nanoc.md} and %identifier{/projects/cri.md}.
|
105
|
-
|
106
|
-
h3. Legacy patterns
|
107
|
-
|
108
|
-
p. Legacy patterns are strings that contain wildcard characters. The wildcard characters behave differently than the glob wildcard characters.
|
109
|
-
|
110
|
-
p. To enable legacy patterns, set %code{string_pattern_type} to %code{"legacy"} in the configuration. For example:
|
111
|
-
|
112
|
-
listing[lang=yaml].
|
113
|
-
string_pattern_type: "legacy"
|
114
|
-
|
115
|
-
p. For legacy patterns, Nanoc supports the following wildcards:
|
116
|
-
|
117
|
-
dl.
|
118
|
-
dt. %code{*}
|
119
|
-
dd. Matches zero or more characters, including a slash. For example, %glob{/projects/*/} matches %glob{/projects/nanoc/} and %identifier{/projects/nanoc/about/}, but not %identifier{/projects/}.
|
120
|
-
|
121
|
-
dt. %code{+}
|
122
|
-
dd. Matches one or more characters, including a slash. For example, %glob{/projects/+} matches %identifier{/projects/nanoc/} and %identifier{/projects/nanoc/about/}, but not %identifier{/projects/}.
|
123
|
-
|
124
|
-
p. Install Nanoc using RubyGems:
|
125
|
-
|
126
|
-
listing.
|
127
|
-
%prompt{%%} %kbd{gem install nanoc}
|
128
|
-
|
129
|
-
note. %entity{sudo-gem-install}
|
130
|
-
|
131
|
-
p. After installing, head over to %ref[item=/doc/tutorial.*]{}! For detailed installation instructions, read on.
|
132
|
-
|
133
|
-
h2. Installing Ruby
|
134
|
-
|
135
|
-
p. Nanoc requires %ref[url=http://ruby-lang.org/]{Ruby} in order to run. Nanoc supports the official Ruby interpreter from version 2.1 up, as well as JRuby from version 9000 up.
|
136
|
-
|
137
|
-
p. Ruby may already be installed on your system. To check, open a terminal window and type %kbd{ruby --version}. If you get “command not found”, Ruby is not yet installed. Otherwise, you will see which version of Ruby you have:
|
138
|
-
|
139
|
-
listing.
|
140
|
-
%prompt{%%} %kbd{ruby --version}
|
141
|
-
%erb{config[:ruby_version_info]}
|
142
|
-
%prompt{%%}
|
143
|
-
|
144
|
-
p. To install Ruby, follow the %ref[url=https://www.ruby-lang.org/en/documentation/installation/]{installation instructions on the Ruby web site}.
|
145
|
-
|
146
|
-
h2. Installing Nanoc
|
147
|
-
|
148
|
-
p. All dependencies are now taken care of, and installing Nanoc should now be easy:
|
149
|
-
|
150
|
-
listing.
|
151
|
-
%prompt{%%} %kbd{gem install nanoc}
|
152
|
-
|
153
|
-
note. %entity{sudo-gem-install}
|
154
|
-
|
155
|
-
p. To make sure that Nanoc was installed correctly, run %kbd{nanoc --version}. It should print the version number along with some other information, like this:
|
156
|
-
|
157
|
-
listing.
|
158
|
-
%prompt{%%} %kbd{nanoc --version}
|
159
|
-
%erb{config[:nanoc_version_info]}
|
160
|
-
%prompt{%%}
|
161
|
-
|
162
|
-
p. If you get a “command not found” error when trying to run %command{nanoc}, you might have to adjust your %code{$PATH} to include the path to the directory where RubyGems installs executables.
|
163
|
-
|
164
|
-
p. The current version of Nanoc is is %erb{latest_release_info[:version]}, released on %erb{latest_release_info[:date].format_as_date}. You can find the release notes for this version as well as release notes for older versions on %ref[item=/release-notes]{}.
|
165
|
-
|
166
|
-
p. If you’re on Windows and are using the Windows console, it’s probably a good idea to install the %productname{win32console} gem using %kbd{gem install win32console} to allow Nanoc to use pretty colors when writing stuff to the terminal.
|
167
|
-
|
168
|
-
h3. Installing from git
|
169
|
-
|
170
|
-
p. You can also install Nanoc from the repository if you want to take advantage of the latest features and improvements in Nanoc. Be warned that the versions from the repository may be unstable, so it is recommended to install Nanoc from RubyGems if you want to stay safe. You can install Nanoc from the git repository like this:
|
171
|
-
|
172
|
-
listing.
|
173
|
-
%prompt{~%%} %kbd{git clone git://github.com/nanoc/nanoc.git}
|
174
|
-
%prompt{~%%} %kbd{cd nanoc}
|
175
|
-
%prompt{~/nanoc%%} %kbd{gem build nanoc.gemspec}
|
176
|
-
%prompt{~/nanoc%%} %kbd{gem install nanoc-*.gem}
|
177
|
-
|
178
|
-
p. Nanoc 4 takes a clean break from the past, removing anything that was holding back future development.
|
179
|
-
|
180
|
-
p. The good news is that Nanoc 4.0 is quite similar to 3.8. Upgrading a Nanoc 3.x site to Nanoc 4.0 only takes minutes.
|
181
|
-
|
182
|
-
h2. Why upgrade?
|
183
|
-
|
184
|
-
ul[spacious].
|
185
|
-
li. Nanoc 4 brings identifiers with extensions, and thereby solves a long-standing usability issue. It also introduces glob patterns, which makes rules easier to write.
|
186
|
-
|
187
|
-
li. Nanoc 4 paves the way for new features and performance improvements. Nanoc 3 exposed its internals in a public API, making it hard to make significant changes.
|
188
|
-
|
189
|
-
li. Nanoc 3 is in maintenance mode, which means it will only get critical bug fixes.
|
190
|
-
|
191
|
-
h2. Installing Nanoc 4
|
192
|
-
|
193
|
-
p. Before installing, ensure you have a supported version of Ruby. Nanoc supports Ruby 2.2 and up, and JRuby 9000 and up:
|
194
|
-
|
195
|
-
listing.
|
196
|
-
%prompt{%%} %kbd{ruby --version}
|
197
|
-
%erb{config[:ruby_version_info]}
|
198
|
-
%prompt{%%}
|
199
|
-
|
200
|
-
p. To upgrade Ruby, follow the %ref[url=https://www.ruby-lang.org/en/documentation/installation/]{installation instructions on the Ruby web site}.
|
201
|
-
|
202
|
-
p. You can install Nanoc 4 using RubyGems:
|
203
|
-
|
204
|
-
listing.
|
205
|
-
%prompt{%%} %kbd{gem install nanoc}
|
206
|
-
|
207
|
-
note. %entity{sudo-gem-install}
|
208
|
-
|
209
|
-
p. We recommend using %ref[url=http://bundler.io/]{Bundler} to manage dependencies. When using Bundler, ensure there is a line for Nanoc in the %filename{Gemfile} that looks like this:
|
210
|
-
|
211
|
-
listing[lang=ruby].
|
212
|
-
gem 'nanoc', '~> 4.0'
|
213
|
-
|
214
|
-
h2[id=quick-upgrade-guide]. Quick upgrade guide
|
215
|
-
|
216
|
-
p. The following steps will get a Nanoc 3 site working on Nanoc 4 with a minimal amount of changes.
|
217
|
-
|
218
|
-
ol[spacious].
|
219
|
-
li. Change mentions of %code{Nanoc3} to %code{Nanoc}.
|
220
|
-
|
221
|
-
li. Change mentions of %code{@site.config} to %code{@config}.
|
222
|
-
|
223
|
-
li. Add %code{identifier_type: legacy} to the individual data source configurations. For example:
|
224
|
-
|
225
|
-
listing[lang=yaml,legacy].
|
226
|
-
data_sources:
|
227
|
-
-
|
228
|
-
type: filesystem
|
229
|
-
|
230
|
-
listing[lang=yaml,new].
|
231
|
-
data_sources:
|
232
|
-
-
|
233
|
-
type: filesystem
|
234
|
-
identifier_type: legacy
|
235
|
-
|
236
|
-
li. Add %code{string_pattern_type: legacy} to the configuration file. For example:
|
237
|
-
|
238
|
-
listing[lang=yaml,legacy].
|
239
|
-
data_sources:
|
240
|
-
-
|
241
|
-
type: filesystem
|
242
|
-
identifier_type: legacy
|
243
|
-
|
244
|
-
listing[lang=yaml,new].
|
245
|
-
string_pattern_type: legacy
|
246
|
-
data_sources:
|
247
|
-
-
|
248
|
-
type: filesystem
|
249
|
-
identifier_type: legacy
|
250
|
-
|
251
|
-
li. In Rules, remove the %code{rep.} prefix from %code{filter}, %code{layout} and %code{snapshot}. For example:
|
252
|
-
|
253
|
-
listing[lang=ruby,legacy].
|
254
|
-
compile '*' do
|
255
|
-
rep.filter :erb
|
256
|
-
rep.layout 'default'
|
257
|
-
end
|
258
|
-
|
259
|
-
listing[lang=ruby,new].
|
260
|
-
compile '*' do
|
261
|
-
filter :erb
|
262
|
-
layout 'default'
|
263
|
-
end
|
264
|
-
|
265
|
-
li. In the %code{preprocess} block, use %code{@items.create} rather than instantiating %code{Nanoc::Item}. For example:
|
266
|
-
|
267
|
-
listing[lang=ruby,legacy].
|
268
|
-
@items << Nanoc::Item.new('Hello', {%}, '/hello/')
|
269
|
-
|
270
|
-
listing[lang=ruby,new].
|
271
|
-
@items.create('Hello', {%}, '/hello/')
|
272
|
-
|
273
|
-
li. In data sources, use %code{#new_item} or %code{#new_layout} rather than instantiating %code{Nanoc::Item} or %code{Nanoc::Layout}. For example:
|
274
|
-
|
275
|
-
listing[lang=ruby,legacy].
|
276
|
-
def items
|
277
|
-
[Nanoc::Item.new('Hello', {%}, '/hello/')]
|
278
|
-
end
|
279
|
-
|
280
|
-
listing[lang=ruby,new].
|
281
|
-
def items
|
282
|
-
[new_item('Hello', {%}, '/hello/')]
|
283
|
-
end
|
284
|
-
|
285
|
-
li. Replace %code{.reps[0]} by %code{.reps[:default]}. For example:
|
286
|
-
|
287
|
-
listing[lang=ruby,legacy].
|
288
|
-
item.reps[0].path
|
289
|
-
|
290
|
-
listing[lang=ruby,new].
|
291
|
-
item.reps[:default].path
|
292
|
-
|
293
|
-
li. Replace calls to %code{#rep_named} by %code{reps[%var{something}]}, where %var{something} is the argument to %code{#rep_named}. For example:
|
294
|
-
|
295
|
-
listing[lang=ruby,legacy].
|
296
|
-
item.rep_named(:raw).path
|
297
|
-
|
298
|
-
listing[lang=ruby,new].
|
299
|
-
item.reps[:raw].path
|
300
|
-
|
301
|
-
li. If you use the static data source, disable it for now and follow the extended upgrade instructions below.
|
302
|
-
|
303
|
-
h2. Extended upgrade guide
|
304
|
-
|
305
|
-
p. This section describes how to upgrade a site to identifiers with extensions and glob patterns. For details, see %ref[item=/doc/identifiers-and-patterns.*]{}.
|
306
|
-
|
307
|
-
p. This section assumes you have already upgraded the site following the instructions in %ref[frag=quick-upgrade-guide]{} above.
|
308
|
-
|
309
|
-
p. Before you start, add %code{enable_output_diff: true} to the configuration file. This will let the %command{compile} command write out a diff with the changes to the compiled output. This diff will allow you to verify that no unexpected changes occur.
|
310
|
-
|
311
|
-
tip. If you use a filter that minifies HTML content, such as %code{html5small}, we recommend turning it off before upgrading the site, so that the output diff becomes easier to read.
|
312
|
-
|
313
|
-
h3. Enabling glob patterns
|
314
|
-
|
315
|
-
p. Before enabling them, ensure you are familiar with glob patterns. For details, see %ref[item=/doc/identifiers-and-patterns.*,frag=glob-patterns]{}.
|
316
|
-
|
317
|
-
p. To use glob patterns:
|
318
|
-
|
319
|
-
ol[spacious].
|
320
|
-
li. Set %code{string_pattern_type} to %code{glob} in the configuration file. For example:
|
321
|
-
|
322
|
-
listing[lang=yaml,legacy].
|
323
|
-
string_pattern_type: legacy
|
324
|
-
|
325
|
-
listing[lang=yaml,new].
|
326
|
-
string_pattern_type: glob
|
327
|
-
|
328
|
-
li. Ensure that all string patterns in the %filename{Rules} file, as well as in calls to %code{@items[…]}, %code{@layouts[…]}, and %code{#render} throughout the site, start and end with a slash. This is an intermediate step. For example:
|
329
|
-
|
330
|
-
listing[lang=ruby,legacy].
|
331
|
-
# Before
|
332
|
-
compile 'articles/*' do
|
333
|
-
layout 'default'
|
334
|
-
end
|
335
|
-
|
336
|
-
listing[lang=ruby,legacy].
|
337
|
-
# After
|
338
|
-
compile '/articles/*/' do
|
339
|
-
layout '/default/'
|
340
|
-
end
|
341
|
-
|
342
|
-
listing[lang=ruby,legacy].
|
343
|
-
# Before
|
344
|
-
@items['foo']
|
345
|
-
@layouts['/bar']
|
346
|
-
|
347
|
-
listing[lang=ruby,legacy].
|
348
|
-
# After
|
349
|
-
@items['/foo/']
|
350
|
-
@layouts['/bar/']
|
351
|
-
|
352
|
-
listing[lang=rhtml,legacy].
|
353
|
-
<!-- Before -->
|
354
|
-
<%%= render 'header' %%>
|
355
|
-
|
356
|
-
listing[lang=rhtml,legacy].
|
357
|
-
<!-- After -->
|
358
|
-
<%%= render '/header/' %%>
|
359
|
-
|
360
|
-
li. Replace %code{*} and %code{+} with %code{**/*} in all string patterns in the %filename{Rules} file, as well as in calls to %code{@items[…]}, %code{@layouts[…]}, and %code{#render} throughout the site. For example:
|
361
|
-
|
362
|
-
listing[lang=ruby,legacy].
|
363
|
-
compile '/articles/*/' do
|
364
|
-
layout '/default/'
|
365
|
-
end
|
366
|
-
|
367
|
-
listing[lang=ruby,new].
|
368
|
-
compile '/articles/**/*/' do
|
369
|
-
layout '/default/'
|
370
|
-
end
|
371
|
-
|
372
|
-
listing[lang=ruby,legacy].
|
373
|
-
@items['/articles/*/']
|
374
|
-
|
375
|
-
listing[lang=ruby,new].
|
376
|
-
@items['/articles/**/*/']
|
377
|
-
|
378
|
-
p. This approach should work out of the box: Nanoc should not raise errors and the output diff should be empty.
|
379
|
-
|
380
|
-
h3. Enabling identifiers with extensions
|
381
|
-
|
382
|
-
note. This section assumes that glob patterns have been enabled.
|
383
|
-
|
384
|
-
p. Before enabling them, ensure you are familiar with identifiers with extensions. See %ref[item=/doc/identifiers-and-patterns.*,frag=identifiers]{} section for documentation.
|
385
|
-
|
386
|
-
p. To use identifiers with extensions:
|
387
|
-
|
388
|
-
ol[spacious].
|
389
|
-
li. Set %code{identifier_type} to %code{full} in the configuration file. For example:
|
390
|
-
|
391
|
-
listing[lang=yaml,legacy].
|
392
|
-
identifier_type: legacy
|
393
|
-
|
394
|
-
listing[lang=yaml,new].
|
395
|
-
identifier_type: full
|
396
|
-
|
397
|
-
li. Remove the trailing slash from any argument to %code{#compile}, %code{#route} and %code{#layout} in the %filename{Rules} file, as well as in calls to %code{@items[…]}, %code{@layouts[…]}, and %code{#render} throughout the site. If the pattern does not end with a “%code{*}”, add “%code{.*}”. For example:
|
398
|
-
|
399
|
-
listing[lang=ruby,legacy].
|
400
|
-
compile '/articles/**/*/' do
|
401
|
-
filter :kramdown
|
402
|
-
layout '/default/'
|
403
|
-
end
|
404
|
-
|
405
|
-
compile '/about/' do
|
406
|
-
layout '/default/'
|
407
|
-
end
|
408
|
-
|
409
|
-
listing[lang=ruby,new].
|
410
|
-
compile '/articles/**/*' do
|
411
|
-
filter :kramdown
|
412
|
-
layout '/default.*'
|
413
|
-
end
|
414
|
-
|
415
|
-
compile '/about.*' do
|
416
|
-
layout '/default.*'
|
417
|
-
end
|
418
|
-
|
419
|
-
listing[lang=ruby,legacy].
|
420
|
-
@items['/about/']
|
421
|
-
@layouts['/default/']
|
422
|
-
|
423
|
-
listing[lang=ruby,new].
|
424
|
-
@items['/about.*']
|
425
|
-
@layouts['/default.*']
|
426
|
-
|
427
|
-
listing[lang=rhtml,legacy].
|
428
|
-
<%%= render '/root/' %%>
|
429
|
-
|
430
|
-
listing[lang=rhtml,new].
|
431
|
-
<%%= render '/root.*' %%>
|
432
|
-
|
433
|
-
li. Update the routing rules to output the correct path. For example:
|
434
|
-
|
435
|
-
listing[lang=ruby,legacy].
|
436
|
-
route '/articles/*/' do
|
437
|
-
# /articles/foo/ gets written to /articles/foo/index.html
|
438
|
-
item.identifier + 'index.html'
|
439
|
-
end
|
440
|
-
|
441
|
-
listing[lang=ruby,new].
|
442
|
-
route '/articles/**/*' do
|
443
|
-
# /articles/foo.md gets written to /articles/foo/index.html
|
444
|
-
item.identifier.without_ext + '/index.html'
|
445
|
-
end
|
446
|
-
|
447
|
-
li. Create a routing rule that matches index files in the content directory (such as %filename{content/index.md} or %filename{content/blog/index.md}). For example, put the following _before_ any rules matching %code{/**/*}:
|
448
|
-
|
449
|
-
listing[lang=ruby,new].
|
450
|
-
route '/**/index.*' do
|
451
|
-
# /projects/index.md gets written to /projects/index.html
|
452
|
-
item.identifier.without_ext + '.html'
|
453
|
-
end
|
454
|
-
|
455
|
-
li. Replace calls to %code{#children} with a call to %code{#find_all}, passing a pattern that matches the children. For example:
|
456
|
-
|
457
|
-
listing[lang=ruby,legacy].
|
458
|
-
@items['/articles/'].children
|
459
|
-
@item.children
|
460
|
-
|
461
|
-
listing[lang=ruby,new].
|
462
|
-
@items.find_all('/articles/*')
|
463
|
-
@items.find_all(@item.identifier.without_ext + '/*')
|
464
|
-
|
465
|
-
li. Replace calls to %code{#parent} with a call to %code{#[]}, passing a pattern that matches the parent. For example:
|
466
|
-
|
467
|
-
listing[lang=ruby,legacy].
|
468
|
-
@item.parent
|
469
|
-
|
470
|
-
listing[lang=ruby,new].
|
471
|
-
@items[@item.identifier.to_s.sub(/[^\/]+$/, '').chop + '.*']
|
472
|
-
|
473
|
-
note. When using identifiers with extensions, the children and parent of an item are no longer unambiguous. For example, the two items %filename{/foo.md} and %filename{/foo.adoc} both have %filename{/foo/bar.md} as a child, and %filename{/foo/bar.md} has two parents.
|
474
|
-
|
475
|
-
h3. Upgrading from the static data source
|
476
|
-
|
477
|
-
note. This section assumes that glob patterns and identifiers with extensions have been enabled.
|
478
|
-
|
479
|
-
p. The static data source no longer exists in Nanoc 4. It existed in Nanoc 3 to work around the problem of identifiers not including the file extension, which is no longer the case in Nanoc 4.
|
480
|
-
|
481
|
-
p. Theoretically, with identifiers with extensions enabled, it is possible to move the contents of the %filename{static/} directory into %filename{content/}. This can be tricky, however, because some rules that did not match any items in %filename{static/} might now match.
|
482
|
-
|
483
|
-
p. Because of this, the recommend approach for upgrading is to keep the %filename{static/} directory, and set up a new data source that reads from this directory.
|
484
|
-
|
485
|
-
p. In the site configuration, re-enable the static data source, change its type to %code{filesystem}, set %code{content_dir} to %code{"static"} and %code{layouts_dir} to %code{null}:
|
486
|
-
|
487
|
-
listing[lang=yaml,new].
|
488
|
-
data_sources:
|
489
|
-
-
|
490
|
-
type: filesystem
|
491
|
-
-
|
492
|
-
type: filesystem
|
493
|
-
items_root: /static
|
494
|
-
content_dir: 'static'
|
495
|
-
layouts_dir: null
|
496
|
-
|
497
|
-
p. The null value for the %code{layouts_dir} option prevents this data source from loading layouts—the other data source already does so.
|
498
|
-
|
499
|
-
p. Lastly, update the rules to copy these items as-is, but without the %code{/static} prefix:
|
500
|
-
|
501
|
-
listing[lang=ruby,new].
|
502
|
-
compile '/static/**/*' do
|
503
|
-
end
|
504
|
-
|
505
|
-
route '/static/**/*' do
|
506
|
-
# /static/foo.html → /foo.html
|
507
|
-
item.identifier.to_s.sub(/\A\/static/, '')
|
508
|
-
end
|
509
|
-
|
510
|
-
p. This approach should work out of the box: Nanoc should not raise errors and the output diff should be empty.
|
511
|
-
|
512
|
-
p. A final improvement would be to move the contents of the %filename{static/} directory into %filename{content/}. The main thing to watch out for with this approach is rules that accidentally match the wrong items.
|
513
|
-
|
514
|
-
h2. Troubleshooting
|
515
|
-
|
516
|
-
ol[spacious].
|
517
|
-
li. If you use Nanoc with a Gemfile, ensure you call Nanoc as %kbd{bundle exec nanoc}. Nanoc no longer attempts to load the Gemfile.
|
518
|
-
|
519
|
-
li. If you get a %code{NoMethodError} error on %code{Nanoc::Identifier}, call %code{.to_s} on the identifier before doing anything with it. In Nanoc 4.x, identifiers have their own class and are no longer strings.
|
520
|
-
|
521
|
-
listing[lang=ruby,legacy].
|
522
|
-
item.identifier[7..-2]
|
523
|
-
|
524
|
-
listing[lang=ruby,new].
|
525
|
-
item.identifier.to_s[7..-2]
|
526
|
-
|
527
|
-
li. If you get a %code{NoMethodError} that you did not expect, you might be using a private API that is no longer present in Nanoc 4.0. In case of doubt, ask for help on the %ref[url=http://nanoc.ws/community/#discussion-groups]{discussion group}.
|
528
|
-
|
529
|
-
h2. Removed features
|
530
|
-
|
531
|
-
p. The %code{watch} and %code{autocompile} commands have been removed. Both were deprecated in Nanoc 3.6. Use %ref[url=https://github.com/guard/guard-nanoc]{%productname{guard-nanoc}} instead.
|
532
|
-
|
533
|
-
p. Because Nanoc’s focus is now more clearly on compiling content rather than managing it, the following features have been removed:
|
534
|
-
|
535
|
-
ol.
|
536
|
-
li. the %code{create-item} and %code{create-layout} commands
|
537
|
-
li. the %code{update} and %code{sync} commands
|
538
|
-
li. VCS integration (along with %code{Nanoc::Extra::VCS})
|
539
|
-
li. the %code{DataSource#create_item} and %code{DataSource#create_layout} methods.
|