lmt 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.markdownlint.json +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +35 -0
- data/README.md +73 -0
- data/Rakefile +75 -0
- data/bin/console +25 -0
- data/bin/lmt +6 -0
- data/bin/lmw +5 -0
- data/bin/setup +8 -0
- data/doc/lmt/error_reporting.md +15 -0
- data/doc/lmt/lmt.rb.md +742 -0
- data/doc/lmt/lmt_expressions.md +33 -0
- data/doc/lmt/lmt_include.md +9 -0
- data/doc/lmt/lmw.rb.md +396 -0
- data/doc/lmt/option_verification.md +20 -0
- data/lib/lmt.rb +4 -0
- data/lib/lmt/lmt.rb +277 -0
- data/lib/lmt/lmw.rb +190 -0
- data/lib/lmt/version.rb +3 -0
- data/lmt.gemspec +30 -0
- data/src/lmt/error_reporting.lmd +13 -0
- data/src/lmt/lmt.rb.lmd +652 -0
- data/src/lmt/lmt_expressions.lmd +27 -0
- data/src/lmt/lmt_include.lmd +7 -0
- data/src/lmt/lmw.rb.lmd +358 -0
- data/src/lmt/option_verification.lmd +18 -0
- metadata +156 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# Lmt Regular Expressions
|
2
|
+
|
3
|
+
Our Lmt language depends is a regular language and depends on a few regular expressions, we are listing them here because both the tangler and weave care about them.
|
4
|
+
|
5
|
+
## The Include Expression
|
6
|
+
|
7
|
+
The first regular expression handles the detection of include directives. It recognizes lines like `! include [some description](some-file)` and extracts `some-file`.
|
8
|
+
|
9
|
+
``` ruby include_expression
|
10
|
+
/^!\s+include\s+\[.*\]\((.*)\)\s*$/
|
11
|
+
```
|
12
|
+
|
13
|
+
## The Code Block Expression
|
14
|
+
|
15
|
+
The second regular expression is intended to note when whe enter or leave a code block. It detects markdown code fences and processes the special directives. It has four groups. The first identifies white space at the beginning of the line. The second detects the language. The third determines if this is a replacement. The fourth is the name of the block (if applicable).
|
16
|
+
|
17
|
+
``` ruby code_block_expression
|
18
|
+
/^([s]*)``` ?([\w]*) ?(=?)([-\w]*)?/
|
19
|
+
```
|
20
|
+
|
21
|
+
## The Macro Substitution Expression
|
22
|
+
|
23
|
+
The third expression identifies macro expansions surrounded with `⦅` and `⦆`. The first bit deals with making sure that the opening `⦅` isn't escaped. Then there is one group which contains the name of the macro combined and any filters which are being used.
|
24
|
+
|
25
|
+
``` ruby macro_substitution_expression
|
26
|
+
/(?<!\\)⦅ *([-\w | ]*) *⦆/
|
27
|
+
```
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# A file to be included in Lmt-Ruby
|
2
|
+
|
3
|
+
This is just a file to be included in lmt-Ruby. The contents of this file will be included in the output of lmt but not lmm. Any blocks defined here will be available for use in Lmt.
|
4
|
+
|
5
|
+
``` ruby =included_block
|
6
|
+
included_string = "I came from lmt_include.lmd"
|
7
|
+
```
|
data/src/lmt/lmw.rb.lmd
ADDED
@@ -0,0 +1,358 @@
|
|
1
|
+
# Lmw-Ruby
|
2
|
+
|
3
|
+
``` text description
|
4
|
+
A literate Markdown weave tool written in Ruby.
|
5
|
+
```
|
6
|
+
|
7
|
+
Lmw is a literate Markdown weave program for [literate programing](https://en.wikipedia.org/wiki/Literate_programming). This is a fairly simple program designed to turn a literate Markdown file into a more normal Markdown file without the special semantics. It is interprets the Markdown as described in [lmt-ruby](lmt.lmd). The primary changes to the output is that the header for code blocks is extracted and rendered in standard Markdown. File names are also changed from .lmd to .md. This change is also applied to links.
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
In order to effectively weave a lmt file we must:
|
12
|
+
|
13
|
+
1) Replace the lmt headers with something that a standard markdown parser will make sense of.
|
14
|
+
2) Replace include directives with a more informative text.
|
15
|
+
3) Update all links to .lmd files with a similar link to a .md file.
|
16
|
+
|
17
|
+
A few nice to have features:
|
18
|
+
|
19
|
+
1) Links between reopenings of a given block in the lmw output.
|
20
|
+
2) Add links from macro substitutions to the body of the macro.
|
21
|
+
3) syntax verification: check for balanced code fences, make sure that all reopenings of a block are in the same language, etc.
|
22
|
+
|
23
|
+
Ideally, any links between and to blocks would also go to included files.
|
24
|
+
|
25
|
+
Currently, it puts headers on blocks, and replaces include directives with a more human version. We still need to handle the parts and linking. We also need to handle the link updating.
|
26
|
+
|
27
|
+
## Interface
|
28
|
+
|
29
|
+
We need to know where to get the input from and where to send the output to. For that, we will use the following command line options
|
30
|
+
|
31
|
+
``` ruby options
|
32
|
+
on("--file FILE", "-f", "Required: input file")
|
33
|
+
on("--output FILE", "-o", "Required: output file")
|
34
|
+
on("--dev", "disables self test failure for development")
|
35
|
+
```
|
36
|
+
|
37
|
+
Of which, both are required
|
38
|
+
|
39
|
+
``` ruby options
|
40
|
+
required(:file, :output)
|
41
|
+
```
|
42
|
+
|
43
|
+
## Implementation and Example
|
44
|
+
|
45
|
+
Now for an example in implementation. Using Ruby we can write a template as below:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
#!/usr/bin/env ruby
|
49
|
+
# Encoding: utf-8
|
50
|
+
|
51
|
+
⦅includes⦆
|
52
|
+
|
53
|
+
module Lmt
|
54
|
+
|
55
|
+
class Lmw
|
56
|
+
include Methadone::Main
|
57
|
+
include Methadone::CLILogging
|
58
|
+
|
59
|
+
@dev = true
|
60
|
+
|
61
|
+
main do
|
62
|
+
check_arguments()
|
63
|
+
begin
|
64
|
+
⦅main_body⦆
|
65
|
+
rescue Exception => e
|
66
|
+
puts "Error: #{e.message} #{extract_causes(e)}At:"
|
67
|
+
e.backtrace.each do |trace|
|
68
|
+
puts " #{trace}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.extract_causes(error)
|
74
|
+
if (error.cause)
|
75
|
+
" Caused by: #{error.cause.message}\n#{extract_causes(error.cause)}"
|
76
|
+
else
|
77
|
+
""
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
⦅self_test⦆
|
82
|
+
|
83
|
+
⦅report_self_test_failure⦆
|
84
|
+
|
85
|
+
⦅weave_class⦆
|
86
|
+
|
87
|
+
⦅option_verification⦆
|
88
|
+
|
89
|
+
description "⦅description⦆"
|
90
|
+
⦅options⦆
|
91
|
+
|
92
|
+
version Lmt::VERSION
|
93
|
+
|
94
|
+
use_log_level_option :toggle_debug_on_signal => 'USR1'
|
95
|
+
|
96
|
+
go! if __FILE__ == $0
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
This is a basic template using the [Ruby methadone](https://github.com/davetron5000/methadone) command line application framework and making sure that we report errors (because silent failure sucks).
|
103
|
+
|
104
|
+
The main body will first test itself then, invoke the library component, which isn't in lib as traditional because it is in this file and I don't want to move it around.
|
105
|
+
|
106
|
+
``` ruby main_body
|
107
|
+
self_test()
|
108
|
+
weave = Lmw::Weave.from_file(options[:file])
|
109
|
+
weave.weave()
|
110
|
+
weave.write(options[:output])
|
111
|
+
```
|
112
|
+
|
113
|
+
Finally, we have the dependencies. Optparse and methadone are used for cli argument handling and other niceties.
|
114
|
+
|
115
|
+
``` ruby includes
|
116
|
+
require 'optparse'
|
117
|
+
require 'methadone'
|
118
|
+
|
119
|
+
require 'pry'
|
120
|
+
```
|
121
|
+
|
122
|
+
There, now we are done with the boilerplate. On to:
|
123
|
+
|
124
|
+
## The Actual Weaver
|
125
|
+
|
126
|
+
The weaver is defined within a class that contains the weaving implementation
|
127
|
+
|
128
|
+
``` ruby weave_class
|
129
|
+
class Weave
|
130
|
+
class << self
|
131
|
+
⦅from_file⦆
|
132
|
+
end
|
133
|
+
|
134
|
+
⦅initializer⦆
|
135
|
+
⦅weave⦆
|
136
|
+
⦅write⦆
|
137
|
+
|
138
|
+
private
|
139
|
+
⦅weave_class_privates⦆
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
There may be some private methods, we need a block for them. They will be inserted where needed.
|
144
|
+
|
145
|
+
``` ruby weave_class_privates
|
146
|
+
⦅include_includes⦆
|
147
|
+
```
|
148
|
+
|
149
|
+
### Initializer
|
150
|
+
|
151
|
+
The initializer takes the input file and sets up our state.
|
152
|
+
|
153
|
+
``` ruby initializer
|
154
|
+
def initialize(lines, file_name = "")
|
155
|
+
@file_name = file_name
|
156
|
+
@lines = lines
|
157
|
+
@weaved = false
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
#### Factory
|
162
|
+
|
163
|
+
For testing, we want to be able to create an instance with a hard coded set of lines. Furthermore, because this processing is stateful, we want to make the input immutable. Reading from a file needs to be handled. A factory can do it.
|
164
|
+
|
165
|
+
##### Reading the File
|
166
|
+
|
167
|
+
This is fairly self explanatory, though note, we are storing the file in memory as an array of lines.
|
168
|
+
|
169
|
+
``` ruby from_file
|
170
|
+
def from_file(file)
|
171
|
+
File.open(file, 'r') do |f|
|
172
|
+
Weave.new(f.readlines, file)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
```
|
177
|
+
|
178
|
+
### Weave
|
179
|
+
|
180
|
+
To weave a file, first we have to identify and construct metadata on all the blocks. Then we use that metadata to transform any lines containing a block declaration into an appropriate header for that block. Finally, we replace any links to an .lmd file with the equivalent .md link.
|
181
|
+
|
182
|
+
``` ruby weave
|
183
|
+
def weave()
|
184
|
+
@blocks = find_blocks(@lines)
|
185
|
+
@weaved_lines = substitute_directives_and_headers(
|
186
|
+
@lines.map do |line|
|
187
|
+
replace_markdown_links(line)
|
188
|
+
end)
|
189
|
+
@weaved = true
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
#### Finding the Blocks
|
194
|
+
|
195
|
+
In order to find the blocks we will need the regular expressions defined in:
|
196
|
+
|
197
|
+
! include [lmt_expressions](lmt_expressions.lmd)
|
198
|
+
|
199
|
+
First, we get the lines from includes. then we filter the lines for only the headers and footers and check for unmatched headers and footers.
|
200
|
+
|
201
|
+
``` ruby weave_class_privates
|
202
|
+
def find_blocks(lines)
|
203
|
+
lines_with_includes = include_includes(lines)
|
204
|
+
code_block_exp = ⦅code_block_expression⦆
|
205
|
+
headers_and_footers = lines_with_includes.filter do |(line, source_file)|
|
206
|
+
code_block_exp =~ line
|
207
|
+
end
|
208
|
+
throw "Missing code fence" if headers_and_footers.length % 2 != 0
|
209
|
+
```
|
210
|
+
|
211
|
+
Now, we throw out all the footers and use the code_block_exp to parse them, group them by name, and generate the metadata. In this case the metadata includes 1) a count of the number of blocks with a particular name in this file. 2) the source file of each block.
|
212
|
+
|
213
|
+
We are also validating that a block only has one language.
|
214
|
+
|
215
|
+
``` ruby weave_class_privates
|
216
|
+
headers_and_footers.each_slice(2).map(&:first)
|
217
|
+
.map do |(header, source_file)|
|
218
|
+
white_space, language, replacement_mark, name = code_block_exp.match(header)[1..-1]
|
219
|
+
[name, source_file, language, replacement_mark]
|
220
|
+
end.group_by do |name, _, _, _|
|
221
|
+
name
|
222
|
+
end.transform_values do |blocks|
|
223
|
+
block_name, _, block_language, _ = blocks[0]
|
224
|
+
count, _ = blocks.inject(0) do |count, (name, source_file, language, replacement_mark)|
|
225
|
+
throw "block #{block_name} has multiple languages" unless language == block_language
|
226
|
+
count + 1
|
227
|
+
end
|
228
|
+
block_locations = blocks.each_with_index.map do |(name, source_file, language, replacement_mark), index|
|
229
|
+
[name, index, source_file]
|
230
|
+
end
|
231
|
+
{:count => count, :block_locations => block_locations}
|
232
|
+
end
|
233
|
+
end
|
234
|
+
```
|
235
|
+
|
236
|
+
### Including the Includes
|
237
|
+
|
238
|
+
This depends on the expression in [lmt_expressions][lmt_expressions.md#The-Include-Expression]
|
239
|
+
|
240
|
+
Here we go through each line looking for an include statement. When we find one, we replace it with the lines from that file. Those lines will, of course, need to have includes processed as well. For each line, we also need to add the file that it came from.
|
241
|
+
|
242
|
+
``` ruby include_includes
|
243
|
+
def include_includes(lines, current_file = @file_name, current_path = '', depth = 0)
|
244
|
+
raise "too many includes" if depth > 1000
|
245
|
+
include_exp = ⦅include_expression⦆
|
246
|
+
lines.map do |line|
|
247
|
+
match = include_exp.match(line)
|
248
|
+
if match
|
249
|
+
file = File.dirname(current_file) + '/' + match[1]
|
250
|
+
path = File.dirname(current_path) + '/' + match[1]
|
251
|
+
new_lines = File.open(file, 'r') {|f| f.readlines}
|
252
|
+
include_includes(new_lines, file, path, depth + 1)
|
253
|
+
else
|
254
|
+
[[line, current_path]]
|
255
|
+
end
|
256
|
+
end.flatten(1)
|
257
|
+
end
|
258
|
+
|
259
|
+
```
|
260
|
+
|
261
|
+
### Substituting the Directives and Headers
|
262
|
+
|
263
|
+
Now we need to substitute both the directives and headers with appropriate markdown replacements. To do so we need the [include expression](lmt_expressions.lmd#The-Include-Expression) and the [code block expression](lmt_expressions.lmd#The-Code-Block-Expression).
|
264
|
+
|
265
|
+
We will match the lines against the expressions and, when a match occurs, we will substitute the appropriate template. There is a little complexity when dealing with entering and exiting code fences. Specifically, we will need to toggle between entering and exiting code fence behavior.
|
266
|
+
|
267
|
+
``` ruby weave_class_privates
|
268
|
+
def substitute_directives_and_headers(lines)
|
269
|
+
include_expression = ⦅include_expression⦆
|
270
|
+
code_block_expression = ⦅code_block_expression⦆
|
271
|
+
in_block = false
|
272
|
+
block_name = ""
|
273
|
+
lines.map do |line|
|
274
|
+
case line
|
275
|
+
when include_expression
|
276
|
+
include_file = $1
|
277
|
+
["**See include:** [#{include_file}](include_file)\n"]
|
278
|
+
when code_block_expression
|
279
|
+
in_block = !in_block
|
280
|
+
if in_block
|
281
|
+
⦅make_code_block_header⦆
|
282
|
+
else
|
283
|
+
[line]
|
284
|
+
end
|
285
|
+
else
|
286
|
+
[line]
|
287
|
+
end
|
288
|
+
end.flatten(1)
|
289
|
+
end
|
290
|
+
```
|
291
|
+
|
292
|
+
#### The header for code blocks
|
293
|
+
|
294
|
+
Code blocks need to be headed appropriately as markdown parsing eats the code block name. Because of this we put it in a `h6` header. When the block is repeated, we add a `(part n)` to the end. We also should be adding links for the next and last version of this header.
|
295
|
+
|
296
|
+
``` ruby make_code_block_header
|
297
|
+
white_space, language, replacement_mark, name =
|
298
|
+
code_block_expression.match(line)[1..-1]
|
299
|
+
human_name = name.gsub(/[-_]/, ' ').split(' ').map(&:capitalize).join(' ')
|
300
|
+
replacing = if replacement_mark == "="
|
301
|
+
" Replacing"
|
302
|
+
else
|
303
|
+
""
|
304
|
+
end
|
305
|
+
header = if name != ""
|
306
|
+
"#######{replacing} Code Block: #{human_name}\n\n"
|
307
|
+
else
|
308
|
+
"#######{replacing} Output Block\n\n"
|
309
|
+
end
|
310
|
+
[header,
|
311
|
+
"#{white_space}``` #{language}\n"]
|
312
|
+
```
|
313
|
+
|
314
|
+
### Replacing the Markdown Links
|
315
|
+
|
316
|
+
``` ruby weave_class_privates
|
317
|
+
def replace_markdown_links(line)
|
318
|
+
line
|
319
|
+
end
|
320
|
+
```
|
321
|
+
|
322
|
+
### Write The Output
|
323
|
+
|
324
|
+
Finally, write the output.
|
325
|
+
|
326
|
+
``` ruby write
|
327
|
+
def write(output)
|
328
|
+
fout = File.open(output, 'w')
|
329
|
+
weave() unless @weaved
|
330
|
+
@weaved_lines.each {|line| fout << line}
|
331
|
+
end
|
332
|
+
|
333
|
+
```
|
334
|
+
|
335
|
+
## Option Verification
|
336
|
+
|
337
|
+
Option verification is described here:
|
338
|
+
|
339
|
+
! include [Option verification](option_verification.lmd)
|
340
|
+
|
341
|
+
## Testing
|
342
|
+
|
343
|
+
Of course, we will also need a testing procedure. In this case, we will be passing a set of strings in to the weave and seeing if the output is sane.
|
344
|
+
|
345
|
+
First, we need a method to report test failures:
|
346
|
+
|
347
|
+
! include [Error reporting](error_reporting.lmd)
|
348
|
+
|
349
|
+
``` ruby self_test
|
350
|
+
def self.self_test()
|
351
|
+
end
|
352
|
+
```
|
353
|
+
|
354
|
+
## Fin ┐( ˘_˘)┌
|
355
|
+
|
356
|
+
And with that, we have weaved some Markdown.
|
357
|
+
|
358
|
+
∎
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Option Verification
|
2
|
+
|
3
|
+
Sadly neither Methadone nor Optparser offer mandatory option verification, so we have to add it ourselves. (In the future, we will probably want to move this to a support library) Doing so requires two methods, required and check_arguments
|
4
|
+
|
5
|
+
``` ruby option_verification
|
6
|
+
def self.required(*options)
|
7
|
+
@required_options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.check_arguments
|
11
|
+
missing = @required_options.select{ |p| options[p].nil?}
|
12
|
+
unless missing.empty?
|
13
|
+
message = "Missing Required Argument(s): #{missing.join(', ')}"
|
14
|
+
|
15
|
+
abort("#{message}\n\n#{opts.help()}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
```
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lmt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marty Gentillon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-17 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.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: methadone
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.9.5
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.9.5
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: test-unit
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: A literate tangler written in Ruby for use with MarkDown.
|
98
|
+
email:
|
99
|
+
- marty.gentillon+lmt-ruby@gmail.com
|
100
|
+
executables:
|
101
|
+
- lmt
|
102
|
+
- lmw
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- ".gitignore"
|
107
|
+
- ".markdownlint.json"
|
108
|
+
- Gemfile
|
109
|
+
- Gemfile.lock
|
110
|
+
- README.md
|
111
|
+
- Rakefile
|
112
|
+
- bin/console
|
113
|
+
- bin/lmt
|
114
|
+
- bin/lmw
|
115
|
+
- bin/setup
|
116
|
+
- doc/lmt/error_reporting.md
|
117
|
+
- doc/lmt/lmt.rb.md
|
118
|
+
- doc/lmt/lmt_expressions.md
|
119
|
+
- doc/lmt/lmt_include.md
|
120
|
+
- doc/lmt/lmw.rb.md
|
121
|
+
- doc/lmt/option_verification.md
|
122
|
+
- lib/lmt.rb
|
123
|
+
- lib/lmt/lmt.rb
|
124
|
+
- lib/lmt/lmw.rb
|
125
|
+
- lib/lmt/version.rb
|
126
|
+
- lmt.gemspec
|
127
|
+
- src/lmt/error_reporting.lmd
|
128
|
+
- src/lmt/lmt.rb.lmd
|
129
|
+
- src/lmt/lmt_expressions.lmd
|
130
|
+
- src/lmt/lmt_include.lmd
|
131
|
+
- src/lmt/lmw.rb.lmd
|
132
|
+
- src/lmt/option_verification.lmd
|
133
|
+
homepage: https://github.com/MartyGentillon/lmt-ruby
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubygems_version: 3.0.1
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: A literate tangler written in Ruby for use with MarkDown.
|
156
|
+
test_files: []
|