jay_flavored_markdown 0.1.0

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,391 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2016 Nomura Laboratory
5
+ #
6
+ # This file is NOT part of kramdown and is licensed under the MIT.
7
+ #++
8
+ #
9
+
10
+ require 'kramdown/parser'
11
+ require 'kramdown/converter'
12
+ require 'kramdown/utils'
13
+
14
+ # block 間の明示的な改行は, :blank エレメントとしてパーズされる
15
+ # span 中の改行は, :text エレメント中に残り,かつ,:br が挟まる
16
+ #
17
+ # + :blank は,そのまま反映する
18
+ # + span 中の改行と :br は全て削る
19
+ # + block の後には改行を1つ入れるが,block がネストしている場合は,改行が続くので,1つに集約する
20
+ #
21
+ # block は,通常インデントする必要はない.
22
+ # :root, :blank, :p, :header, :hr, :table, :tr, :td
23
+ #
24
+ # 以下のブロックは,インデントをする
25
+ # :blockquote, :codeblock
26
+ #
27
+ # :ul, :ol,:li, :dl はインデントする
28
+ #
29
+ # dt (term), dd (definition)
30
+ #
31
+ # li は,中のブロック
32
+ # <ul> や <p> のように 実体のない (transparent) ブロックは,何もしない
33
+ # <li> のように,ぶら下げるブロックはインデントしない
34
+
35
+ module Kramdown
36
+ module Converter
37
+
38
+ # Converts a Kramdown::Document to ASCII Plain Text.
39
+ #
40
+ # You can customize this converter by sub-classing it and overriding the +convert_NAME+
41
+ # methods. Each such method takes the following parameters:
42
+ #
43
+ # [+el+] The element of type +NAME+ to be converted.
44
+ #
45
+ # [+indent+] A number representing the current amount of spaces for indent (only used for
46
+ # block-level elements).
47
+ #
48
+ # The return value of such a method has to be a string containing the element +el+ formatted as
49
+ # HTML element.
50
+ class Ascii < Base
51
+
52
+ MAX_COLUMN = 80
53
+
54
+ include ::Kramdown::Utils::Html
55
+ include ::Kramdown::Parser::Html::Constants
56
+
57
+ # The amount of indentation used when nesting HTML tags.
58
+ attr_accessor :indent
59
+
60
+ # Initialize the ASCII converter with the given Kramdown document +doc+.
61
+ def initialize(root, options)
62
+ super
63
+ @indent = 2
64
+ @stack = []
65
+ @xref_table = {}
66
+ ref_visitor = ReferenceVisitor.new
67
+ @root = ref_visitor.traverse(@root)
68
+ @xref_table = ref_visitor.xref_table
69
+ @item_table = ref_visitor.item_table
70
+ @section_table = ref_visitor.section_table
71
+ debug_dump_tree(@root) if $JAY_DEBUG
72
+ @root
73
+ end
74
+
75
+ # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of
76
+ # the element.
77
+ def convert(el, indent = 0)
78
+ send(DISPATCHER[el.type], el, indent)
79
+ end
80
+
81
+ # The mapping of element type to conversion method.
82
+ DISPATCHER = Hash.new {|h,k| h[k] = "convert_#{k}"}
83
+
84
+ ################################################################
85
+ private
86
+
87
+ # Format the given element as span text.
88
+ def format_as_span(name, attr, body)
89
+ return "<SPAN:#{name}>#{body}</SPAN:#{name}>" if $JAY_DEBUG
90
+ return body.to_s.gsub(/\n */, "")
91
+ end
92
+
93
+ # indent を付加した span の列を作る
94
+ # 前提として span 内には block はない
95
+ # span は,行頭にある (block に直接内包される)か,改行を含むものしか indent されないので注意すること.
96
+ def render_span(el, indent)
97
+ el.children.each do |child|
98
+ body << send(DISPATCHER[child.type], child, indent)
99
+ end
100
+ # XXX
101
+ end
102
+
103
+ # Format the given element as block text.
104
+ # current_indent は自身のインデント幅で,ブロック内の
105
+ #
106
+ # render_block: block エレメントをレンダリングする.
107
+ #
108
+ # 前提: span の子供には span しか入っていない (block は,来ない)
109
+ # span の子供が block になるような記述ができるのか不明 (tree をチェックして waring を出すほうがいいかも)
110
+ #
111
+ # 自分(block) について,子供に span があったら,つなげて indent する
112
+ #
113
+ # DISPATCHER を通して作った str は,indent だけのインデントを持つブロックを返すという前提
114
+ # str = send(DISPATCHER[inner_el.type], inner_el, indent)
115
+ def render_block(el, current_indent, add_indent = 0, bullet = nil)
116
+ body = ""
117
+ span = ""
118
+
119
+ orig_indent = current_indent
120
+ current_indent = [(add_indent + current_indent), 0].max
121
+
122
+ el.children.each do |inner_el|
123
+ str = send(DISPATCHER[inner_el.type], inner_el, current_indent)
124
+
125
+ if el.ancestor?(:blockquote)
126
+ body << str # no wrap
127
+ elsif Element.category(inner_el) == :span
128
+ span << str
129
+ else
130
+ # body << wrap_block(span, current_indent, 60) if span.length > 0
131
+ body << span
132
+ body << str
133
+ span = ""
134
+ end
135
+ end
136
+ if span.length > 0
137
+ # body << wrap_block(span, current_indent, 60)
138
+ body << span
139
+ span = ""
140
+ end
141
+
142
+ body = add_bullet_to_block(bullet, body, orig_indent) if bullet
143
+ body = add_indent_to_block(add_indent, body) if add_indent > 0
144
+ # body = remove_indent(body, 2) if bullet && bullet.length > 2 && ancestor?(el, :li)
145
+ body = body.sub(/[\s]*\Z/, "") + "\n"
146
+
147
+ return "<BLOCK:#{el.type}>#{body}</BLOCK:#{el.type}>\n" if $JAY_DEBUG
148
+ return "#{body}"
149
+ end
150
+
151
+ # XXX この中で span に indent を付けるのはおかしい
152
+ #
153
+ def wrap_block(body, indent, max_columns)
154
+ # puts "WRAP_BLOCK: #{body}, #{indent}"
155
+ body = remove_indent(body, indent)
156
+ body = wrap(body, max_columns - indent)
157
+ body = add_indent_to_block(indent, body)
158
+ # puts "WRAPed_BLOCK: #{body}, #{indent}"
159
+ body
160
+ end
161
+
162
+ def remove_indent(body, indent)
163
+ body.gsub(/^#{" "*indent}/, "")
164
+ end
165
+
166
+ def wrap(body, width)
167
+ body = body.gsub(/[\r\n]/, "")
168
+ string, length = "", 0
169
+ body.each_char.map do |c|
170
+ string << c
171
+ length += (c.bytesize == 1 ? 1 : 2)
172
+ if length > width
173
+ string << "\n"
174
+ length = 0
175
+ end
176
+ end
177
+ string
178
+ end
179
+
180
+ ################################################################
181
+ # conver each element
182
+
183
+ def convert_blank(el, indent)
184
+ render_block(el, indent)
185
+ end
186
+
187
+ def convert_text(el, indent)
188
+ format_as_span("text", nil, el.value)
189
+ end
190
+
191
+ def convert_p(el, indent)
192
+ render_block(el, indent)
193
+ end
194
+
195
+ def convert_codeblock(el, indent)
196
+ "-----------------------\n" + el.value.to_s + "-----------------------\n"
197
+ end
198
+
199
+ def convert_blockquote(el, indent)
200
+ "-----------------------\n" + render_block(el, indent, 4) + "-----------------------"
201
+ end
202
+
203
+ def convert_header(el, indent)
204
+ render_block(el, indent, 0, "#{el.value.full_mark}")
205
+ end
206
+
207
+ def convert_hr(el, indent)
208
+ "-" * MAX_COLUMN
209
+ end
210
+
211
+ def convert_ul(el, indent)
212
+ render_block(el, indent)
213
+ end
214
+
215
+ def convert_dl(el, indent)
216
+ format_as_block("dl", nil, render_block(el, indent), indent)
217
+ end
218
+
219
+ def convert_li(el, indent)
220
+ output = ''
221
+
222
+ bullet = el.value ? "(#{el.value.mark})" : "*"
223
+
224
+ output << "<BLOCK:li>" if $JAY_DEBUG
225
+ output << render_block(el, indent, 0, bullet)
226
+ output << "</BLOCK:li>" if $JAY_DEBUG
227
+ output
228
+ end
229
+
230
+ def add_bullet_to_block(bullet, body, indent)
231
+ hang = 0
232
+ bullet_offset = " " * (bullet.size + 1)
233
+ indent_string = " " * indent
234
+ hang_string = " " * hang
235
+
236
+ body = body.sub(/^#{indent_string}/, "#{indent_string}#{bullet} ")
237
+ body = body.gsub(/\n/, "\n" + bullet_offset)
238
+ body = body.gsub(/^#{hang_string}/, "") if hang > 0
239
+ body
240
+ end
241
+
242
+ def add_indent_to_block(indent, body)
243
+ spc = " " * indent
244
+ body = "#{spc}#{body}".gsub(/\n/, "\n" + spc)
245
+ end
246
+
247
+ def convert_dt(el, indent)
248
+ render_block(el, indent)
249
+ end
250
+
251
+ def convert_html_element(el, indent)
252
+ ""
253
+ end
254
+
255
+ def convert_xml_comment(el, indent)
256
+ ""
257
+ end
258
+
259
+ def convert_table(el, indent)
260
+ render_block(el, indent)
261
+ end
262
+
263
+ def convert_td(el, indent)
264
+ render_block(el, indent)
265
+ end
266
+
267
+ def convert_comment(el, indent)
268
+ render_block(el, indent)
269
+ end
270
+
271
+ def convert_br(el, indent)
272
+ "\n" # "\n"
273
+ end
274
+
275
+ def convert_a(el, indent)
276
+ if (c = el.children.first) && c.type == :text && c.value
277
+ "[" + c.value + "]"
278
+ else
279
+ el.attr["href"].to_s
280
+ end
281
+ end
282
+
283
+ def convert_img(el, indent)
284
+ el.attr["href"].to_s
285
+ end
286
+
287
+ def convert_codespan(el, indent)
288
+ "-----------------------\n" + el.value.to_s + "-----------------------"
289
+ end
290
+
291
+ def convert_footnote(el, indent)
292
+ ""
293
+ end
294
+
295
+ def convert_raw(el, indent)
296
+ el.value + (el.options[:category] == :block ? "\n" : '')
297
+ end
298
+
299
+ def convert_em(el, indent)
300
+ format_as_span(el.type, el.attr, render_block(el, indent))
301
+ end
302
+
303
+ # ;gt
304
+ def convert_entity(el, indent)
305
+ format_as_span(el.type, el.attr, render_block(el, indent))
306
+ end
307
+
308
+ def convert_typographic_sym(el, indent)
309
+ {
310
+ :mdash => "---",
311
+ :ndash => "--",
312
+ :hellip => "...",
313
+ :laquo_space => "<<",
314
+ :raquo_space => ">>",
315
+ :laquo => "<< ",
316
+ :raquo => " >>",
317
+ }[el.value]
318
+ end
319
+
320
+ def convert_smart_quote(el, indent)
321
+ {
322
+ :lsquo => "'",
323
+ :rsquo => "'",
324
+ :ldquo => '"',
325
+ :rdquo => '"',
326
+ }[el.value]
327
+ end
328
+
329
+ def convert_math(el, indent)
330
+ format_as_span(el.type, el.attr, render_block(el, indent))
331
+ end
332
+
333
+ def convert_abbreviation(el, indent)
334
+ title = @root.options[:abbrev_defs][el.value]
335
+ attr = @root.options[:abbrev_attr][el.value].dup
336
+ attr['title'] = title unless title.empty?
337
+ format_as_span("abbr", attr, el.value)
338
+ end
339
+
340
+ def convert_root(el, indent)
341
+ render_block(el, indent)
342
+ end
343
+
344
+ alias :convert_ol :convert_ul
345
+ alias :convert_dd :convert_li
346
+ alias :convert_xml_pi :convert_xml_comment
347
+ alias :convert_thead :convert_table
348
+ alias :convert_tbody :convert_table
349
+ alias :convert_tfoot :convert_table
350
+ alias :convert_tr :convert_table
351
+ alias :convert_strong :convert_em
352
+
353
+ ################################################################
354
+
355
+ def convert_ref(el, indent)
356
+ if @xref_table[el.value]
357
+ return "(#{@xref_table[el.value].full_mark})"
358
+ elsif el.value =~ /^(\++|-+)$/
359
+ parent = el.find_first_ancestor(:header) || el.find_first_ancestor(:li)
360
+ table = parent.type == :li ? @item_table : @section_table
361
+ rel_pos = ($1.include?("+") ? 1 : -1) * $1.length
362
+ idx = parent.options[:relative_position] + rel_pos
363
+ ref_el = idx >= 0 ? table[idx] : nil
364
+ return "(#{ref_el.value.full_mark})" if ref_el
365
+ end
366
+ "(???)"
367
+ end
368
+
369
+ def convert_label(el, indent)
370
+ ""
371
+ end
372
+
373
+ def convert_action_item(el, indent)
374
+ "-->(#{el.options[:assignee]})"
375
+ end
376
+
377
+ def convert_issue_link(el, indent)
378
+ el.options[:match]
379
+ end
380
+
381
+ def debug_dump_tree(tree, indent = 0)
382
+ STDERR.print " " * indent
383
+ STDERR.print "#{tree.type}(#{Element.category(tree)}) <<#{tree.value.to_s.gsub("\n", '\n')}>>\n"
384
+ tree.children.each do |c|
385
+ debug_dump_tree(c, indent + 2)
386
+ end
387
+ end
388
+
389
+ end # class Ascii
390
+ end # module Converter
391
+ end # module Kramdown
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JayFlavoredMarkdown
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "jay_flavored_markdown/version"
4
+ require_relative "jay_flavored_markdown/markdown_converter"
5
+ require_relative "jay_flavored_markdown/markdown_to_ascii"
6
+
7
+ module JayFlavoredMarkdown
8
+ class Error < StandardError; end
9
+ # Your code goes here...
10
+ end
metadata ADDED
@@ -0,0 +1,219 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jay_flavored_markdown
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nomura Laboratory
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-09-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kramdown
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: kramdown-parser-gfm
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: html-pipeline
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.14.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.14.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rinku
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
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: gemoji
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sanitize
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rouge
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: activesupport
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 6.1.4
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 6.1.4
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '13.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '13.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: minitest
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '5.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '5.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.7'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.7'
167
+ description: JayFlavoredMarkdown Converter
168
+ email:
169
+ - ''
170
+ executables:
171
+ - jay_flavored_markdown
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".github/workflows/main.yml"
176
+ - ".gitignore"
177
+ - ".rubocop.yml"
178
+ - CHANGELOG.md
179
+ - CODE_OF_CONDUCT.md
180
+ - Gemfile
181
+ - LICENSE.txt
182
+ - README.md
183
+ - Rakefile
184
+ - bin/console
185
+ - bin/setup
186
+ - exe/jay_flavored_markdown
187
+ - jay_flavored_markdown.gemspec
188
+ - lib/jay_flavored_markdown.rb
189
+ - lib/jay_flavored_markdown/markdown_converter.rb
190
+ - lib/jay_flavored_markdown/markdown_to_ascii.rb
191
+ - lib/jay_flavored_markdown/version.rb
192
+ homepage: https://github.com/nomlab/jay_flavored_markdown
193
+ licenses:
194
+ - MIT
195
+ metadata:
196
+ allowed_push_host: https://rubygems.org
197
+ homepage_uri: https://github.com/nomlab/jay_flavored_markdown
198
+ source_code_uri: https://github.com/nomlab/jay_flavored_markdown
199
+ changelog_uri: https://github.com/nomlab/jay_flavored_markdown/blob/master/CHANGELOG.md
200
+ post_install_message:
201
+ rdoc_options: []
202
+ require_paths:
203
+ - lib
204
+ required_ruby_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: 2.4.0
209
+ required_rubygems_version: !ruby/object:Gem::Requirement
210
+ requirements:
211
+ - - ">="
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ requirements: []
215
+ rubygems_version: 3.2.3
216
+ signing_key:
217
+ specification_version: 4
218
+ summary: JayFlavoredMarkdown Converter
219
+ test_files: []