markdown_it_ruby 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,473 @@
1
+ use markdown_it::parser::core::CoreRule;
2
+ use markdown_it::plugins::cmark::inline::{autolink::Autolink, link::Link};
3
+ use markdown_it::plugins::extra::linkify::Linkified;
4
+ use markdown_it::{MarkdownIt, Node, NodeValue, Renderer};
5
+
6
+ use crate::driver::{InternalDomain, MarkdonwItOptions};
7
+
8
+ #[derive(Debug)]
9
+ pub struct LinkWithTarget {
10
+ pub url: String,
11
+ pub title: Option<String>,
12
+ pub target: Option<String>,
13
+ pub rel: Option<String>,
14
+ }
15
+
16
+ impl NodeValue for LinkWithTarget {
17
+ fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
18
+ let mut attrs = node.attrs.clone();
19
+ attrs.push(("href", self.url.clone()));
20
+
21
+ if let Some(target) = self.target.as_ref() {
22
+ attrs.push(("target", target.to_string()));
23
+ }
24
+ if let Some(rel) = self.rel.as_ref() {
25
+ attrs.push(("rel", rel.to_string()));
26
+ }
27
+
28
+ if let Some(title) = &self.title {
29
+ attrs.push(("title", title.clone()));
30
+ }
31
+
32
+ fmt.open("a", &attrs);
33
+ fmt.contents(&node.children);
34
+ fmt.close("a");
35
+ }
36
+ }
37
+
38
+ impl LinkWithTarget {
39
+ pub fn new(
40
+ url: String,
41
+ title: Option<String>,
42
+ internal_domain_name: Option<InternalDomain>,
43
+ ) -> Self {
44
+ // for internal links only
45
+ if let Some(internal_domain_name) = internal_domain_name {
46
+ if internal_domain_name.matches(&url) {
47
+ return LinkWithTarget {
48
+ url,
49
+ title,
50
+ target: None,
51
+ rel: None,
52
+ };
53
+ }
54
+ }
55
+
56
+ // open external links in a new tab
57
+ LinkWithTarget {
58
+ url,
59
+ title,
60
+ target: Some("_blank".to_string()),
61
+ rel: Some("noopener noreferrer".to_string()),
62
+ }
63
+ }
64
+ }
65
+
66
+ struct LinkTargetRule;
67
+
68
+ impl CoreRule for LinkTargetRule {
69
+ // a custom function that will be invoked once per document.
70
+ fn run(root: &mut Node, md: &MarkdownIt) {
71
+ let options = md.ext.get::<MarkdonwItOptions>();
72
+ let internal_domain = match options {
73
+ None => None,
74
+ Some(options) => options.internal_domain(),
75
+ };
76
+
77
+ // walk through AST recursively
78
+ root.walk_mut(|node, _| {
79
+ if let Some(link) = node.cast::<Link>() {
80
+ let link_with_target = LinkWithTarget::new(
81
+ link.url.clone(),
82
+ link.title.clone(),
83
+ internal_domain.clone(),
84
+ );
85
+ node.replace::<LinkWithTarget>(link_with_target);
86
+ } else if let Some(autolink) = node.cast::<Autolink>() {
87
+ let link_with_target =
88
+ LinkWithTarget::new(autolink.url.clone(), None, internal_domain.clone());
89
+ node.replace::<LinkWithTarget>(link_with_target);
90
+ } else if let Some(linkified) = node.cast::<Linkified>() {
91
+ let link_with_target =
92
+ LinkWithTarget::new(linkified.url.clone(), None, internal_domain.clone());
93
+ node.replace::<LinkWithTarget>(link_with_target);
94
+ }
95
+ });
96
+ }
97
+ }
98
+
99
+ pub fn add(md: &mut MarkdownIt) {
100
+ md.add_rule::<LinkTargetRule>();
101
+ }
102
+
103
+ #[test]
104
+ fn test_link_with_target() {
105
+ use std::collections::HashMap;
106
+
107
+ let mut md = MarkdownIt::new();
108
+
109
+ markdown_it::plugins::cmark::add(&mut md);
110
+ markdown_it::plugins::extra::add(&mut md);
111
+ add(&mut md);
112
+
113
+ {
114
+ // without options
115
+ {
116
+ // for non-autolink (custom links)
117
+ {
118
+ // with scheme part
119
+ {
120
+ // with base_url that has scheme part
121
+ let src = "[some title](https://kyoto.dosue.jp/foo/bar)";
122
+ let html = md.parse(src).render();
123
+ assert_eq!(
124
+ html,
125
+ "<p><a href=\"https://kyoto.dosue.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
126
+ );
127
+ }
128
+ {
129
+ // with base_url with http scheme
130
+ let src = "[some title](http://kyoto.dosue.jp/foo/bar)";
131
+ let html = md.parse(src).render();
132
+ assert_eq!(
133
+ html,
134
+ "<p><a href=\"http://kyoto.dosue.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
135
+ );
136
+ }
137
+ {
138
+ // with subdomain of base_url
139
+ let src = "[some title](https://fuji.kyoto.dosue.jp/foo/bar)";
140
+ let html = md.parse(src).render();
141
+ assert_eq!(
142
+ html,
143
+ "<p><a href=\"https://fuji.kyoto.dosue.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
144
+ );
145
+ }
146
+ {
147
+ // with 'parent' domain of base_url
148
+ // this should be treated as external link
149
+ let src = "[some title](https://dosue.jp/foo/bar)";
150
+ let html = md.parse(src).render();
151
+ assert_eq!(
152
+ html,
153
+ "<p><a href=\"https://dosue.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
154
+ );
155
+ }
156
+ {
157
+ // with different domain
158
+ let src = "[some title](https://nara.jp/foo/bar)";
159
+ let html = md.parse(src).render();
160
+ assert_eq!(
161
+ html,
162
+ "<p><a href=\"https://nara.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
163
+ );
164
+ }
165
+ }
166
+ {
167
+ // without sheme part
168
+ {
169
+ // domain part is the same as base_url
170
+ let src = "[some title](kyoto.dosue.jp/foo/bar)";
171
+ let html = md.parse(src).render();
172
+ assert_eq!(
173
+ html,
174
+ "<p><a href=\"kyoto.dosue.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
175
+ );
176
+ }
177
+ {
178
+ // domain part is different from base_url
179
+ // NOTE: for simplicity, any url without scheme part is treated as "internal" link
180
+ let src = "[some title](dosue.jp/foo/bar)";
181
+ let html = md.parse(src).render();
182
+ assert_eq!(html, "<p><a href=\"dosue.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n");
183
+ }
184
+ {
185
+ // without domain part
186
+ let src = "[some title](foo/bar)";
187
+ let html = md.parse(src).render();
188
+ assert_eq!(html, "<p><a href=\"foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n");
189
+ }
190
+ {
191
+ // with filename
192
+ let src = "[some title](foo.jpg)";
193
+ let html = md.parse(src).render();
194
+ assert_eq!(html, "<p><a href=\"foo.jpg\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n");
195
+ }
196
+ }
197
+ }
198
+ {
199
+ // for autolink urls
200
+ {
201
+ // with base_url
202
+ let src = "<https://kyoto.dosue.jp>";
203
+ let html = md.parse(src).render();
204
+ assert_eq!(
205
+ html,
206
+ "<p><a href=\"https://kyoto.dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">kyoto.dosue.jp</a></p>\n"
207
+ );
208
+ }
209
+ {
210
+ // with child domain of base_url
211
+ let src = "<https://pontocho.kyoto.dosue.jp>";
212
+ let html = md.parse(src).render();
213
+ assert_eq!(
214
+ html,
215
+ "<p><a href=\"https://pontocho.kyoto.dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">pontocho.kyoto.dosue.jp</a></p>\n"
216
+ );
217
+ }
218
+ {
219
+ // with parent domain of base_url
220
+ let src = "<https://dosue.jp>";
221
+ let html = md.parse(src).render();
222
+ assert_eq!(
223
+ html,
224
+ "<p><a href=\"https://dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">dosue.jp</a></p>\n"
225
+ );
226
+ }
227
+ {
228
+ // with base_url, with http scheme
229
+ let src = "<http://kyoto.dosue.jp>";
230
+ let html = md.parse(src).render();
231
+ assert_eq!(
232
+ html,
233
+ "<p><a href=\"http://kyoto.dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">kyoto.dosue.jp</a></p>\n"
234
+ );
235
+ }
236
+ {
237
+ // external links
238
+ let src = "<https://nara.jp>";
239
+ let html = md.parse(src).render();
240
+ assert_eq!(html, "<p><a href=\"https://nara.jp\" target=\"_blank\" rel=\"noopener noreferrer\">nara.jp</a></p>\n");
241
+ }
242
+ }
243
+ {
244
+ // for linkified urls
245
+ {
246
+ // with base_url
247
+ let src = "https://kyoto.dosue.jp";
248
+ let html = md.parse(src).render();
249
+ assert_eq!(
250
+ html,
251
+ "<p><a href=\"https://kyoto.dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">kyoto.dosue.jp</a></p>\n"
252
+ );
253
+ }
254
+ {
255
+ // with child domain of base_url
256
+ let src = "https://pontocho.kyoto.dosue.jp";
257
+ let html = md.parse(src).render();
258
+ assert_eq!(
259
+ html,
260
+ "<p><a href=\"https://pontocho.kyoto.dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">pontocho.kyoto.dosue.jp</a></p>\n"
261
+ );
262
+ }
263
+ {
264
+ // with parent domain of base_url
265
+ let src = "https://dosue.jp";
266
+ let html = md.parse(src).render();
267
+ assert_eq!(
268
+ html,
269
+ "<p><a href=\"https://dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">dosue.jp</a></p>\n"
270
+ );
271
+ }
272
+ {
273
+ // with base_url, with http scheme
274
+ let src = "http://kyoto.dosue.jp";
275
+ let html = md.parse(src).render();
276
+ assert_eq!(
277
+ html,
278
+ "<p><a href=\"http://kyoto.dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">kyoto.dosue.jp</a></p>\n"
279
+ );
280
+ }
281
+ {
282
+ // external links
283
+ let src = "https://nara.jp";
284
+ let html = md.parse(src).render();
285
+ assert_eq!(html, "<p><a href=\"https://nara.jp\" target=\"_blank\" rel=\"noopener noreferrer\">nara.jp</a></p>\n");
286
+ }
287
+ }
288
+ }
289
+
290
+ {
291
+ // with options
292
+ let base_url = "https://kyoto.dosue.jp".to_string();
293
+ let options = MarkdonwItOptions::new(HashMap::from([(
294
+ "internal_domain_name".to_string(),
295
+ base_url.to_string(),
296
+ )]));
297
+ options.add(&mut md);
298
+
299
+ {
300
+ // for non-autolink (custom links)
301
+ {
302
+ // with scheme part
303
+ {
304
+ // with base_url that has scheme part
305
+ let src = "[some title](https://kyoto.dosue.jp/foo/bar)";
306
+ let html = md.parse(src).render();
307
+ assert_eq!(
308
+ html,
309
+ "<p><a href=\"https://kyoto.dosue.jp/foo/bar\">some title</a></p>\n"
310
+ );
311
+ }
312
+ {
313
+ // with base_url with http scheme
314
+ let src = "[some title](http://kyoto.dosue.jp/foo/bar)";
315
+ let html = md.parse(src).render();
316
+ assert_eq!(
317
+ html,
318
+ "<p><a href=\"http://kyoto.dosue.jp/foo/bar\">some title</a></p>\n"
319
+ );
320
+ }
321
+ {
322
+ // with subdomain of base_url
323
+ let src = "[some title](https://fuji.kyoto.dosue.jp/foo/bar)";
324
+ let html = md.parse(src).render();
325
+ assert_eq!(
326
+ html,
327
+ "<p><a href=\"https://fuji.kyoto.dosue.jp/foo/bar\">some title</a></p>\n"
328
+ );
329
+ }
330
+ {
331
+ // with 'parent' domain of base_url
332
+ // this should be treated as external link
333
+ let src = "[some title](https://dosue.jp/foo/bar)";
334
+ let html = md.parse(src).render();
335
+ assert_eq!(
336
+ html,
337
+ "<p><a href=\"https://dosue.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
338
+ );
339
+ }
340
+ {
341
+ // with different domain
342
+ let src = "[some title](https://nara.jp/foo/bar)";
343
+ let html = md.parse(src).render();
344
+ assert_eq!(
345
+ html,
346
+ "<p><a href=\"https://nara.jp/foo/bar\" target=\"_blank\" rel=\"noopener noreferrer\">some title</a></p>\n"
347
+ );
348
+ }
349
+ }
350
+ {
351
+ // without sheme part
352
+ {
353
+ // domain part is the same as base_url
354
+ let src = "[some title](kyoto.dosue.jp/foo/bar)";
355
+ let html = md.parse(src).render();
356
+ assert_eq!(
357
+ html,
358
+ "<p><a href=\"kyoto.dosue.jp/foo/bar\">some title</a></p>\n"
359
+ );
360
+ }
361
+ {
362
+ // domain part is different from base_url
363
+ // NOTE: for simplicity, any url without scheme part is treated as "internal" link
364
+ let src = "[some title](dosue.jp/foo/bar)";
365
+ let html = md.parse(src).render();
366
+ assert_eq!(html, "<p><a href=\"dosue.jp/foo/bar\">some title</a></p>\n");
367
+ }
368
+ {
369
+ // without domain part
370
+ let src = "[some title](foo/bar)";
371
+ let html = md.parse(src).render();
372
+ assert_eq!(html, "<p><a href=\"foo/bar\">some title</a></p>\n");
373
+ }
374
+ {
375
+ // with filename
376
+ let src = "[some title](foo.jpg)";
377
+ let html = md.parse(src).render();
378
+ assert_eq!(html, "<p><a href=\"foo.jpg\">some title</a></p>\n");
379
+ }
380
+ }
381
+ }
382
+ {
383
+ // for autolink urls
384
+ {
385
+ // with base_url
386
+ let src = "<https://kyoto.dosue.jp>";
387
+ let html = md.parse(src).render();
388
+ assert_eq!(
389
+ html,
390
+ "<p><a href=\"https://kyoto.dosue.jp\">kyoto.dosue.jp</a></p>\n"
391
+ );
392
+ }
393
+ {
394
+ // with child domain of base_url
395
+ let src = "<https://pontocho.kyoto.dosue.jp>";
396
+ let html = md.parse(src).render();
397
+ assert_eq!(
398
+ html,
399
+ "<p><a href=\"https://pontocho.kyoto.dosue.jp\">pontocho.kyoto.dosue.jp</a></p>\n"
400
+ );
401
+ }
402
+ {
403
+ // with parent domain of base_url
404
+ let src = "<https://dosue.jp>";
405
+ let html = md.parse(src).render();
406
+ assert_eq!(
407
+ html,
408
+ "<p><a href=\"https://dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">dosue.jp</a></p>\n"
409
+ );
410
+ }
411
+ {
412
+ // with base_url, with http scheme
413
+ let src = "<http://kyoto.dosue.jp>";
414
+ let html = md.parse(src).render();
415
+ assert_eq!(
416
+ html,
417
+ "<p><a href=\"http://kyoto.dosue.jp\">kyoto.dosue.jp</a></p>\n"
418
+ );
419
+ }
420
+ {
421
+ // external links
422
+ let src = "<https://nara.jp>";
423
+ let html = md.parse(src).render();
424
+ assert_eq!(html, "<p><a href=\"https://nara.jp\" target=\"_blank\" rel=\"noopener noreferrer\">nara.jp</a></p>\n");
425
+ }
426
+ }
427
+ {
428
+ // for linkified urls
429
+ {
430
+ // with base_url
431
+ let src = "https://kyoto.dosue.jp";
432
+ let html = md.parse(src).render();
433
+ assert_eq!(
434
+ html,
435
+ "<p><a href=\"https://kyoto.dosue.jp\">kyoto.dosue.jp</a></p>\n"
436
+ );
437
+ }
438
+ {
439
+ // with child domain of base_url
440
+ let src = "https://pontocho.kyoto.dosue.jp";
441
+ let html = md.parse(src).render();
442
+ assert_eq!(
443
+ html,
444
+ "<p><a href=\"https://pontocho.kyoto.dosue.jp\">pontocho.kyoto.dosue.jp</a></p>\n"
445
+ );
446
+ }
447
+ {
448
+ // with parent domain of base_url
449
+ let src = "https://dosue.jp";
450
+ let html = md.parse(src).render();
451
+ assert_eq!(
452
+ html,
453
+ "<p><a href=\"https://dosue.jp\" target=\"_blank\" rel=\"noopener noreferrer\">dosue.jp</a></p>\n"
454
+ );
455
+ }
456
+ {
457
+ // with base_url, with http scheme
458
+ let src = "http://kyoto.dosue.jp";
459
+ let html = md.parse(src).render();
460
+ assert_eq!(
461
+ html,
462
+ "<p><a href=\"http://kyoto.dosue.jp\">kyoto.dosue.jp</a></p>\n"
463
+ );
464
+ }
465
+ {
466
+ // external links
467
+ let src = "https://nara.jp";
468
+ let html = md.parse(src).render();
469
+ assert_eq!(html, "<p><a href=\"https://nara.jp\" target=\"_blank\" rel=\"noopener noreferrer\">nara.jp</a></p>\n");
470
+ }
471
+ }
472
+ }
473
+ }
@@ -0,0 +1,88 @@
1
+ use crate::driver::MarkdonwItOptions;
2
+ use markdown_it::parser::core::CoreRule;
3
+ use markdown_it::plugins::extra::tables::Table;
4
+ use markdown_it::{MarkdownIt, Node, NodeValue, Renderer};
5
+
6
+ #[derive(Debug)]
7
+ pub struct TableDecoration {
8
+ pub table: Table,
9
+ pub class_name: String,
10
+ }
11
+
12
+ impl NodeValue for TableDecoration {
13
+ fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
14
+ let class_name = self.class_name.clone();
15
+ let div_attrs = vec![("class", class_name)];
16
+ fmt.open("div", &div_attrs);
17
+ fmt.cr();
18
+ self.table.render(node, fmt);
19
+ fmt.cr();
20
+ fmt.close("div");
21
+ }
22
+ }
23
+
24
+ struct TableDecorationRule;
25
+
26
+ impl CoreRule for TableDecorationRule {
27
+ // a custom function that will be invoked once per document.
28
+ fn run(root: &mut Node, md: &MarkdownIt) {
29
+ let options = md.ext.get::<MarkdonwItOptions>();
30
+ let table_class_name = match options {
31
+ Some(options) => options.get_option_or_default("table_class_name", "table"),
32
+ None => "table".to_string(),
33
+ };
34
+ root.walk_mut(|node, _| {
35
+ if let Some(table) = node.cast::<Table>() {
36
+ node.replace(TableDecoration {
37
+ table: Table {
38
+ alignments: table.alignments.clone(),
39
+ },
40
+ class_name: table_class_name.clone(),
41
+ })
42
+ }
43
+ });
44
+ }
45
+ }
46
+
47
+ pub fn add(md: &mut MarkdownIt) {
48
+ md.add_rule::<TableDecorationRule>();
49
+ }
50
+
51
+ #[test]
52
+ fn test_table_decoration() {
53
+ use std::collections::HashMap;
54
+
55
+ let mut md = MarkdownIt::new();
56
+
57
+ markdown_it::plugins::cmark::add(&mut md);
58
+ markdown_it::plugins::extra::add(&mut md);
59
+ add(&mut md);
60
+
61
+ {
62
+ // without options
63
+ let src = "| 左寄せタイトル | センタリング | 右寄せタイトル |\n |:------------|:------------:|-----------:|\n | column | column | column |\n";
64
+ let html = md.parse(src).render();
65
+
66
+ assert_eq!(
67
+ html,
68
+ "<div class=\"table\">\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">左寄せタイトル</th>\n<th style=\"text-align:center\">センタリング</th>\n<th style=\"text-align:right\">右寄せタイトル</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">column</td>\n<td style=\"text-align:center\">column</td>\n<td style=\"text-align:right\">column</td>\n</tr>\n</tbody>\n</table>\n</div>"
69
+ )
70
+ }
71
+
72
+ {
73
+ // with options
74
+ let options = MarkdonwItOptions::new(HashMap::from([(
75
+ "table_class_name".to_string(),
76
+ "custom-table-class-name".to_string(),
77
+ )]));
78
+ options.add(&mut md);
79
+
80
+ let src = "| 左寄せタイトル | センタリング | 右寄せタイトル |\n |:------------|:------------:|-----------:|\n | column | column | column |\n";
81
+ let html = md.parse(src).render();
82
+
83
+ assert_eq!(
84
+ html,
85
+ "<div class=\"custom-table-class-name\">\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">左寄せタイトル</th>\n<th style=\"text-align:center\">センタリング</th>\n<th style=\"text-align:right\">右寄せタイトル</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">column</td>\n<td style=\"text-align:center\">column</td>\n<td style=\"text-align:right\">column</td>\n</tr>\n</tbody>\n</table>\n</div>"
86
+ )
87
+ }
88
+ }
@@ -0,0 +1,18 @@
1
+ pub(super) mod heading_level_modification;
2
+ pub(super) mod link_with_target;
3
+ pub(super) mod table_decoration;
4
+
5
+ use crate::driver::MarkdonwItOptions;
6
+ use markdown_it::MarkdownIt;
7
+
8
+ pub(super) fn add(md: &mut MarkdownIt, option: &MarkdonwItOptions) {
9
+ if option.is_enabled("heading_level_offset", true) {
10
+ heading_level_modification::add(md);
11
+ }
12
+ if option.is_enabled("internal_domain_name", true) {
13
+ link_with_target::add(md);
14
+ }
15
+ if option.is_enabled("table_class_name", true) {
16
+ table_decoration::add(md);
17
+ }
18
+ }
@@ -0,0 +1,35 @@
1
+ mod driver;
2
+ mod extensions;
3
+ use magnus::{define_module, function, prelude::*, Error};
4
+ use std::collections::HashMap;
5
+
6
+ // macro for regex
7
+ //
8
+ // usage:
9
+ //
10
+ // use crate::regex;
11
+ // let domain_regex = regex!(r"^[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+/");
12
+ // if domain_regex.is_match(url) { ...
13
+ #[macro_export]
14
+ macro_rules! regex {
15
+ ($re:literal $(,)?) => {{
16
+ static RE: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
17
+ RE.get_or_init(|| regex::Regex::new($re).unwrap())
18
+ }};
19
+ }
20
+
21
+ use driver::MarkdownDriver;
22
+
23
+ fn convert(contents: String, options: HashMap<String, String>) -> String {
24
+ let handler = MarkdownDriver::new(options);
25
+ handler.parse(contents);
26
+ handler.render()
27
+ }
28
+
29
+ #[magnus::init]
30
+ fn init() -> Result<(), Error> {
31
+ let module = define_module("MarkdownIt")?;
32
+ module.define_singleton_method("__convert", function!(convert, 2))?;
33
+
34
+ Ok(())
35
+ }
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MarkdownIt
4
+ VERSION = "0.1.1"
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "markdown_it_ruby/version"
4
+ require_relative "markdown_it_ruby/markdown_it_ruby"
5
+
6
+ module MarkdownIt
7
+ class Error < StandardError; end
8
+
9
+ def self.convert(input, **options)
10
+ options.transform_keys!(&:to_s)
11
+ options.transform_values!(&:to_s)
12
+
13
+ __convert(input, **options)
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module MarkdownIt
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end