ppz 0.0.0 → 0.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 381349e2fad6a19cbebb0256f972b89d987d362d3266ea06ba50bbdbac4e9798
4
- data.tar.gz: 7aadf7bdbbda2723092ba43459fdad1be56f18927416edb174859a6984645d67
3
+ metadata.gz: 52c9495b0dd9d71eb9f4cd1a6dcaec7805fb10c450dc1d96d664ae7c30d16e0f
4
+ data.tar.gz: 1a2959299c61dcdf554f6923f5c28c713d8667eba7669b6c683b5196081c27b6
5
5
  SHA512:
6
- metadata.gz: 0a099ef949d0b07c73181271255466f13594b6e31da2cd68a11f2dc2ca172aea4ae46a9ffd05a6c40d2e8e1dd69b249ab48dd431464292e64cd293e2d32a2ce6
7
- data.tar.gz: 2d42597300a332d7cd902146b672ac170175fc3158e2b519dd03a394cc5fe18ed1283cbddcbe28b59714cb06e2f10506b559e5d526719b34731a8118c596d2de
6
+ metadata.gz: 4fc7fbcf2fc28272ab0f453477f8f23eff28bc51040b032896fd58ddb2fd6a28be3afba1ada77b956d577db0ab23e60f7fdb8c9ddd030891687f2893595f6323
7
+ data.tar.gz: 7f6013e0106ee614b07b0ba255e4b812cd4f3fb2773dd98fbb71c2098d51a723b3ef7cd47086a96a33db3370448be9397ae32977abfe889113b66056bacdbd57
@@ -0,0 +1,117 @@
1
+ html {
2
+ line-height: 1.5;
3
+ }
4
+ body,
5
+ div,
6
+ p,
7
+ aside {
8
+ box-sizing: border-box;
9
+ }
10
+ body {
11
+ margin: 0;
12
+ padding: 0;
13
+ position: relative;
14
+ }
15
+ aside {
16
+ overflow-y: auto;
17
+ padding: 2rem 1rem;
18
+ position: fixed;
19
+ top: 0;
20
+ left: 0;
21
+ width: 188px;
22
+ height: 100vh;
23
+ }
24
+ aside ul {
25
+ margin: 0 0 0 1rem;
26
+ padding: 0;
27
+ list-style: none;
28
+ }
29
+ aside a {
30
+ width: 100%;
31
+ overflow: hidden;
32
+ text-overflow: ellipsis;
33
+ white-space: nowrap;
34
+ }
35
+ article {
36
+ margin-left: 188px;
37
+ padding: 1px 1rem;
38
+ }
39
+ h1 {
40
+ font-size: 2rem;
41
+ }
42
+ h2 {
43
+ font-size: 1.3rem;
44
+ }
45
+ h3 {
46
+ font-size: 1.1rem;
47
+ opacity: 0.9;
48
+ }
49
+ h1::before,
50
+ h2::before,
51
+ h3::before {
52
+ content: '# ';
53
+ opacity: 0.3;
54
+ font-size: 1rem;
55
+ }
56
+ .comment-container {
57
+ margin: 1rem 0;
58
+ padding: 1rem 1.6rem;
59
+ background: rgba(0,0,0,0.2);
60
+ font-size: 0.9rem;
61
+ border-radius: 4px;
62
+ }
63
+ .comment-item {
64
+ opacity: 0.8;
65
+ }
66
+ .special-block-container {
67
+ background: #141c22;
68
+ overflow: auto;
69
+ border-radius: 4px;
70
+ color: #eee;
71
+ font-family: monospace;
72
+ white-space: pre;
73
+ margin: 1rem 0;
74
+ padding: 1rem;
75
+ counter-reset: line-index;
76
+ }
77
+ .special-block-item::before {
78
+ counter-increment: line-index;
79
+ content: counter(line-index) " | ";
80
+ opacity: 0.3;
81
+ }
82
+ .special-block-item:hover::before {
83
+ opacity: 0.8;
84
+ }
85
+ .special-txt {
86
+ background: rgba(27,31,35,0.05);
87
+ border-radius: 4px;
88
+ font-size: 0.9em;
89
+ padding: 2px 4px;
90
+ }
91
+ .interpage-nav {
92
+ margin-left: 188px;
93
+ list-style: none;
94
+ padding: 0 1rem;
95
+ }
96
+ .interpage-nav .prev {
97
+ float: left;
98
+ }
99
+ .interpage-nav .prev::before {
100
+ content: '上一篇:';
101
+ opacity: 0.6;
102
+ }
103
+ .interpage-nav .next {
104
+ float: right;
105
+ }
106
+ .interpage-nav .next::before {
107
+ content: '下一篇:';
108
+ opacity: 0.6;
109
+ }
110
+ .interpage-nav::after {
111
+ content: '';
112
+ display: block;
113
+ clear: both;
114
+ }
115
+ .folder-nav {
116
+ margin: 2rem 3rem;
117
+ }
@@ -0,0 +1,106 @@
1
+ nav-width = 188px
2
+
3
+ html
4
+ line-height 1.5
5
+ body, div, p, aside
6
+ box-sizing border-box
7
+
8
+ body
9
+ margin 0
10
+ padding 0
11
+ position relative
12
+
13
+ aside
14
+ overflow-y auto
15
+ padding: 2rem 1rem;
16
+
17
+ position fixed
18
+ top 0
19
+ left 0
20
+ width nav-width
21
+ height 100vh
22
+
23
+ ul
24
+ margin 0 0 0 1rem
25
+ padding 0
26
+ list-style none
27
+ a
28
+ width 100%
29
+ overflow hidden
30
+ text-overflow ellipsis
31
+ white-space nowrap
32
+
33
+ article
34
+ margin-left: nav-width
35
+ padding: 1px 1rem
36
+ h1
37
+ font-size 2rem
38
+ h2
39
+ font-size 1.3rem
40
+ h3
41
+ font-size 1.1rem
42
+ opacity 0.9
43
+
44
+ h1, h2, h3
45
+ &::before
46
+ content '# '
47
+ opacity 0.3
48
+ font-size 1rem
49
+
50
+ .comment-container
51
+ margin 1rem 0
52
+ padding 1rem 1.6rem
53
+ background rgba(0, 0, 0, 0.2)
54
+ font-size 0.9rem
55
+ border-radius 4px
56
+ .comment-item
57
+ opacity 0.8
58
+
59
+ .special-block-container
60
+ background #141c22
61
+ overflow auto
62
+ border-radius 4px
63
+ color #eeeeee
64
+
65
+ font-family monospace
66
+ white-space pre
67
+
68
+ margin 1rem 0
69
+ padding 1rem
70
+
71
+ counter-reset line-index
72
+ .special-block-item
73
+ &::before
74
+ counter-increment line-index
75
+ content counter(line-index) " | "
76
+ opacity 0.3
77
+ &:hover::before
78
+ opacity 0.8
79
+
80
+ .special-txt
81
+ background rgba(27, 31, 35, 0.05)
82
+ border-radius 4px
83
+ font-size 0.9em
84
+ padding 2px 4px
85
+
86
+ .interpage-nav
87
+ margin-left nav-width
88
+ list-style none
89
+ padding 0 1rem
90
+ .prev
91
+ float left
92
+ &::before
93
+ content '上一篇:'
94
+ opacity 0.6
95
+ .next
96
+ float right
97
+ &::before
98
+ content '下一篇:'
99
+ opacity 0.6
100
+ &::after
101
+ content ''
102
+ display block
103
+ clear both
104
+
105
+ .folder-nav
106
+ margin 2rem 3rem
data/bin/common.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'pathname'
2
+
3
+ module PPZMain
4
+ CURRENT_PATH = File.dirname __FILE__
5
+ CSS_FILE_PATH = (Pathname CURRENT_PATH) + '../asset/style/ppz.css'
6
+
7
+ class Util
8
+ class << self
9
+ def get_in_and_out
10
+ target_in, target_out = ARGV
11
+
12
+ # 输入文件
13
+ abort '要编译哪那个文件?请告诉我' unless target_in # 检查参数存在
14
+ target_in = PPZ::Func.format_path target_in
15
+ unless File.exist? target_in # 不存在的话,看看加上 .ppz 后是否存在
16
+ target_in += '.ppz'
17
+ abort target_in[0..-5] + ' 不存在' unless File.exist? target_in # 还不存在的话,就说明是写错了
18
+ end
19
+ is_folder = File.directory? target_in
20
+
21
+ # 输出文件
22
+ unless target_out
23
+ # 从输入文件获取文件名
24
+ target_out = ((/(.*).ppz$/.match target_in)?$1:target_in) + '.pp'
25
+ end
26
+ # + 检查上级文件夹是否存在
27
+ upper_dir = ((Pathname target_out) + '..').to_s
28
+ abort upper_dir + ' 目录不存在' unless Dir.exist? upper_dir
29
+ # + 检查文件夹:有则检查里面有没有文件;无则创建文件夹
30
+ target_out = target_out.to_s
31
+ if Dir.exist? target_out
32
+ abort target_out + ' 不是一个空文件夹' unless (Dir.children target_out).size == 0
33
+ else
34
+ Dir.mkdir target_out
35
+ end
36
+ target_out = PPZ::Func.format_path target_out
37
+
38
+ [target_in, target_out, is_folder]
39
+ end
40
+ end
41
+ end
42
+ end
data/bin/doc.rb ADDED
@@ -0,0 +1,17 @@
1
+ target_out = Pathname TARGET_OUT
2
+
3
+ # css
4
+ # 输出文件路径
5
+ output_css_path = target_out + 'index.css'
6
+ # 复制
7
+ FileUtils.cp PPZMain::CSS_FILE_PATH, output_css_path
8
+
9
+ # html
10
+ # 输出文件路径
11
+ output_html_path = target_out + 'index.html'
12
+ # 解析文档
13
+ parser = PPZ::FileDocParser.new TARGET_IN
14
+ # 拼接上 css 文件链接
15
+ output_html = '<link rel="stylesheet" href="./index.css"/>' + parser.get_model.to_html
16
+ # 输出
17
+ PPZ::Func::write_to_file output_html_path.to_s, output_html
data/bin/folder.rb ADDED
@@ -0,0 +1,10 @@
1
+ require_relative '../lib/parser/folder/index'
2
+
3
+ puts '输入文件夹: ' + TARGET_IN
4
+ puts '输出文件夹: ' + TARGET_OUT
5
+ puts
6
+
7
+ FileUtils.cp PPZMain::CSS_FILE_PATH, ((Pathname TARGET_OUT) + 'style.css').to_s
8
+
9
+ model = PPZ::Folder::FolderModel.new TARGET_IN, 0
10
+ model.compile TARGET_OUT
data/bin/ppz CHANGED
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require_relative './ppz-util'
4
- require_relative '../lib/object/parser/doc/file'
5
- require_relative '../lib/func/util'
6
-
7
- file_in, file_out = UtilInMain.get_file_in_and_out
8
-
9
- parser = FileDocParser.new path
10
- model = parser.get_model
11
-
12
- Func::write_to_file file_out, model.to_html
3
+ require_relative '../lib/ppz'
4
+ require_relative './common'
5
+ require 'fileutils'
6
+ require 'pathname'
7
+
8
+ TARGET_IN, TARGET_OUT, IS_FOLDER = PPZMain::Util.get_in_and_out
9
+
10
+ if IS_FOLDER
11
+ require_relative './folder.rb'
12
+ else
13
+ require_relative './doc.rb'
14
+ end
data/lib/func/util.rb ADDED
@@ -0,0 +1,29 @@
1
+ class PPZ::Func
2
+ class << self
3
+ def write_to_file filepath, data
4
+ if File.exist? filepath
5
+ throw '文件已存在'
6
+ end
7
+ file = File.new filepath, mode: 'w:UTF-8'
8
+ file.print data
9
+ file.close
10
+ end
11
+
12
+ # 检查某类有没有某常量
13
+ def has_const? klass, const_name
14
+ klass.constants.include? const_name
15
+ end
16
+ # 检查某实例的类有没有某常量
17
+ def class_has_const? instance, const_name
18
+ has_const? instance.class, const_name
19
+ end
20
+
21
+ def format_path path
22
+ if ['/', '\\'].include? path[-1]
23
+ path[0...-1]
24
+ else
25
+ path
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,42 @@
1
+ class PPZ::AbstractModel
2
+ attr_accessor :left_model, :right_model, :index # 左右兄弟 model
3
+ attr_accessor :father_model
4
+
5
+ def self.from_line line # 静态方法,从“输入行”里实例化一个 model
6
+ return nil unless self::REG_EXP.match(line)
7
+ self.new $1
8
+ end
9
+
10
+ # 加粗、斜体、链接等
11
+ def transform_inline_element str
12
+ str = str + ''
13
+ # 因为加粗、斜体等,会生成 html 代码,为了不使“用户原本输入的 html”和“生成的 html”冲突,因此先把“用户输入的 html 转义
14
+ PPZ::Escape.html_char! str
15
+
16
+ # 变粗等,使用特殊字符比如 *,来标识
17
+ # 但这会使用户想输入 * 时,形成歧义
18
+ # 因此,用户向输入 *(而不是变斜时),可以输入 \*
19
+
20
+ # 所以此流程
21
+ # 先把 * 等特殊字符转义(\* -> 某种形式)
22
+ # 再识别哪些变斜,哪些变粗
23
+ # 再把用户原来想输入的 * 放到字符串里(某种形式 -> *)
24
+
25
+ PPZ::Escape.ppz_char! str # 把用户输入的 \* 转义 => 剩下的 *** 就肯定是 斜体加粗 了
26
+
27
+ # + 斜体和加粗
28
+ str.gsub! /\*\*\*(.+)\*\*\*/, '<b><i>\1</i></b>'
29
+ # + 加粗
30
+ str.gsub! /\*\*(.+)\*\*/, '<b>\1</b>'
31
+ # + 斜体
32
+ str.gsub! /\*(.+)\*/, '<i>\1</i>'
33
+ # + 行内块
34
+ str.gsub! /```([^(```)]+)```/, '<span class="special-txt">\1</span>'
35
+ # + 图片 先图片后链接
36
+ str.gsub! /!\[([^\]]*)\]\(([^\)]+)\)/, '<img title="\1" src="\2" />'
37
+ # + 链接 先图片后链接
38
+ str.gsub! /\[([^\]]+)\]\(([^\)]+)\)/, '<a href="\2" title="\2">\1</a>'
39
+
40
+ PPZ::Escape.transform_to_real! str
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ class PPZ::AbstractWrapperModel < PPZ::AbstractModel
2
+ def initialize
3
+ @children = []
4
+ end
5
+
6
+ # 把 el 加入到 children
7
+ def append el
8
+ el.father_model = self
9
+
10
+ left_model = @children[-1]
11
+ if left_model
12
+ left_model.right_model = el
13
+ el.left_model = el
14
+ el.index = left_model.index + 1
15
+ else
16
+ el.index = 1
17
+ end
18
+ @children.push el
19
+ end
20
+
21
+ def to_html
22
+ @children
23
+ .map { |child| child.to_html }
24
+ .join
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ class PPZ::CommentContainerModel < PPZ::AbstractWrapperModel
2
+ UpperClass = PPZ::AbstractSectionModel
3
+
4
+ def to_html
5
+ "<div class=\"comment-container\">#{super}</div>"
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ class PPZ::CommentItemModel < PPZ::AbstractModel
2
+ ContainerClass = PPZ::CommentContainerModel
3
+ REG_EXP = /^\> (.+)/
4
+
5
+ def initialize content
6
+ @content = transform_inline_element content
7
+ end
8
+
9
+ def to_html
10
+ "<div class=\"comment-item\">#{@content}</div>"
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ class PPZ::Escape
2
+ PpzRule = [
3
+ ['\\\\', '\\backslash', '\\'],
4
+ ['\\*', '\\star;', '*'],
5
+ ['\\`', '\\backquote;', '`']
6
+ ]
7
+ class << self
8
+ def ppz_char! str
9
+ PpzRule.each do |source, escaped|
10
+ str.gsub! source, escaped
11
+ end
12
+ end
13
+
14
+ def transform_to_real! str
15
+ PpzRule.each do |source, escaped, target|
16
+ str.gsub! escaped, target
17
+ end
18
+ str
19
+ end
20
+ end
21
+
22
+ HtmlRule = [
23
+ ['&', '&amp;'],
24
+ ['<', '&lt;'],
25
+ ['>', '&gt;'],
26
+ [' ', '&nbsp;'],
27
+ ['"', '&quot;']
28
+ ]
29
+ def self.html_char! str
30
+ HtmlRule.each do |source, escaped|
31
+ str.gsub! source, escaped
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ class Tag
2
+ def initialize name, content, attr
3
+ @tagName = tagName
4
+ @content = content
5
+ @attr = attr
6
+ end
7
+
8
+ def to_s
9
+ attrStr = ''
10
+ @attr.each do |key, value|
11
+ attrStr << " #{key}='#{value}'"
12
+ end
13
+ "<#{@tagName}#{attrStr}>#{@content}</#{@tagName}>"
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class PPZ::AbstractListItemModel < PPZ::AbstractModel
2
+ attr_reader :level
3
+
4
+ def initialize text, level
5
+ super()
6
+ @text = transform_inline_element text
7
+ @level = level
8
+ end
9
+
10
+ def to_html
11
+ "<li>#{@text}</li>"
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ class PPZ::UnorderedListItemModel < PPZ::AbstractListItemModel
2
+ REG_EXP = /^(\++) (.+)/
3
+ def self.from_line line
4
+ return nil unless REG_EXP.match(line)
5
+ self.new $2, $1.size
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ class PPZ::AbstractListWrapperModel < PPZ::AbstractWrapperModel
2
+ attr_reader :level
3
+
4
+ def initialize level
5
+ super()
6
+ @level = level
7
+ end
8
+
9
+ def to_html
10
+ "<#{self.class::TAG_NAME}>#{super}</#{self.class::TAG_NAME}>"
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ class PPZ::UnorderedListWrapperModel < PPZ::AbstractListWrapperModel
2
+ TAG_NAME = 'ul'
3
+ end
@@ -0,0 +1,17 @@
1
+ class PPZ::PModel < PPZ::AbstractModel
2
+ UpperClass = PPZ::AbstractSectionModel
3
+
4
+ def initialize text
5
+ # 转义行首的加号
6
+ pre = text[0..2]
7
+ text = text[1..-1] if (pre == '\\+ ' or pre == '\\> ')
8
+ # 转义 html
9
+ text = transform_inline_element text
10
+
11
+ @text = text
12
+ end
13
+
14
+ def to_html
15
+ "<p>#{@text}</p>"
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ class PPZ::AbstractSectionModel < PPZ::AbstractWrapperModel
2
+ def append section
3
+ super
4
+ if section.is_a? PPZ::AbstractSectionModel
5
+ section.section_dom_id = "#{section_dom_id}-#{section.level.to_s}.#{section.index.to_s}"
6
+ end
7
+ end
8
+
9
+ def get_nav_html
10
+ @children
11
+ .select { |child| child.is_a? PPZ::AbstractSectionModel }
12
+ .collect { |child| child.get_nav_html }
13
+ .join
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ class PPZ::LeafSectionModel < PPZ::AbstractSectionModel
2
+ attr_accessor :title, :section_dom_id, :level
3
+
4
+ def initialize title, level
5
+ raise TypeError unless title.is_a?(String) && level.is_a?(Integer)
6
+ super() # 不可以省略括号
7
+ @title = transform_inline_element title
8
+ @level = level
9
+ end
10
+
11
+ REG_EXP = /^(\#{1,5}) (.+)/
12
+ def self.from_line line
13
+ return nil unless REG_EXP.match(line)
14
+
15
+ level = {
16
+ 1 => 1, # 一个井号是 一级
17
+ 5 => 3 # 五个井号是 三级
18
+ }[$1.size] || 2 # 其余都是 两级
19
+ PPZ::LeafSectionModel.new $2, level
20
+ end
21
+
22
+ def get_nav_html
23
+ return "<li><a href=\"##{section_dom_id}\">#{@title}</a><ul>#{super}</ul></li>"
24
+ end
25
+
26
+ def to_html
27
+ "<section id=#{@section_dom_id}><h#{@level}>#{@title}</h#{@level}>#{super}</section>"
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ class PPZ::RootSectionModel < PPZ::AbstractSectionModel
2
+ def level
3
+ 0
4
+ end
5
+ def section_dom_id
6
+ 'section'
7
+ end
8
+
9
+ def get_nav_html
10
+ return "<aside><ul>#{super}</ul></aside>"
11
+ end
12
+
13
+ def to_html
14
+ "#{get_nav_html}<article>#{super}</article>"
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ class PPZ::SpecialContainerModel < PPZ::AbstractWrapperModel
2
+ UpperClass = PPZ::AbstractSectionModel
3
+
4
+ REG_EXP = /^```( (.*))?/
5
+ def self.from_line line
6
+ return nil unless REG_EXP.match(line)
7
+ PPZ::SpecialContainerModel.new $2
8
+ end
9
+
10
+ def initialize name
11
+ @name = name
12
+ super()
13
+ end
14
+
15
+ def to_html
16
+ "<div class=\"special-block-container #{@name}\">#{super}</div>"
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ class PPZ::SpecialItemModel < PPZ::AbstractModel
2
+ def initialize line
3
+ @line = line
4
+ end
5
+ def to_html
6
+ "<div class=\"special-block-item\">#{@line}</div>"
7
+ end
8
+ end
@@ -0,0 +1,30 @@
1
+ # 当前行,所处的上下文
2
+ # 比如 一级 section 下面的 ul 下的 第 n 个 ul
3
+
4
+ class PPZ::AbstractContext
5
+ def initialize root
6
+ @stack = [root]
7
+ end
8
+
9
+ # def append # 交给子类实现
10
+
11
+ def pop
12
+ @stack.pop
13
+ end
14
+
15
+ def head
16
+ @stack[-1]
17
+ end
18
+
19
+ def root
20
+ @stack[0]
21
+ end
22
+
23
+ private
24
+ def pop_to klass
25
+ loop do
26
+ break if head.is_a? klass
27
+ pop
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ class PPZ::DocContext < PPZ::AbstractContext
2
+ def append target
3
+ # ContainerClass: 容器类,如果上级不是,就造一个
4
+ if(PPZ::Func::class_has_const? target, :ContainerClass) and (head.class != target.class::ContainerClass)
5
+ append target.class::ContainerClass.new
6
+ end
7
+ # UpperClass: 上级类,如果上级不是,就出栈
8
+ if(PPZ::Func::class_has_const? target, :UpperClass) and (head.class != target.class::UpperClass)
9
+ pop_to target.class::UpperClass
10
+ end
11
+
12
+ head.append target # 加入 model
13
+ @stack.push target if target.is_a? PPZ::AbstractWrapperModel # 加入 stack
14
+ end
15
+ end
@@ -0,0 +1,68 @@
1
+ # 解析一个 .ppz 文档(可以是一个文件、字符串)
2
+
3
+ class PPZ::AbstractDocParser
4
+ def initialize
5
+ @context = PPZ::DocContext.new PPZ::RootSectionModel.new
6
+ end
7
+
8
+ def get_model
9
+ loop do
10
+ line = readline
11
+ break unless line != nil
12
+ handle_line line
13
+ end
14
+ @context.root
15
+ end
16
+
17
+ private
18
+ def handle_line line
19
+ head = @context.head
20
+ if head.is_a? PPZ::SpecialContainerModel # 只要进入 special-block,下面的 line 都算是 special-block 的content
21
+ # special-block
22
+ if /^``` *$/.match line # 除非遇到 ``` (special-block 的结束符)
23
+ # special-block-end
24
+ @context.pop # 遇到,就跳出去
25
+ return # 立刻结束
26
+ elsif /\\``` *$/.match line # 但是有的 ``` (是 special-block 的内容,于是需要转义)
27
+ line = line[1..-1]
28
+ end
29
+ # special-block-item
30
+ target = PPZ::SpecialItemModel.new line
31
+ elsif target = PPZ::LeafSectionModel.from_line(line)
32
+ # section
33
+ loop do
34
+ break if (head.is_a? PPZ::AbstractSectionModel) and (head.level < target.level)
35
+ @context.pop
36
+ head = @context.head
37
+ end
38
+ elsif target = PPZ::UnorderedListItemModel.from_line(line)
39
+ # 列表
40
+ # + 对上级 container 的操作
41
+ # ++ 没有 container -> new
42
+ # ++ 有,等级低 -> new
43
+ # ++ 有,等级高 -> pop 到同等级,如果没有同等级,则 new
44
+ # ++ 有,等级相等 -> 啥也不做
45
+ if !(head.is_a? PPZ::UnorderedListWrapperModel) || head.level < target.level
46
+ @context.append PPZ::UnorderedListWrapperModel.new target.level
47
+ elsif head.level > target.level
48
+ loop do
49
+ @context.pop
50
+ head = @context.head
51
+ break if head.level <= target.level # pop 到同等级
52
+ end
53
+ if head.level < target.level # 如果没有同等级,则 new
54
+ @context.append PPZ::UnorderedListWrapperModel.new target.level
55
+ end
56
+ end
57
+ elsif target = PPZ::CommentItemModel.from_line(line)
58
+ # 注释
59
+ elsif target = PPZ::SpecialContainerModel.from_line(line)
60
+ # 特殊快
61
+ else
62
+ # p
63
+ target = PPZ::PModel.new line
64
+ end
65
+
66
+ @context.append target
67
+ end
68
+ end
@@ -0,0 +1,22 @@
1
+ class PPZ::FileDocParser < PPZ::AbstractDocParser
2
+ def initialize path
3
+ super()
4
+ unless File.exist? path
5
+ throw '文件不存在,可能是路径错了(需要绝对路径):' + path
6
+ end
7
+ @file = File.new path
8
+ @end = false
9
+ end
10
+
11
+ private def readline
12
+ return nil if @end
13
+
14
+ begin
15
+ line = @file.readline
16
+ return line[-1] == '\n'? line[0...-1] : line
17
+ rescue EOFError => err
18
+ @end = true
19
+ return nil
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ class PPZ::StringDocParser < PPZ::AbstractDocParser
2
+ def initialize str
3
+ super()
4
+ @lines = str.split /\n/
5
+ end
6
+
7
+ private def readline
8
+ @lines.shift
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ # 解析一个文件夹里的 .ppz 文件
2
+
3
+ module PPZ::Folder
4
+ class FolderParser
5
+ def initialize
6
+ @context = Context.new
7
+ end
8
+ end
9
+
10
+ require_relative './model/abstract'
11
+ require_relative './model/folder'
12
+ require_relative './model/file/abstract'
13
+ require_relative './model/file/other'
14
+ require_relative './model/file/ppz'
15
+ end
@@ -0,0 +1,27 @@
1
+ module PPZ::Folder
2
+ class AbstractModel
3
+ attr_reader :index, :name
4
+
5
+ def initialize path, level
6
+ throw '文件(夹)的名字得是字符串啊' unless path.is_a? String
7
+ @path = path
8
+ @basename = File.basename path
9
+ @level = level
10
+ end
11
+
12
+ def self.from_path path, level
13
+ level += 1
14
+ if Dir.exist? path
15
+ FolderModel.new path, level
16
+ elsif File.exist? path
17
+ AbstractFileModel.from_path path, level
18
+ else
19
+ throw path + '不存在?'
20
+ end
21
+ end
22
+
23
+ def get_css_path
24
+ ('../' * @level) + 'style.css'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ module PPZ::Folder
2
+ class AbstractFileModel < AbstractModel
3
+ attr_reader :name
4
+ def self.from_path path, level
5
+ if (File.extname path) == '.ppz'
6
+ PPZFileModel.new path, level
7
+ else
8
+ OtherFileModel.new path, level
9
+ end
10
+ end
11
+
12
+ attr_reader :file_ext
13
+
14
+ def initialize path, level
15
+ super
16
+ unless /^((\d+)_)?([^\.]+)(\.[^\.]+)?$/.match @basename
17
+ throw '文件的命名方式不太理解哦:' + path
18
+ end
19
+ @index = $2?($2.to_i):(Float::INFINITY)
20
+ @name = $3
21
+ @file_ext = $4 || ''
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ module PPZ::Folder
2
+ class OtherFileModel < AbstractFileModel
3
+ def _compile dir_out
4
+ FileUtils.cp @path, (dir_out + '/' + @basename)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ module PPZ::Folder
2
+ class PPZFileModel < AbstractFileModel
3
+ attr_accessor :left, :right
4
+
5
+ def _compile dir_out
6
+ parser = PPZ::FileDocParser.new @path
7
+ html_str = %!<link rel="stylesheet" href="#{get_css_path}"/>
8
+ <title>#{@name}</title>#{
9
+ parser.get_model.to_html
10
+ }<ul class="interpage-nav">#{
11
+ (@left ?
12
+ "<li class=\"prev\"><a href=\"#{@left.name}.html\">#{@left.name}</a></li>"
13
+ : "") +
14
+ (@right ?
15
+ "<li class=\"next\"><a href=\"#{@right.name}.html\">#{@right.name}</a></li>"
16
+ : "")
17
+ }</ul>!
18
+ PPZ::Func::write_to_file (dir_out + '/' + @name + '.html'), html_str
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,63 @@
1
+ module PPZ::Folder
2
+ class FolderModel < AbstractModel
3
+ def initialize path, level
4
+ super
5
+ /^((\d+)_)?(.+)/.match @basename
6
+ @index = $2?($2.to_i):(Float::INFINITY)
7
+ @name = $3
8
+
9
+ @children = []
10
+ (Dir.children path, encoding: 'utf-8').each do |child_name|
11
+ @children.push AbstractModel.from_path (path + '/' + child_name), level
12
+ end
13
+ @children.sort! do |a, b|
14
+ a.index <=> b.index
15
+ end
16
+
17
+ left = right = nil
18
+ @children.each do |child|
19
+ next unless child.is_a? PPZFileModel
20
+ if left
21
+ left.right = child
22
+ child.left = left
23
+ end
24
+ left = child
25
+ end
26
+ end
27
+
28
+ def title
29
+ @name
30
+ end
31
+
32
+ def _compile out_dir # compile 是 _compile 的安全版本
33
+ PPZ::Func.write_to_file (out_dir + '/' + @name + '.html'), %!<title>#{title}</title>
34
+ <link rel="stylesheet" href="#{get_css_path}"/><div class="folder-nav"><ul>#{
35
+ @children
36
+ .map do |child|
37
+ child.file_ext == '.ppz' ?
38
+ "<li><a href=\"./#{@name}/#{child.name}.html\">#{child.name}</a></li>"
39
+ : ''
40
+ end
41
+ .join
42
+ }</ul></div>!
43
+
44
+ children_dir = out_dir + '/' + @name
45
+ Dir.mkdir children_dir
46
+ @children.each { |child| child._compile children_dir }
47
+ end
48
+
49
+ def compile out_dir
50
+ unless out_dir.is_a? String
51
+ throw 'out_dir 只能是字符串'
52
+ end
53
+ unless Dir.exist? out_dir
54
+ throw "out_dir #{out_dir} 不存在"
55
+ end
56
+ if ['/', '\\'].include? out_dir[-1]
57
+ _compile out_dir[0...-1]
58
+ else
59
+ _compile out_dir
60
+ end
61
+ end
62
+ end
63
+ end
data/lib/ppz.rb CHANGED
@@ -1 +1,26 @@
1
- p '接口还没写呢~感兴趣的话,可以直接读源码,码量不大'
1
+ module PPZ
2
+ require_relative './func/util'
3
+
4
+ require_relative './model/abstract/model'
5
+ require_relative './model/abstract/wrapper-model'
6
+ require_relative './model/section/abstract'
7
+ require_relative './model/section/leaf'
8
+ require_relative './model/section/root'
9
+ require_relative './model/comment/container'
10
+ require_relative './model/comment/item'
11
+ require_relative './model/common/escape'
12
+ require_relative './model/list/wrapper/abstract'
13
+ require_relative './model/list/wrapper/unordered'
14
+ require_relative './model/list/item/abstract'
15
+ require_relative './model/list/item/unordered'
16
+ require_relative './model/p/index'
17
+ require_relative './model/special-block/container'
18
+ require_relative './model/special-block/item'
19
+
20
+ require_relative './parser/common/context/abstract'
21
+ require_relative './parser/common/context/doc'
22
+ require_relative './parser/doc/abstract'
23
+ require_relative './parser/doc/file'
24
+ require_relative './parser/doc/string'
25
+
26
+ end
metadata CHANGED
@@ -1,23 +1,56 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ppz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - wuse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-02 00:00:00.000000000 Z
11
+ date: 2021-02-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: ''
13
+ description:
14
14
  email: 372301467@qq.com
15
15
  executables:
16
16
  - ppz
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - asset/style/ppz.css
21
+ - asset/style/ppz.styl
22
+ - bin/common.rb
23
+ - bin/doc.rb
24
+ - bin/folder.rb
20
25
  - bin/ppz
26
+ - lib/func/util.rb
27
+ - lib/model/abstract/model.rb
28
+ - lib/model/abstract/wrapper-model.rb
29
+ - lib/model/comment/container.rb
30
+ - lib/model/comment/item.rb
31
+ - lib/model/common/escape.rb
32
+ - lib/model/common/tag.rb
33
+ - lib/model/list/item/abstract.rb
34
+ - lib/model/list/item/unordered.rb
35
+ - lib/model/list/wrapper/abstract.rb
36
+ - lib/model/list/wrapper/unordered.rb
37
+ - lib/model/p/index.rb
38
+ - lib/model/section/abstract.rb
39
+ - lib/model/section/leaf.rb
40
+ - lib/model/section/root.rb
41
+ - lib/model/special-block/container.rb
42
+ - lib/model/special-block/item.rb
43
+ - lib/parser/common/context/abstract.rb
44
+ - lib/parser/common/context/doc.rb
45
+ - lib/parser/doc/abstract.rb
46
+ - lib/parser/doc/file.rb
47
+ - lib/parser/doc/string.rb
48
+ - lib/parser/folder/index.rb
49
+ - lib/parser/folder/model/abstract.rb
50
+ - lib/parser/folder/model/file/abstract.rb
51
+ - lib/parser/folder/model/file/other.rb
52
+ - lib/parser/folder/model/file/ppz.rb
53
+ - lib/parser/folder/model/folder.rb
21
54
  - lib/ppz.rb
22
55
  homepage: https://github.com/daGaiGuanYu/ppz
23
56
  licenses: