qiita_marker 0.23.2.2 → 0.23.5.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +19 -17
  3. data/Rakefile +57 -56
  4. data/bin/qiita_marker +2 -7
  5. data/ext/qiita_marker/blocks.c +4 -1
  6. data/ext/qiita_marker/cmark-gfm_version.h +2 -2
  7. data/ext/qiita_marker/qfm_custom_block.c +33 -52
  8. data/ext/qiita_marker/qiita_marker.c +30 -44
  9. data/ext/qiita_marker/scanners.c +2438 -2450
  10. data/ext/qiita_marker/table.c +28 -2
  11. data/lib/qiita_marker/config.rb +3 -3
  12. data/lib/qiita_marker/node/inspect.rb +8 -18
  13. data/lib/qiita_marker/node.rb +6 -6
  14. data/lib/qiita_marker/renderer/html_renderer.rb +38 -38
  15. data/lib/qiita_marker/renderer.rb +5 -5
  16. data/lib/qiita_marker/version.rb +1 -1
  17. data/lib/qiita_marker.rb +9 -11
  18. data/qiita_marker.gemspec +27 -29
  19. metadata +3 -63
  20. data/test/benchmark.rb +0 -32
  21. data/test/fixtures/curly.md +0 -1
  22. data/test/fixtures/dingus.md +0 -10
  23. data/test/fixtures/strong.md +0 -1
  24. data/test/fixtures/table.md +0 -10
  25. data/test/test_attributes.rb +0 -24
  26. data/test/test_basics.rb +0 -35
  27. data/test/test_commands.rb +0 -72
  28. data/test/test_commonmark.rb +0 -36
  29. data/test/test_doc.rb +0 -130
  30. data/test/test_encoding.rb +0 -23
  31. data/test/test_extensions.rb +0 -116
  32. data/test/test_footnotes.rb +0 -60
  33. data/test/test_gc.rb +0 -47
  34. data/test/test_helper.rb +0 -71
  35. data/test/test_linebreaks.rb +0 -15
  36. data/test/test_maliciousness.rb +0 -262
  37. data/test/test_node.rb +0 -89
  38. data/test/test_options.rb +0 -37
  39. data/test/test_pathological_inputs.rb +0 -94
  40. data/test/test_plaintext.rb +0 -46
  41. data/test/test_qfm_autolink_class_name.rb +0 -62
  42. data/test/test_qfm_code_data_metadata.rb +0 -41
  43. data/test/test_qfm_custom_block.rb +0 -39
  44. data/test/test_qfm_mention_no_emphasis.rb +0 -60
  45. data/test/test_renderer.rb +0 -47
  46. data/test/test_smartpunct.rb +0 -27
  47. data/test/test_spec.rb +0 -30
  48. data/test/test_tasklists.rb +0 -43
  49. data/test/test_xml.rb +0 -107
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15d5d73e2386cf310ae997adc33bfca334a51c241a0345b8d5fddc2af9a988bf
4
- data.tar.gz: c45e0c3f30cfd5dfad5d8beb4dc0f3ee08fc6bb405e2dfb188623393180fa104
3
+ metadata.gz: 343d2a549df9aee75c4bb3890307425d9a82251a2dfe46826afd6f8a8bfcb245
4
+ data.tar.gz: bf76c480df59b28e13cace472228b3ca39a60d9ce3406a866125f347c18689c1
5
5
  SHA512:
6
- metadata.gz: 88d95a7228008d65a57f13d571370c3fe9a3701319e2e6a801a16659c032646d592345e155a23a8ac4f70b8d87a347b152a72b8447399c73285f2b475e3426d5
7
- data.tar.gz: b3a3a996bfac4705044451fee3ecd7cd29909de05b3a1c9b52f64e9cc9cf14497820b8a74f67f49225c7ab777d87a83e9a0da104fa15219df03a3efb1c054a66
6
+ metadata.gz: 0c8c25dda4cadad88e855c84fa02d42de53c54c87665ca6b5530483a78b57e100b3df9869fe1f451faf16679a5de3ed7c6f630c9568258fdb559fd0d255cb2e2
7
+ data.tar.gz: d0927839957a98673181f2235f8a4e16a6ddfc2fa5bb88259d0cb7723bf925472e8214f98aa5ede40a24d3420af48b8b8e877472278efeb683eba80c171edd92
data/LICENSE.txt CHANGED
@@ -1,21 +1,23 @@
1
- MIT License
1
+ Copyright (c) 2015 Garen J. Torikian
2
+ Copyright (c) 2021 Qiita Inc.
2
3
 
3
- Copyright 2021 Qiita Inc.
4
+ MIT License
4
5
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
11
13
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
14
16
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,113 +1,114 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
4
- require 'rake/clean'
5
- require 'rake/extensiontask'
6
- require 'digest/md5'
3
+ require "date"
4
+ require "rake/clean"
5
+ require "rake/extensiontask"
6
+ require "digest/md5"
7
7
 
8
- host_os = RbConfig::CONFIG['host_os']
9
- require 'devkit' if host_os == 'mingw32'
8
+ host_os = RbConfig::CONFIG["host_os"]
9
+ require "devkit" if host_os == "mingw32"
10
10
 
11
11
  task default: [:test]
12
12
 
13
13
  # Gem Spec
14
- gem_spec = Gem::Specification.load('qiita_marker.gemspec')
14
+ gem_spec = Gem::Specification.load("qiita_marker.gemspec")
15
15
 
16
16
  # Ruby Extension
17
- Rake::ExtensionTask.new('qiita_marker', gem_spec) do |ext|
18
- ext.lib_dir = File.join('lib', 'qiita_marker')
17
+ Rake::ExtensionTask.new("qiita_marker", gem_spec) do |ext|
18
+ ext.lib_dir = File.join("lib", "qiita_marker")
19
19
  end
20
20
 
21
21
  # Packaging
22
- require 'bundler/gem_tasks'
22
+ require "bundler/gem_tasks"
23
23
 
24
24
  # Testing
25
- require 'rake/testtask'
25
+ require "rake/testtask"
26
26
 
27
- Rake::TestTask.new('test:unit') do |t|
28
- t.libs << 'lib'
29
- t.libs << 'test'
30
- t.pattern = 'test/test_*.rb'
27
+ Rake::TestTask.new("test:unit") do |t|
28
+ t.libs << "lib"
29
+ t.libs << "test"
30
+ t.pattern = "test/test_*.rb"
31
31
  t.verbose = true
32
32
  t.warning = false
33
33
  end
34
34
 
35
- task 'test:unit' => :compile
35
+ desc "Run unit tests"
36
+ task "test:unit" => :compile
36
37
 
37
- desc 'Run unit and conformance tests'
38
- task test: %w[test:unit]
38
+ desc "Run unit and conformance tests"
39
+ task test: ["test:unit"]
39
40
 
40
- require 'rubocop/rake_task'
41
+ require "rubocop/rake_task"
41
42
 
42
43
  RuboCop::RakeTask.new(:rubocop)
43
44
 
44
- desc 'Run benchmarks'
45
+ desc "Run benchmarks"
45
46
  task :benchmark do
46
- if ENV['FETCH_PROGIT']
47
- `rm -rf test/progit`
48
- `git clone https://github.com/progit/progit.git test/progit`
49
- langs = %w[ar az be ca cs de en eo es es-ni fa fi fr hi hu id it ja ko mk nl no-nb pl pt-br ro ru sr th tr uk vi zh zh-tw]
47
+ if ENV["FETCH_PROGIT"]
48
+ %x(rm -rf test/progit)
49
+ %x(git clone https://github.com/progit/progit.git test/progit)
50
+ langs = ["ar", "az", "be", "ca", "cs", "de", "en", "eo", "es", "es-ni", "fa", "fi", "fr", "hi", "hu", "id", "it", "ja", "ko", "mk", "nl", "no-nb", "pl", "pt-br", "ro", "ru", "sr", "th", "tr", "uk", "vi", "zh", "zh-tw"]
50
51
  langs.each do |lang|
51
- `cat test/progit/#{lang}/*/*.markdown >> test/benchinput.md`
52
+ %x(cat test/progit/#{lang}/*/*.markdown >> test/benchinput.md)
52
53
  end
53
54
  end
54
- $LOAD_PATH.unshift 'lib'
55
- load 'test/benchmark.rb'
55
+ $LOAD_PATH.unshift("lib")
56
+ load "test/benchmark.rb"
56
57
  end
57
58
 
58
- desc 'Match C style of cmark'
59
+ desc "Match C style of cmark"
59
60
  task :format do
60
- sh 'clang-format -style llvm -i ext/qiita_marker/*.c ext/qiita_marker/*.h'
61
+ sh "clang-format -style llvm -i ext/qiita_marker/*.c ext/qiita_marker/*.h"
61
62
  end
62
63
 
63
64
  # Documentation
64
- require 'rdoc/task'
65
+ require "rdoc/task"
65
66
 
66
- desc 'Generate API documentation'
67
+ desc "Generate API documentation"
67
68
  RDoc::Task.new do |rd|
68
- rd.rdoc_dir = 'docs'
69
- rd.main = 'README.md'
70
- rd.rdoc_files.include 'README.md', 'lib/**/*.rb', 'ext/qiita_marker/qiita_marker.c'
71
-
72
- rd.options << '--markup tomdoc'
73
- rd.options << '--inline-source'
74
- rd.options << '--line-numbers'
75
- rd.options << '--all'
76
- rd.options << '--fileboxes'
69
+ rd.rdoc_dir = "docs"
70
+ rd.main = "README.md"
71
+ rd.rdoc_files.include("README.md", "lib/**/*.rb", "ext/qiita_marker/qiita_marker.c")
72
+
73
+ rd.options << "--markup tomdoc"
74
+ rd.options << "--inline-source"
75
+ rd.options << "--line-numbers"
76
+ rd.options << "--all"
77
+ rd.options << "--fileboxes"
77
78
  end
78
79
 
79
- desc 'Generate the documentation and run a web server'
80
+ desc "Generate the documentation and run a web server"
80
81
  task serve: [:rdoc] do
81
- require 'webrick'
82
+ require "webrick"
82
83
 
83
- puts 'Navigate to http://localhost:3000 to see the docs'
84
+ puts "Navigate to http://localhost:3000 to see the docs"
84
85
 
85
- server = WEBrick::HTTPServer.new Port: 3000
86
- server.mount '/', WEBrick::HTTPServlet::FileHandler, 'docs'
87
- trap('INT') { server.stop }
86
+ server = WEBrick::HTTPServer.new(Port: 3000)
87
+ server.mount("/", WEBrick::HTTPServlet::FileHandler, "docs")
88
+ trap("INT") { server.stop }
88
89
  server.start
89
90
  end
90
91
 
91
- desc 'Generate and publish docs to gh-pages'
92
+ desc "Generate and publish docs to gh-pages"
92
93
  task publish: [:rdoc] do
93
- require 'tmpdir'
94
- require 'shellwords'
94
+ require "tmpdir"
95
+ require "shellwords"
95
96
 
96
97
  Dir.mktmpdir do |tmp|
97
98
  system "mv docs/* #{tmp}"
98
- system 'git checkout origin/gh-pages'
99
- system 'rm -rf *'
99
+ system "git checkout origin/gh-pages"
100
+ system "rm -rf *"
100
101
  system "mv #{tmp}/* ."
101
102
  message = Shellwords.escape("Site updated at #{Time.now.utc}")
102
- system 'git add .'
103
+ system "git add ."
103
104
  system "git commit -am #{message}"
104
- system 'git push origin gh-pages --force'
105
- system 'git checkout master'
106
- system 'echo yolo'
105
+ system "git push origin gh-pages --force"
106
+ system "git checkout master"
107
+ system "echo yolo"
107
108
  end
108
109
  end
109
110
 
110
111
  # Custom tasks
111
- Dir.glob('tasks/*.rake').each do |f|
112
+ Dir.glob("tasks/*.rake").each do |f|
112
113
  load f
113
114
  end
data/bin/qiita_marker CHANGED
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'optparse'
5
- require 'ostruct'
6
5
 
7
6
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
8
7
  require 'qiita_marker'
@@ -11,17 +10,13 @@ root = File.expand_path('..', __dir__)
11
10
  $LOAD_PATH.unshift File.expand_path('lib', root)
12
11
 
13
12
  def parse_options
14
- options = OpenStruct.new
13
+ options = Struct.new(:active_extensions, :active_parse_options, :active_render_options, :output_format, :renderer)
14
+ .new([], [:DEFAULT], [:DEFAULT], :html)
15
15
  extensions = QiitaMarker.extensions
16
16
  parse_options = QiitaMarker::Config::OPTS.fetch(:parse)
17
17
  render_options = QiitaMarker::Config::OPTS.fetch(:render)
18
18
  format_options = QiitaMarker::Config::OPTS.fetch(:format)
19
19
 
20
- options.active_extensions = []
21
- options.active_parse_options = [:DEFAULT]
22
- options.active_render_options = [:DEFAULT]
23
- options.output_format = :html
24
-
25
20
  option_parser = OptionParser.new do |opts|
26
21
  opts.banner = 'Usage: qiita_marker [--html-renderer] [--extension=EXTENSION]'
27
22
  opts.separator ' [--to=FORMAT]'
@@ -22,6 +22,7 @@
22
22
  #include "houdini.h"
23
23
  #include "buffer.h"
24
24
  #include "footnotes.h"
25
+ #include "qfm_custom_block.h"
25
26
 
26
27
  #define CODE_INDENT 4
27
28
  #define TAB_STOP 4
@@ -289,7 +290,9 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
289
290
  b->end_column = parser->last_line_length;
290
291
  } else if (S_type(b) == CMARK_NODE_DOCUMENT ||
291
292
  (S_type(b) == CMARK_NODE_CODE_BLOCK && b->as.code.fenced) ||
292
- (S_type(b) == CMARK_NODE_HEADING && b->as.heading.setext)) {
293
+ (S_type(b) == CMARK_NODE_HEADING && b->as.heading.setext) ||
294
+ /* For make the sourcepos of the `qfm_custom_block` accurate */
295
+ (cmark_node_get_type(b) == CMARK_NODE_QFM_CUSTOM_BLOCK)) {
293
296
  b->end_line = parser->line_number;
294
297
  b->end_column = parser->curline.size;
295
298
  if (b->end_column && parser->curline.ptr[b->end_column - 1] == '\n')
@@ -1,7 +1,7 @@
1
1
  #ifndef CMARK_GFM_VERSION_H
2
2
  #define CMARK_GFM_VERSION_H
3
3
 
4
- #define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 2)
5
- #define CMARK_GFM_VERSION_STRING "0.29.0.gfm.2"
4
+ #define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 4)
5
+ #define CMARK_GFM_VERSION_STRING "0.29.0.gfm.4"
6
6
 
7
7
  #endif
@@ -6,14 +6,13 @@
6
6
  #include "houdini.h"
7
7
  #include "qfm_custom_block.h"
8
8
  #include "qfm_scanners.h"
9
- #include "strikethrough.h"
10
9
 
11
10
  cmark_node_type CMARK_NODE_QFM_CUSTOM_BLOCK;
12
11
 
13
12
  typedef struct {
13
+ /* info: Text following the opening custom block fence (optional). This is
14
+ * trimmed of leading and trailing whitespace. */
14
15
  cmark_chunk info;
15
- bool opening;
16
- cmark_strbuf *xml_attr_buff;
17
16
  } node_qfm_custom_block;
18
17
 
19
18
  static void escape_html(cmark_strbuf *dest, const unsigned char *source,
@@ -21,33 +20,6 @@ static void escape_html(cmark_strbuf *dest, const unsigned char *source,
21
20
  houdini_escape_html0(dest, source, length, 0);
22
21
  }
23
22
 
24
- static bool get_qfm_custom_block_opening(cmark_node *node) {
25
- if (node == NULL) {
26
- return false;
27
- }
28
-
29
- cmark_node_type node_type = cmark_node_get_type(node);
30
- if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
31
- return ((node_qfm_custom_block *)node->as.opaque)->opening;
32
- } else {
33
- return false;
34
- }
35
- }
36
-
37
- static bool set_qfm_custom_block_opening(cmark_node *node, bool opening) {
38
- if (node == NULL) {
39
- return false;
40
- }
41
-
42
- cmark_node_type node_type = cmark_node_get_type(node);
43
- if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
44
- ((node_qfm_custom_block *)node->as.opaque)->opening = opening;
45
- return true;
46
- } else {
47
- return false;
48
- }
49
- }
50
-
51
23
  static cmark_chunk *get_qfm_custom_block_info(cmark_node *node) {
52
24
  if (node == NULL) {
53
25
  return NULL;
@@ -81,26 +53,21 @@ static void free_node_qfm_custom_block(cmark_mem *mem, void *ptr) {
81
53
  node_qfm_custom_block *cb = (node_qfm_custom_block *)ptr;
82
54
 
83
55
  cmark_chunk_free(mem, &cb->info);
84
- cmark_strbuf_free(cb->xml_attr_buff);
85
56
  mem->free(cb);
86
57
  }
87
58
 
59
+ /* Now, a custom block can contain another custom block, but this behavior is
60
+ * not a specification. */
88
61
  static int matches(cmark_syntax_extension *self, cmark_parser *parser,
89
62
  unsigned char *input, int len,
90
63
  cmark_node *parent_container) {
91
- int res = 0;
92
-
93
- if (get_qfm_custom_block_opening(parent_container)) {
94
- bufsize_t matched = scan_close_qfm_custom_block_fence(
95
- input, len, cmark_parser_get_first_nonspace(parser));
64
+ int res = 1;
65
+ bufsize_t matched = scan_close_qfm_custom_block_fence(
66
+ input, len, cmark_parser_get_first_nonspace(parser));
96
67
 
97
- if (matched > 0) {
98
- set_qfm_custom_block_opening(parent_container, false);
99
- cmark_parser_advance_offset(parser, (char *)input,
100
- len - cmark_parser_get_offset(parser), 0);
101
- } else {
102
- res = 1;
103
- }
68
+ if (matched > 0) {
69
+ cmark_parser_advance_offset(parser, (char *)input, matched, 0);
70
+ res = 0;
104
71
  }
105
72
 
106
73
  return res;
@@ -120,21 +87,34 @@ static cmark_node *try_opening_qfm_custom_block_block(
120
87
 
121
88
  cmark_node *custom_block_node = cmark_parser_add_child(
122
89
  parser, parent_container, CMARK_NODE_QFM_CUSTOM_BLOCK,
123
- parser->first_nonspace_column);
90
+ parser->first_nonspace + 1);
124
91
  custom_block_node->as.opaque = (node_qfm_custom_block *)parser->mem->calloc(
125
92
  1, sizeof(node_qfm_custom_block));
126
93
 
127
94
  cmark_strbuf *info = parser->mem->calloc(1, sizeof(cmark_strbuf));
128
- cmark_strbuf_init(parser->mem, info, len - matched);
129
- cmark_strbuf_put(info, input + matched, len - matched);
130
- cmark_strbuf_trim(info);
95
+ bufsize_t info_startpos = cmark_parser_get_first_nonspace(parser) + matched;
96
+
97
+ /* Length from after opening custom block fence to before newline character.
98
+ */
99
+ bufsize_t info_len = len - info_startpos;
100
+ if (info_len > 0 && input[len - 1] == '\n') {
101
+ info_len -= 1;
102
+ }
103
+ if (info_len > 0 && input[len - 1] == '\r') {
104
+ info_len -= 1;
105
+ }
131
106
 
132
- set_qfm_custom_block_opening(custom_block_node, true);
107
+ cmark_strbuf_init(parser->mem, info, info_len);
108
+ cmark_strbuf_put(info, input + info_startpos, info_len);
109
+ cmark_strbuf_trim(info);
133
110
  set_qfm_custom_block_info(custom_block_node, (char *)info->ptr);
134
111
 
135
112
  cmark_node_set_syntax_extension(custom_block_node, self);
136
113
  cmark_parser_advance_offset(parser, (char *)input,
137
- len - cmark_parser_get_offset(parser), 0);
114
+ cmark_parser_get_first_nonspace(parser) +
115
+ matched + info_len -
116
+ cmark_parser_get_offset(parser),
117
+ 0);
138
118
 
139
119
  return custom_block_node;
140
120
  }
@@ -155,12 +135,14 @@ static const char *get_type_string(cmark_syntax_extension *self,
155
135
 
156
136
  static int can_contain(cmark_syntax_extension *self, cmark_node *node,
157
137
  cmark_node_type child_type) {
138
+ /* Can contain all block nodes */
158
139
  cmark_node_type node_type = cmark_node_get_type(node);
159
140
 
160
141
  return node_type == CMARK_NODE_QFM_CUSTOM_BLOCK;
161
142
  }
162
143
 
163
144
  static int contains_inlines(cmark_syntax_extension *self, cmark_node *node) {
145
+ /* Can contain all inline nodes */
164
146
  cmark_node_type node_type = cmark_node_get_type(node);
165
147
 
166
148
  return node_type == CMARK_NODE_QFM_CUSTOM_BLOCK;
@@ -210,9 +192,8 @@ static const char *xml_attr(cmark_syntax_extension *self, cmark_node *node) {
210
192
  if (node_type == CMARK_NODE_QFM_CUSTOM_BLOCK) {
211
193
  cmark_chunk *info = get_qfm_custom_block_info(node);
212
194
  cmark_mem *mem = node->content.mem;
213
-
214
195
  cmark_strbuf *xml_attr_buff = mem->calloc(1, sizeof(cmark_strbuf));
215
- ((node_qfm_custom_block *)node->as.opaque)->xml_attr_buff = xml_attr_buff;
196
+
216
197
  cmark_strbuf_init(
217
198
  mem, xml_attr_buff,
218
199
  17 + info->len); // `17` is length of ` data-metadata="` and `"`.
@@ -220,7 +201,7 @@ static const char *xml_attr(cmark_syntax_extension *self, cmark_node *node) {
220
201
  cmark_strbuf_puts(xml_attr_buff, (char *)info->data);
221
202
  cmark_strbuf_putc(xml_attr_buff, '"');
222
203
 
223
- return (char *)xml_attr_buff->ptr;
204
+ return (char *)cmark_strbuf_detach(xml_attr_buff);
224
205
  }
225
206
 
226
207
  return NULL;
@@ -115,25 +115,23 @@ static void rb_parent_removed(VALUE val) {
115
115
  RDATA(val)->dfree = rb_free_c_struct;
116
116
  }
117
117
 
118
- static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark_mem *mem) {
118
+ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions) {
119
119
  int options;
120
- int extensions_len;
121
120
  VALUE rb_ext_name;
122
121
  int i;
123
122
 
124
- Check_Type(rb_options, T_FIXNUM);
123
+ FIXNUM_P(rb_options);
124
+ options = FIX2INT(rb_options);
125
+
125
126
  Check_Type(rb_extensions, T_ARRAY);
126
127
 
127
- options = FIX2INT(rb_options);
128
- extensions_len = RARRAY_LEN(rb_extensions);
128
+ cmark_parser *parser = cmark_parser_new(options);
129
129
 
130
- cmark_parser *parser = cmark_parser_new_with_mem(options, mem);
131
- for (i = 0; i < extensions_len; ++i) {
132
- rb_ext_name = RARRAY_PTR(rb_extensions)[i];
130
+ for (i = 0; i < RARRAY_LEN(rb_extensions); ++i) {
131
+ rb_ext_name = rb_ary_entry(rb_extensions, i);
133
132
 
134
133
  if (!SYMBOL_P(rb_ext_name)) {
135
134
  cmark_parser_free(parser);
136
- cmark_arena_reset();
137
135
  rb_raise(rb_eTypeError, "extension names should be Symbols; got a %"PRIsVALUE"", rb_obj_class(rb_ext_name));
138
136
  }
139
137
 
@@ -142,7 +140,6 @@ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark
142
140
 
143
141
  if (!syntax_extension) {
144
142
  cmark_parser_free(parser);
145
- cmark_arena_reset();
146
143
  rb_raise(rb_eArgError, "extension %s not found", rb_id2name(SYM2ID(rb_ext_name)));
147
144
  }
148
145
 
@@ -157,33 +154,28 @@ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark
157
154
  *
158
155
  */
159
156
  static VALUE rb_markdown_to_html(VALUE self, VALUE rb_text, VALUE rb_options, VALUE rb_extensions) {
160
- char *str, *html;
161
- int len;
157
+ char *html;
162
158
  cmark_parser *parser;
163
159
  cmark_node *doc;
164
- Check_Type(rb_text, T_STRING);
165
- Check_Type(rb_options, T_FIXNUM);
166
160
 
167
- parser = prepare_parser(rb_options, rb_extensions, cmark_get_arena_mem_allocator());
161
+ Check_Type(rb_text, T_STRING);
168
162
 
169
- str = (char *)RSTRING_PTR(rb_text);
170
- len = RSTRING_LEN(rb_text);
163
+ parser = prepare_parser(rb_options, rb_extensions);
171
164
 
172
- cmark_parser_feed(parser, str, len);
165
+ cmark_parser_feed(parser, StringValuePtr(rb_text), RSTRING_LEN(rb_text));
173
166
  doc = cmark_parser_finish(parser);
167
+
174
168
  if (doc == NULL) {
175
- cmark_arena_reset();
169
+ cmark_parser_free(parser);
176
170
  rb_raise(rb_eNodeError, "error parsing document");
177
171
  }
178
172
 
179
- cmark_mem *default_mem = cmark_get_default_mem_allocator();
180
- html = cmark_render_html_with_mem(doc, FIX2INT(rb_options), parser->syntax_extensions, default_mem);
181
- cmark_arena_reset();
173
+ html = cmark_render_html(doc, parser->options, parser->syntax_extensions);
182
174
 
183
- VALUE ruby_html = rb_str_new2(html);
184
- default_mem->free(html);
175
+ cmark_parser_free(parser);
176
+ cmark_node_free(doc);
185
177
 
186
- return ruby_html;
178
+ return rb_utf8_str_new_cstr(html);
187
179
  }
188
180
 
189
181
  /*
@@ -191,33 +183,28 @@ static VALUE rb_markdown_to_html(VALUE self, VALUE rb_text, VALUE rb_options, VA
191
183
  *
192
184
  */
193
185
  static VALUE rb_markdown_to_xml(VALUE self, VALUE rb_text, VALUE rb_options, VALUE rb_extensions) {
194
- char *str, *xml;
195
- int len;
186
+ char *xml;
196
187
  cmark_parser *parser;
197
188
  cmark_node *doc;
198
- Check_Type(rb_text, T_STRING);
199
- Check_Type(rb_options, T_FIXNUM);
200
189
 
201
- parser = prepare_parser(rb_options, rb_extensions, cmark_get_arena_mem_allocator());
190
+ Check_Type(rb_text, T_STRING);
202
191
 
203
- str = (char *)RSTRING_PTR(rb_text);
204
- len = RSTRING_LEN(rb_text);
192
+ parser = prepare_parser(rb_options, rb_extensions);
205
193
 
206
- cmark_parser_feed(parser, str, len);
194
+ cmark_parser_feed(parser, StringValuePtr(rb_text), RSTRING_LEN(rb_text));
207
195
  doc = cmark_parser_finish(parser);
196
+
208
197
  if (doc == NULL) {
209
- cmark_arena_reset();
198
+ cmark_parser_free(parser);
210
199
  rb_raise(rb_eNodeError, "error parsing document");
211
200
  }
212
201
 
213
- cmark_mem *default_mem = cmark_get_default_mem_allocator();
214
- xml = cmark_render_xml_with_mem(doc, FIX2INT(rb_options), default_mem);
215
- cmark_arena_reset();
202
+ xml = cmark_render_xml(doc, parser->options);
216
203
 
217
- VALUE ruby_xml = rb_str_new2(xml);
218
- default_mem->free(xml);
204
+ cmark_parser_free(parser);
205
+ cmark_node_free(doc);
219
206
 
220
- return ruby_xml;
207
+ return rb_utf8_str_new_cstr(xml);
221
208
  }
222
209
 
223
210
  /*
@@ -308,18 +295,17 @@ static VALUE rb_node_new(VALUE self, VALUE type) {
308
295
  static VALUE rb_parse_document(VALUE self, VALUE rb_text, VALUE rb_len,
309
296
  VALUE rb_options, VALUE rb_extensions) {
310
297
  char *text;
311
- int len, options;
298
+ int len;
312
299
  cmark_parser *parser;
313
300
  cmark_node *doc;
314
301
  Check_Type(rb_text, T_STRING);
315
302
  Check_Type(rb_len, T_FIXNUM);
316
303
  Check_Type(rb_options, T_FIXNUM);
317
304
 
318
- parser = prepare_parser(rb_options, rb_extensions, cmark_get_default_mem_allocator());
305
+ parser = prepare_parser(rb_options, rb_extensions);
319
306
 
320
307
  text = (char *)RSTRING_PTR(rb_text);
321
308
  len = FIX2INT(rb_len);
322
- options = FIX2INT(rb_options);
323
309
 
324
310
  cmark_parser_feed(parser, text, len);
325
311
  doc = cmark_parser_finish(parser);
@@ -614,7 +600,6 @@ static VALUE rb_render_html(VALUE self, VALUE rb_options, VALUE rb_extensions) {
614
600
  */
615
601
  static VALUE rb_render_xml(VALUE self, VALUE rb_options) {
616
602
  int options;
617
- int i;
618
603
  cmark_node *node;
619
604
  Check_Type(rb_options, T_FIXNUM);
620
605
 
@@ -1270,6 +1255,7 @@ __attribute__((visibility("default"))) void Init_qiita_marker() {
1270
1255
  rb_define_singleton_method(module, "extensions", rb_extensions, 0);
1271
1256
  rb_eNodeError = rb_define_class_under(module, "NodeError", rb_eStandardError);
1272
1257
  rb_cNode = rb_define_class_under(module, "Node", rb_cObject);
1258
+ rb_undef_alloc_func(rb_cNode);
1273
1259
  rb_define_singleton_method(rb_cNode, "markdown_to_html", rb_markdown_to_html,
1274
1260
  3);
1275
1261
  rb_define_singleton_method(rb_cNode, "markdown_to_xml", rb_markdown_to_xml,