d-mark 1.0.0a1 → 1.0.0b2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  describe DMark::Translator do
2
- let(:translator) { translator_class.new(nodes) }
2
+ let(:translator) { translator_class.new }
3
3
  let(:translator_class) { described_class }
4
4
 
5
5
  let(:nodes) do
@@ -7,39 +7,95 @@ describe DMark::Translator do
7
7
  DMark::ElementNode.new(
8
8
  'para',
9
9
  { 'only' => 'web', 'animal' => 'donkey' },
10
- ['Hi!']
10
+ [
11
+ DMark::ElementNode.new('em', {}, ['Hello']),
12
+ ' world!'
13
+ ]
11
14
  )
12
15
  ]
13
16
  end
14
17
 
15
- describe '#run' do
16
- subject { translator.run }
17
-
18
+ shared_examples 'translates' do
18
19
  context 'translator base class' do
19
- it 'raises NotImplementedError' do
20
- expect { subject }.to raise_error(NotImplementedError)
20
+ it 'raises error' do
21
+ expect { subject }.to raise_error(
22
+ DMark::Translator::UnhandledNode,
23
+ 'Unhandled element node "para"'
24
+ )
21
25
  end
22
26
  end
23
27
 
24
28
  context 'custom translator' do
25
29
  let(:translator_class) do
26
30
  Class.new(described_class) do
27
- def handle(node)
28
- case node
29
- when String
30
- out << node
31
- when DMark::ElementNode
32
- out << "<#{node.name}"
33
- out << node.attributes.map { |k, v| ' ' + [k, v].join('=') }.join
34
- out << '>'
35
- handle_children(node)
36
- out << "</#{node.name}>"
31
+ def handle_string(string, _context)
32
+ [string]
33
+ end
34
+
35
+ def handle_element(element, context)
36
+ [
37
+ "<#{element.name}",
38
+ element.attributes.map { |k, v| ' ' + [k, v].join('=') }.join,
39
+ '>',
40
+ handle_children(element, context),
41
+ "</#{element.name}>"
42
+ ]
43
+ end
44
+ end
45
+ end
46
+
47
+ it { is_expected.to eql('<para only=web animal=donkey><em>Hello</em> world!</para>') }
48
+
49
+ context 'doing something with context' do
50
+ let(:translator_class) do
51
+ Class.new(described_class) do
52
+ def handle_string(string, context)
53
+ [string, " [parent=#{context[:kind]}]"]
54
+ end
55
+
56
+ def handle_element(element, context)
57
+ [
58
+ "<#{element.name}",
59
+ element.attributes.map { |k, v| ' ' + [k, v].join('=') }.join,
60
+ '>',
61
+ handle_children(element, context.merge(kind: element.name)),
62
+ "</#{element.name}>"
63
+ ]
37
64
  end
38
65
  end
39
66
  end
67
+
68
+ it { is_expected.to eql('<para only=web animal=donkey><em>Hello [parent=em]</em> world! [parent=para]</para>') }
40
69
  end
70
+ end
71
+ end
72
+
73
+ shared_examples 'errors on unknown type' do
74
+ it 'raises' do
75
+ expect { subject }.to raise_error(
76
+ ArgumentError,
77
+ 'Cannot handle Symbol'
78
+ )
79
+ end
80
+ end
81
+
82
+ describe '.translate' do
83
+ subject { translator_class.translate(nodes) }
84
+ include_examples 'translates'
85
+
86
+ context 'unrecognised type' do
87
+ subject { translator_class.translate([:donkey]) }
88
+ include_examples 'errors on unknown type'
89
+ end
90
+ end
91
+
92
+ describe '#translate' do
93
+ subject { translator.translate(nodes) }
94
+ include_examples 'translates'
41
95
 
42
- it { is_expected.to eql('<para only=web animal=donkey>Hi!</para>') }
96
+ context 'unrecognised type' do
97
+ subject { translator.translate([:donkey]) }
98
+ include_examples 'errors on unknown type'
43
99
  end
44
100
  end
45
101
  end
metadata CHANGED
@@ -1,35 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: d-mark
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0a1
4
+ version: 1.0.0b2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-20 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.11.2
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '2.0'
23
- type: :development
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 1.11.2
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '2.0'
11
+ date: 2021-01-01 00:00:00.000000000 Z
12
+ dependencies: []
33
13
  description: D★Mark is a markup language aimed at being able to write semantically
34
14
  meaningful text without limiting itself to the semantics provided by HTML or Markdown.
35
15
  email: denis.defreyne@stoneship.org
@@ -37,7 +17,7 @@ executables: []
37
17
  extensions: []
38
18
  extra_rdoc_files:
39
19
  - LICENSE
40
- - README.adoc
20
+ - README.md
41
21
  - NEWS.md
42
22
  files:
43
23
  - Gemfile
@@ -45,16 +25,15 @@ files:
45
25
  - Guardfile
46
26
  - LICENSE
47
27
  - NEWS.md
48
- - README.adoc
28
+ - README.md
49
29
  - Rakefile
50
30
  - d-mark.gemspec
31
+ - ideas.dmark
51
32
  - lib/d-mark.rb
52
- - lib/d-mark/cli.rb
53
33
  - lib/d-mark/element_node.rb
54
34
  - lib/d-mark/parser.rb
55
35
  - lib/d-mark/translator.rb
56
36
  - lib/d-mark/version.rb
57
- - samples/identifiers-and-patterns.dmark
58
37
  - samples/trivial.dmark
59
38
  - samples/trivial.rb
60
39
  - spec/d-mark/element_node_spec.rb
@@ -65,27 +44,25 @@ homepage: http://rubygems.org/gems/d-mark
65
44
  licenses:
66
45
  - MIT
67
46
  metadata: {}
68
- post_install_message:
47
+ post_install_message:
69
48
  rdoc_options:
70
49
  - "--main"
71
- - README.adoc
50
+ - README.md
72
51
  require_paths:
73
52
  - lib
74
53
  required_ruby_version: !ruby/object:Gem::Requirement
75
54
  requirements:
76
55
  - - ">="
77
56
  - !ruby/object:Gem::Version
78
- version: 2.1.0
57
+ version: '2.5'
79
58
  required_rubygems_version: !ruby/object:Gem::Requirement
80
59
  requirements:
81
60
  - - ">"
82
61
  - !ruby/object:Gem::Version
83
62
  version: 1.3.1
84
63
  requirements: []
85
- rubyforge_project:
86
- rubygems_version: 2.5.2
87
- signing_key:
64
+ rubygems_version: 3.2.4
65
+ signing_key:
88
66
  specification_version: 4
89
67
  summary: markup language for writing text
90
68
  test_files: []
91
- has_rdoc:
@@ -1,221 +0,0 @@
1
- = D★Mark
2
- Denis Defreyne <denis@stoneship.org>
3
-
4
- image:http://img.shields.io/gem/v/d-mark.svg[Gem version, link="http://rubygems.org/gems/d-mark"]
5
- image:http://img.shields.io/travis/ddfreyne/d-mark.svg[Build status, link="https://travis-ci.org/ddfreyne/d-mark"]
6
- image:http://img.shields.io/codeclimate/github/ddfreyne/d-mark.svg[Code Climate, link="https://codeclimate.com/github/ddfreyne/d-mark"]
7
- image:http://img.shields.io/codecov/c/github/ddfreyne/d-mark.svg[Code Coverage, link="https://codecov.io/github/ddfreyne/d-mark"]
8
-
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
-
11
- Here’s an example of D★Mark:
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.
96
-
97
- == Goals
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
- ----
137
-
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
- [source]
142
- ----
143
- A glob pattern that matches every item is <span class="glob attr-kind-glob">/**/*</span>.
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
- ----
185
-
186
- == Specification
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]
197
- ----
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
-
204
- [source,ruby]
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
- ----
@@ -1,28 +0,0 @@
1
- require_relative '../d-mark'
2
-
3
- data = File.read(ARGV[0]).strip
4
-
5
- parser = DMark::Parser.new(data)
6
- begin
7
- before = Time.now
8
- result = parser.parse
9
- after = Time.now
10
- result.each do |tree|
11
- puts tree.inspect
12
- puts
13
- end
14
- puts "parse duration: #{(after - before).to_f}s"
15
- rescue => e
16
- case e
17
- when DMark::Parser::ParserError
18
- line = data.lines[e.line_nr]
19
-
20
- puts "\e[31mError:\e[0m #{e.message}}"
21
- puts
22
- puts line
23
- puts "\e[31m" + ' ' * e.col_nr + '↑' + "\e[0m"
24
- exit 1
25
- else
26
- raise e
27
- end
28
- end