elisp2any 0.0.6 → 0.0.7

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.
@@ -1,20 +0,0 @@
1
- require "forwardable"
2
-
3
- module Elisp2any
4
- class Blanklines
5
- def self.scan(scanner)
6
- scanner = StringScanner.new(scanner) unless scanner.respond_to?(:skip)
7
- count = 0
8
- count += 1 while !scanner.eos? && scanner.skip(/ *\n/)
9
- count.zero? and return
10
- new(count)
11
- end
12
-
13
- def initialize(count) # :nodoc:
14
- @count = count
15
- end
16
-
17
- extend Forwardable # :nodoc:
18
- def_delegator :@count, :to_i
19
- end
20
- end
@@ -1,49 +0,0 @@
1
- require "forwardable"
2
- require "elisp2any/paragraph"
3
- require "elisp2any/blanklines"
4
- require "elisp2any/section"
5
-
6
- module Elisp2any
7
- class Code
8
- def self.scan(scanner)
9
- pos = scanner.pos
10
- heading = Elisp2any.scan_top_heading(scanner) or return
11
- unless heading == "Code:"
12
- scanner.pos = pos
13
- return
14
- end
15
- Blanklines.scan(scanner) # optional
16
- paragraphs = []
17
- while (par = Paragraph.scan(scanner))
18
- paragraphs << par
19
- Blanklines.scan(scanner) # optional
20
- end
21
- blocks = [paragraphs]
22
- pos = scanner.pos
23
- while (section = Section.scan(scanner))
24
- if section.heading.level == 1
25
- blocks << section
26
- pos = scanner.pos
27
- else
28
- scanner.pos = pos
29
- break
30
- end
31
- end
32
- new(blocks)
33
- end
34
-
35
- def initialize(blocks)
36
- @blocks = blocks
37
- end
38
-
39
- def sections
40
- @blocks.drop(1)
41
- end
42
-
43
- extend Forwardable # :nodoc:
44
- def_delegator :@blocks, :first, :paragraphs
45
- def_delegator :@blocks, :each
46
-
47
- include Enumerable
48
- end
49
- end
@@ -1,56 +0,0 @@
1
- require "forwardable"
2
- require "elisp2any/expression"
3
- require "elisp2any/blanklines"
4
- require "elisp2any/aside"
5
-
6
- module Elisp2any
7
- class Codeblock # :nodoc:
8
- def self.scan(scanner)
9
- scanner = StringScanner.new(scanner) unless scanner.respond_to?(:skip)
10
- expressions = []
11
- while (exp = Expression.scan(scanner) ||
12
- scanner.scan(/[ \n]+/) ||
13
- Aside.scan(scanner))
14
- expressions << exp
15
- end
16
- expressions.empty? and return
17
- Blanklines.scan(scanner) # optional
18
- new(:TODO, expressions:)
19
- end
20
-
21
- def source
22
- @expressions.sum(+"") do |exp|
23
- case exp
24
- in String
25
- exp
26
- else
27
- exp.source
28
- end
29
- end
30
- end
31
-
32
- # TODO: delete node
33
- # TODO: Remove default empty array
34
- def initialize(node, expressions: []) # :nodoc:
35
- @node = node
36
- @expressions = expressions
37
- end
38
-
39
- def append(source, end_byte) # :nodoc:
40
- @node.append(source, end_byte)
41
- end
42
-
43
- def content
44
- if @node.respond_to?(:content)
45
- @node.content
46
- else
47
- @expressions
48
- end
49
- end
50
-
51
- extend Forwardable # :nodoc:
52
- def_delegator :@expressions, :each
53
-
54
- include Enumerable
55
- end
56
- end
@@ -1,19 +0,0 @@
1
- module Elisp2any
2
- class Comment
3
- attr_reader :colons, :content, :padding
4
-
5
- def self.scan(scanner)
6
- scanner = StringScanner.new(scanner) unless scanner.respond_to?(:skip)
7
- scanner.skip(/(?<colons>;+)(?<padding> *)(?<content>.*)\n?/) or return
8
- new(colons: scanner[:colons].size,
9
- content: scanner[:content],
10
- padding: scanner[:padding])
11
- end
12
-
13
- def initialize(colons:, content:, padding:)
14
- @colons = colons
15
- @content = content
16
- @padding = padding
17
- end
18
- end
19
- end
@@ -1,32 +0,0 @@
1
- require "forwardable"
2
- require "elisp2any/paragraph"
3
- require "elisp2any/blanklines"
4
-
5
- module Elisp2any
6
- class Commentary
7
- def self.scan(scanner)
8
- pos = scanner.pos
9
- heading = Elisp2any.scan_top_heading(scanner) or return
10
- unless heading == "Commentary:"
11
- scanner.pos = pos
12
- return
13
- end
14
- Blanklines.scan(scanner) # optional
15
- paragraphs = []
16
- while (par = Paragraph.scan(scanner))
17
- paragraphs << par
18
- Blanklines.scan(scanner) # optional
19
- end
20
- new(paragraphs)
21
- end
22
-
23
- def initialize(paragraphs)
24
- @paragraphs = paragraphs
25
- end
26
-
27
- extend Forwardable # :nodoc:
28
- def_delegators :@paragraphs, :each, :size
29
-
30
- include Enumerable
31
- end
32
- end
@@ -1,90 +0,0 @@
1
- require "strscan"
2
-
3
- module Elisp2any
4
- class Expression
5
- def self.scan(scanner)
6
- scanner = StringScanner.new(scanner) unless scanner.respond_to?(:skip)
7
- if scanner.skip("(")
8
- exps = []
9
- while (exp = scan(scanner))
10
- exps << exp
11
- spaces = scanner.scan(/[ \n]+/)
12
- exps << spaces if spaces
13
- end
14
- scanner.skip(")") or raise Error, scanner.inspect
15
- new(exps)
16
- elsif scanner.skip("'")
17
- exp = scan(scanner) or raise Error, scanner.inspect
18
- new({ quoted: exp })
19
- elsif scanner.skip("\"")
20
- content = +""
21
- while !scanner.eos? && !scanner.match?("\\") && !scanner.match?('"')
22
- content << scanner.getch
23
- end
24
- scanner.skip('"') or raise Error, scanner.inspect
25
- new(content)
26
- elsif scanner.skip("#'")
27
- exp = scan(scanner) or raise Error, scanner.inspect
28
- new({ function: exp })
29
- else
30
- name = scanner.scan(/[a-z0-9_?.:-]+/) or return
31
- new(name.to_sym)
32
- end
33
- end
34
-
35
- def source
36
- case @content
37
- in { quoted: }
38
- "'#{self.class.source(quoted)}"
39
- in String
40
- @content
41
- in { function: }
42
- "#'#{self.class.source(function)}"
43
- in Array
44
- result = +"("
45
- @content.each { |exp| result << self.class.source(exp) }
46
- "#{result})"
47
- in Symbol
48
- @content.to_s
49
- end
50
- end
51
-
52
- def self.source(arg)
53
- case arg
54
- in Symbol
55
- arg.to_s
56
- in Array
57
- result = +"("
58
- arg.sum { |ele| result << source(ele) }
59
- "#{result})"
60
- in Expression
61
- arg.source
62
- in String
63
- arg
64
- else
65
- raise arg.inspect
66
- end
67
- end
68
-
69
- def deconstruct_keys(*keys)
70
- result = {}
71
- keys => [keys]
72
- keys.each do |key|
73
- case key
74
- in :content
75
- result[:content] = @content
76
- else # nop
77
- end
78
- end
79
- result
80
- end
81
-
82
- def deconstruct
83
- [*@content]
84
- end
85
-
86
- def initialize(content)
87
- @content = content
88
- end
89
- end
90
- end
@@ -1,28 +0,0 @@
1
- require "forwardable"
2
-
3
- module Elisp2any
4
- class FooterLine
5
- def self.scan(scanner)
6
- scanner = StringScanner.new(scanner) unless scanner.respond_to?(:pos)
7
- pos = scanner.pos
8
- heading = Elisp2any.scan_top_heading(scanner) or return
9
- cscanner = StringScanner.new(heading)
10
- unless (filename = Elisp2any.scan_filename(cscanner))
11
- scanner.pos = pos
12
- return
13
- end
14
- unless cscanner.skip(/ ends here\n?/)
15
- scanner.pos = pos
16
- return
17
- end
18
- new(filename)
19
- end
20
-
21
- def initialize(filename)
22
- @filename = filename
23
- end
24
-
25
- extend Forwardable # :nodoc:
26
- def_delegator :@filename, :==
27
- end
28
- end
@@ -1,80 +0,0 @@
1
- require "elisp2any/comment"
2
- require "elisp2any/expression"
3
-
4
- module Elisp2any
5
- class HeaderLine
6
- attr_reader :filename, :description, :variables
7
-
8
- def self.scan(scanner)
9
- scanner = StringScanner.new(scanner) unless scanner.respond_to?(:pos)
10
- pos = scanner.pos
11
- unless (heading = Elisp2any.scan_top_heading(scanner))
12
- scanner.pos = pos
13
- return
14
- end
15
- cscanner = StringScanner.new(heading)
16
- unless (filename = Elisp2any.scan_filename(cscanner))
17
- scanner.pos = pos
18
- return
19
- end
20
- unless cscanner.skip(/ +--- +/)
21
- scanner.pos = pos
22
- return
23
- end
24
- description = +""
25
- variables = nil
26
- until cscanner.eos?
27
- if (variables = scan_variables(cscanner)) # nop
28
- break
29
- else
30
- description << cscanner.getch
31
- end
32
- end
33
- if description.empty?
34
- scanner.pos = pos
35
- return
36
- end
37
- new(filename:, description:, variables:)
38
- end
39
-
40
- def self.scan_variables(scanner)
41
- scanner = StringScanner.new(scanner) unless scanner.respond_to?(:pos)
42
- scanner.skip(/ *-[*]- +/) or return
43
- variables = {}
44
- until scanner.skip(/ +-[*]- */)
45
- if scanner.eos?
46
- raise Error, "unexpected end"
47
- elsif (assign = scan_assignments(scanner))
48
- variables[assign[:variable]] = assign[:expression]
49
- elsif scanner.skip(";")
50
- break
51
- else
52
- raise Error, scanner.inspect
53
- end
54
- end
55
- variables
56
- end
57
- private_class_method :scan_variables
58
-
59
- def self.scan_assignments(scanner)
60
- pos = scanner.pos
61
- variable = Elisp2any.scan_variable(scanner) or return
62
- unless scanner.skip(/ *: */)
63
- scanner.pos = pos
64
- return
65
- end
66
- unless (expression = Expression.scan(scanner))
67
- scanner.pos = pos
68
- return
69
- end
70
- { variable:, expression: }
71
- end
72
- private_class_method :scan_assignments
73
-
74
- def initialize(filename:, description:, variables:)
75
- @filename = filename
76
- @description = description
77
- @variables = variables
78
- end
79
- end
80
- end
@@ -1,68 +0,0 @@
1
- require 'strscan'
2
- require 'forwardable'
3
-
4
- module Elisp2any
5
- class Heading
6
- attr_reader :level
7
- attr_accessor :content
8
-
9
- def self.scan(scanner)
10
- pos = scanner.pos
11
- comment = Comment.scan(scanner) or return
12
- unless comment.colons >= 3
13
- scanner.pos = pos
14
- return
15
- end
16
- new(:TODO, comment.colons - 3,
17
- comment.content # do not scan as text at this point
18
- )
19
- end
20
-
21
- def deconstruct_keys(*keys)
22
- result = {}
23
- keys => [keys]
24
- keys.each do |key|
25
- case key
26
- in :level
27
- result[:level] = @level
28
- in :content
29
- result[:content] = @content
30
- end
31
- end
32
- result
33
- end
34
-
35
- # TODO: delete node. Use kwargs.
36
- def initialize(node, level, content) # :nodoc:
37
- @node = node
38
- @level = level
39
- @content = content
40
- end
41
-
42
- # Returns nil if failed
43
- def name_and_synopsis # :nodoc:
44
- scanner = StringScanner.new(@content)
45
- name = scanner.scan_until(/\.el/) or return
46
- name = name[nil...-3] or return
47
- scanner.skip(/\s+---\s+/) or return
48
- scanner.skip(/(?<synopsis>.+?)(:?\s+-\*- .+? -\*-)?\Z/) or return
49
- synopsis = scanner[:synopsis]
50
- return name, synopsis
51
- end
52
-
53
- def commentary? # :nodoc:
54
- @level == 1 && @content == 'Commentary:'
55
- end
56
-
57
- def code? # :nodoc:
58
- @level == 1 && @content == 'Code:'
59
- end
60
-
61
- def final_name # :nodoc:
62
- @content.match(/\A(?<name>.+?)\.el ends here\Z/)[:name]
63
- end
64
-
65
- extend Forwardable # :nodoc:
66
- def_delegator :@level, :<=>
67
- end
68
- end
@@ -1,23 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title><%= name %></title>
7
- <link rel="stylesheet" href="<%= @css %>">
8
- </head>
9
- <body>
10
- <main>
11
- <h1><%= name %></h1>
12
- <p><%= synopsis %></p>
13
- <h2>Commentary</h2>
14
- <% commentary.each do |paragraph| %>
15
- <p><%= render_paragraph(paragraph) %></p>
16
- <% end %>
17
- <h2>Code</h2>
18
- <% code.each do |block| %>
19
- <%= render_block(block, level: 2) %>
20
- <% end %>
21
- </main>
22
- </body>
23
- </html>
@@ -1,22 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title><%= name %></title>
7
- <link rel="stylesheet" href="<%= @css %>">
8
- </head>
9
- <body>
10
- <main>
11
- <h1><%= name %><small> &mdash; <%= synopsis %></small></h1>
12
- <div style="text-align:right"><%= render(header_line.variables) %></div>
13
- <% commentary.each do |paragraph| %>
14
- <%= render(paragraph) %>
15
- <% end %>
16
- <h2>Code</h2>
17
- <% self.code.each do |block| %>
18
- <%= render(block) %>
19
- <% end %>
20
- </main>
21
- </body>
22
- </html>
@@ -1,149 +0,0 @@
1
- require 'erb'
2
- require 'forwardable'
3
- require 'cgi/util'
4
- require_relative 'inline_code'
5
- require_relative 'heading'
6
- require_relative 'paragraph'
7
- require_relative 'codeblock'
8
-
9
- module Elisp2any
10
- class HTMLRenderer
11
- def initialize(file, css: nil, mode:)
12
- @file = file
13
- @css = css || "https://unpkg.com/mvp.css"
14
- @mode = mode
15
- end
16
-
17
- # Write gradually?
18
- def render(node = nil)
19
- if node
20
- case node
21
- in Paragraph
22
- par = node.sum(+"") { |line| render(line) }
23
- "<p>#{par}</p>"
24
- in Line
25
- begin
26
- node.sum(+"") { |chunk| render(chunk) }
27
- rescue => e
28
- warn node.inspect
29
- raise e
30
- end
31
- in String
32
- h(node)
33
- in [] # huh? nop.
34
- in Section
35
- result = render(node.heading)
36
- node.blocks.each { |blo| result << render(blo) }
37
- node.sections.each { |sec| result << render(sec) }
38
- result
39
- in Heading[level:, content:]
40
- lev = level + 2
41
- "<h#{lev}>#{render(content)}</h#{lev}>"
42
- in Codeblock
43
- "<pre><code>#{h(node.source.chomp)}</code></pre>"
44
- in { code: }
45
- "<code>#{h(code)}</code>"
46
- in Hash
47
- result = node.sum(+"<dl>") do |key, value|
48
- "<dt>#{render(key)}</dt><dd>#{render(value)}</dd>"
49
- end
50
- "#{result}</dl>"
51
- in Expression
52
- "<code>#{h(node.source)}</code>"
53
- in Text
54
- node.sum(+"") { |ele| render(ele) }
55
- else
56
- raise Error, node.inspect
57
- end
58
- else
59
- case @mode
60
- in :old
61
- erb_render('index.html.erb')
62
- in :new
63
- source = ::File.read(::File.join(__dir__, 'html_renderer.erb'))
64
- ERB.new(source).result(binding)
65
- end
66
- end
67
- end
68
-
69
- private
70
-
71
- def render_paragraph(paragraph)
72
- html = ''
73
- paragraph.each do |line|
74
- line.each do |chunk|
75
- case chunk
76
- in InlineCode
77
- html << "<code>#{h(chunk.content)}</code>"
78
- in String
79
- html << h(chunk)
80
- in { code: }
81
- html << "<code>#{h(code)}</code>"
82
- else
83
- raise Error, chunk.inspect
84
- end
85
- end
86
- end
87
- html
88
- end
89
-
90
- # TODO: remove level
91
- def render_block(block, level: nil)
92
- html = ''
93
- case block
94
- when Heading
95
- lev = level
96
- if level
97
- lev = level + block.level - 1
98
- else
99
- lev = block.level
100
- end
101
- name = "h#{lev}"
102
- html << "<#{name}>#{h(block.content)}</#{name}>"
103
- when Paragraph
104
- html << render_paragraph(block)
105
- when Codeblock
106
- html << "<pre><code>#{h(block.content)}</code></pre>"
107
- when [] # huh? nop
108
- when Section
109
- render_block(block.heading)
110
- block.blocks.each do |blo|
111
- render_block(blo)
112
- end
113
- block.sections.each do |sec|
114
- render_block(sec)
115
- end
116
- else
117
- raise Error, block.inspect
118
- end
119
- html
120
- end
121
-
122
- def erb_render(path)
123
- source = ::File.read(::File.join(__dir__, 'html_renderer', path))
124
- ERB.new(source).result(binding)
125
- end
126
-
127
- def h(arg)
128
- case arg
129
- in String
130
- CGI.escape_html(arg)
131
- in Array
132
- arg.map do |ele|
133
- h(ele)
134
- end.join
135
- in Symbol
136
- h(arg.to_s)
137
- in Expression
138
- h(arg.source)
139
- in Integer
140
- h(arg.to_s)
141
- in Aside
142
- h(arg.content)
143
- end
144
- end
145
-
146
- extend Forwardable # :nodoc:
147
- def_delegators :@file, :name, :synopsis, :commentary, :code, :header_line
148
- end
149
- end
@@ -1,10 +0,0 @@
1
- module Elisp2any
2
- # TODO: delete
3
- class InlineCode
4
- attr_reader :content
5
-
6
- def initialize(content)
7
- @content = content
8
- end
9
- end
10
- end