nora_mark 0.2beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +188 -0
- data/Rakefile +12 -0
- data/lib/nora_mark/html/abstract_item_writer.rb +14 -0
- data/lib/nora_mark/html/context.rb +119 -0
- data/lib/nora_mark/html/generator.rb +177 -0
- data/lib/nora_mark/html/header_writer.rb +35 -0
- data/lib/nora_mark/html/pages.rb +56 -0
- data/lib/nora_mark/html/paragraph_writer.rb +52 -0
- data/lib/nora_mark/html/tag_writer.rb +110 -0
- data/lib/nora_mark/html/util.rb +12 -0
- data/lib/nora_mark/html/writer_selector.rb +24 -0
- data/lib/nora_mark/parser.kpeg +123 -0
- data/lib/nora_mark/parser.kpeg.rb +3422 -0
- data/lib/nora_mark/parser.rb +31 -0
- data/lib/nora_mark/version.rb +3 -0
- data/lib/nora_mark.rb +46 -0
- data/nora_mark.gemspec +22 -0
- data/spec/created_files/.gitignore +1 -0
- data/spec/fixture/test_src_ja.nora +50 -0
- data/spec/nokogiri_test_helper.rb +41 -0
- data/spec/nora_mark_spec.rb +840 -0
- data/spec/spec_helper.rb +29 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8a2886da05fdf6ceef15ef567fe80634a580b381
|
4
|
+
data.tar.gz: 0a34c663272a064a68d6256f1743008309fcf0ca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a38237dbfa6e03d97caf7b80c00413b968faf1e1efb731b692212dee2c33a3dfedc769108dc4ad2c7ef70349ed32afd5d3d69ba9ee69ef3b712f91862fd52d97
|
7
|
+
data.tar.gz: 3cc67438a689ecfaf3ef11e635ee8d09c9d0b8f8ff50ecfbbd61ccfc7cc973081e1a313d921460fcfaf66bde4216467e2de381b2f41b525fa630427f8e60a22b
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# version 0.2beta1 (NoraMark beta)
|
2
|
+
* Change name to NoraMark
|
3
|
+
|
4
|
+
# version 0.1beta3 (pre NoraMark)
|
5
|
+
|
6
|
+
* Totally rewrite using kpeg.
|
7
|
+
* remove toc feature (for the old toc feature is so poor)
|
8
|
+
* removed custom BlockParser. Instead of the feature, easy and powerful customization will be introduced in NoraText 0.2
|
9
|
+
* markup change: alternate block notation stnorang with 'd{---' has removed
|
10
|
+
* markup change: inline image notation is changed form [img(alt-text){src}] to [img(src, alt)]
|
11
|
+
|
12
|
+
|
13
|
+
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 KOJIMA Satoshi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# NoraMark
|
2
|
+
|
3
|
+
NoraMark is a simple text markup language. It is designed to create XHTML files for EPUB books. Its default mode is for Japanese text.
|
4
|
+
|
5
|
+
**CAUTION This is very early alpha version, so it's not stable at all, even the markup syntax**
|
6
|
+
|
7
|
+
In the next release, the library name will change from NoraMark to NoraMark.
|
8
|
+
In NoraMark release version, the syntax will be more stable.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'nora_mark'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install nora_mark
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
require 'nora_mark'
|
27
|
+
|
28
|
+
document = NoraMark::Document.parse(string_or_io)
|
29
|
+
put document.html[0] # outputs 1st page of converted XHTML file
|
30
|
+
|
31
|
+
An example of markup text (text is in english, but the paragraph style is japanese)
|
32
|
+
|
33
|
+
# line begins with # is a comment.
|
34
|
+
# you don't need to indent noramark text.
|
35
|
+
|
36
|
+
lang: ja
|
37
|
+
title: test title
|
38
|
+
stylesheets: css/normalize.css, css/main.css
|
39
|
+
|
40
|
+
art {
|
41
|
+
h1: header 1
|
42
|
+
article comes here.
|
43
|
+
linebreak will produce paragraph.
|
44
|
+
|
45
|
+
blank line will procude div.pgroup.
|
46
|
+
|
47
|
+
d.column {
|
48
|
+
This block will produce div.column.
|
49
|
+
Inline commands like [link(http://github.com/skoji/nora_mark/){this}] and [s.strong{this}] is available.
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
The converted XHTML file
|
54
|
+
|
55
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
56
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
57
|
+
<head>
|
58
|
+
<title> test title</title>
|
59
|
+
<link rel="stylesheet" type="text/css" href="css/normalize.css" />
|
60
|
+
<link rel="stylesheet" type="text/css" href="css/main.css" />
|
61
|
+
</head>
|
62
|
+
<body>
|
63
|
+
<article>
|
64
|
+
<h1>header 1</h1>
|
65
|
+
<div class='pgroup'>
|
66
|
+
<p>article comes here.</p>
|
67
|
+
<p>linebreak will produce paragraph.</p>
|
68
|
+
</div>
|
69
|
+
<div class='pgroup'>
|
70
|
+
<p>blank line will produce</p>
|
71
|
+
</div>
|
72
|
+
<div class='column'>
|
73
|
+
<div class='pgroup'>
|
74
|
+
<p>This block will produce div.column.</p>
|
75
|
+
<p>Inline commands like <a href='http://github.com/skoji/nora_mark/'>this</a> and <span class='strong'>this</span> is available.</p>
|
76
|
+
</div>
|
77
|
+
</div>
|
78
|
+
</article>
|
79
|
+
</body>
|
80
|
+
</html>
|
81
|
+
|
82
|
+
Another example of markup text in non-japanese (paragraph style is default)
|
83
|
+
|
84
|
+
# line begins with # is a comment.
|
85
|
+
# you don't need to indent noramark text.
|
86
|
+
|
87
|
+
lang: en
|
88
|
+
title: test title
|
89
|
+
stylesheets: css/normalize.css, css/main.css
|
90
|
+
|
91
|
+
art {
|
92
|
+
h1: header 1
|
93
|
+
article comes here.
|
94
|
+
linebreak will produce br.
|
95
|
+
|
96
|
+
blank line will procude paragraph.
|
97
|
+
|
98
|
+
d.column {
|
99
|
+
This block will produce div.column.
|
100
|
+
Inline commands like [link(http://github.com/skoji/nora_mark/){this}] and [s.strong{this}] is available.
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
The converted XHTML file
|
105
|
+
|
106
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
107
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
108
|
+
<head>
|
109
|
+
<title> test title</title>
|
110
|
+
<link rel="stylesheet" type="text/css" href="css/normalize.css" />
|
111
|
+
<link rel="stylesheet" type="text/css" href="css/main.css" />
|
112
|
+
</head>
|
113
|
+
<body>
|
114
|
+
<article>
|
115
|
+
<h1>header 1</h1>
|
116
|
+
<p>article comes here.<br />linebreak will produce paragraph.</p>
|
117
|
+
<p>blank line will produce paragraph</p>
|
118
|
+
<div class='column'>
|
119
|
+
<p>This block will produce div.column.<br />Inline commands like <a href='http://github.com/skoji/nora_mark/'>this</a> and <span class='strong'>this</span> is available.</p>
|
120
|
+
</div>
|
121
|
+
</article>
|
122
|
+
</body>
|
123
|
+
</html>
|
124
|
+
|
125
|
+
|
126
|
+
Another example of markup text
|
127
|
+
|
128
|
+
# Markdown-ish heading will creates section
|
129
|
+
|
130
|
+
lang: ja
|
131
|
+
title: test title
|
132
|
+
stylesheets: css/normalize.css, css/main.css
|
133
|
+
|
134
|
+
=: this is the first heading
|
135
|
+
|
136
|
+
This line is in a section.
|
137
|
+
This line is in a section.
|
138
|
+
|
139
|
+
==: this is the second heading
|
140
|
+
|
141
|
+
This section is nested.
|
142
|
+
|
143
|
+
=: this is the third heading
|
144
|
+
|
145
|
+
will terminate lower level section
|
146
|
+
|
147
|
+
The converted XHTML file
|
148
|
+
|
149
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
150
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
151
|
+
<head>
|
152
|
+
<title>test title</title>
|
153
|
+
<link rel="stylesheet" type="text/css" href="css/normalize.css" />
|
154
|
+
<link rel="stylesheet" type="text/css" href="css/main.css" />
|
155
|
+
</head>
|
156
|
+
<body>
|
157
|
+
<section><h1>this is the first heading</h1>
|
158
|
+
<div class='pgroup'><p>This line is in a section.</p>
|
159
|
+
<p>This line is in a section.</p>
|
160
|
+
</div>
|
161
|
+
<section><h2>this is the second heading</h2>
|
162
|
+
<div class='pgroup'><p>This section is nested.</p>
|
163
|
+
</div>
|
164
|
+
</section>
|
165
|
+
</section>
|
166
|
+
<section><h1>this is the third heading</h1>
|
167
|
+
<div class='pgroup'><p>will terminate lower level section</p>
|
168
|
+
</div>
|
169
|
+
</section>
|
170
|
+
</body>
|
171
|
+
</html>
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
In a near future version, you will be able to add custom commands.
|
181
|
+
|
182
|
+
## Contributing
|
183
|
+
|
184
|
+
1. Fork it
|
185
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
186
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
187
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
188
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
rule(/\.kpeg\.rb/ => proc {|task_name| task_name.sub(/kpeg\.rb$/, 'kpeg')}) do
|
5
|
+
|t|
|
6
|
+
system "kpeg -f #{t.prerequisites[0]}"
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "run rspec"
|
10
|
+
task :test => ["lib/nora_mark/parser.kpeg.rb"] do
|
11
|
+
system 'rspec'
|
12
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module NoraMark
|
2
|
+
module Html
|
3
|
+
class Context
|
4
|
+
attr_accessor :title, :head_inserters, :toc, :lang, :stylesheets, :enable_pgroup
|
5
|
+
def initialize(param = {})
|
6
|
+
@head_inserters = []
|
7
|
+
@toc = []
|
8
|
+
@lang = param[:lang] || 'en'
|
9
|
+
@title = param[:title] || 'NoraMark generated document'
|
10
|
+
@stylesheets = param[:stylesheets] || []
|
11
|
+
@stylesheets_alt = param[:stylesheets_alt] || []
|
12
|
+
@enable_pgroup = param[:enable_pgroup] || true
|
13
|
+
self.paragraph_style= param[:paragraph_style]
|
14
|
+
@pages = Pages.new(param[:filename_base], param[:sequence_format])
|
15
|
+
@block_delimiter_stack = []
|
16
|
+
head_inserter do
|
17
|
+
ret = ""
|
18
|
+
@stylesheets.each { |s|
|
19
|
+
if s.is_a? String
|
20
|
+
ret << "<link rel=\"stylesheet\" type=\"text/css\" href=\"#{s}\" />\n"
|
21
|
+
elsif s.is_a? Array
|
22
|
+
ret << "<link rel=\"stylesheet\" type=\"text/css\" media=\"#{s[1]}\" href=\"#{s[0]}\" />\n"
|
23
|
+
else
|
24
|
+
raise "Can't use #{s} as a stylesheet"
|
25
|
+
end
|
26
|
+
}
|
27
|
+
ret
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def created_files
|
32
|
+
@pages.created_files
|
33
|
+
end
|
34
|
+
|
35
|
+
def chop_last_space
|
36
|
+
@pages.last.sub!(/[[:space:]]+$/, '')
|
37
|
+
end
|
38
|
+
|
39
|
+
def paragraph_style=(style)
|
40
|
+
return if style.nil?
|
41
|
+
raise "paragrapy_style accepts only :default or :use_paragraph_group but is #{style}" if style != :default && style != :use_paragraph_group
|
42
|
+
@paragraph_style = style
|
43
|
+
end
|
44
|
+
|
45
|
+
def paragraph_style
|
46
|
+
if @paragraph_style
|
47
|
+
@paragraph_style
|
48
|
+
elsif @lang.split('-')[0] == 'ja'
|
49
|
+
:use_paragraph_group
|
50
|
+
else
|
51
|
+
:default
|
52
|
+
end
|
53
|
+
end
|
54
|
+
def head_inserter(&block)
|
55
|
+
head_inserters << block
|
56
|
+
end
|
57
|
+
|
58
|
+
def start_html(title = nil)
|
59
|
+
@title = title if !title.nil?
|
60
|
+
if @pages.size >0 && !@pages.last.frozen?
|
61
|
+
end_html
|
62
|
+
end
|
63
|
+
page = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
64
|
+
page << "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"#{@lang}\" xml:lang=\"#{@lang}\">\n"
|
65
|
+
page << "<head>\n"
|
66
|
+
page << "<title>#{@title}</title>\n"
|
67
|
+
@head_inserters.each {
|
68
|
+
|f|
|
69
|
+
page << f.call
|
70
|
+
}
|
71
|
+
page << "</head>\n"
|
72
|
+
page << "<body>\n"
|
73
|
+
@pages << page
|
74
|
+
@toc << title
|
75
|
+
end
|
76
|
+
|
77
|
+
def end_html
|
78
|
+
page = @pages.last
|
79
|
+
if !page.frozen?
|
80
|
+
page << "</body>\n"
|
81
|
+
page << "</html>\n"
|
82
|
+
page.freeze
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def enter_block(lexed)
|
87
|
+
@block_delimiter_stack.push(lexed[:delimiter])
|
88
|
+
end
|
89
|
+
|
90
|
+
def exit_block(lexed)
|
91
|
+
@block_delimiter_stack.pop
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def block_close?(line)
|
96
|
+
line == (@block_delimiter_stack.last || '') + '}'
|
97
|
+
end
|
98
|
+
|
99
|
+
def toc=(label)
|
100
|
+
@toc[-1] = label if @toc.size > 0
|
101
|
+
end
|
102
|
+
|
103
|
+
def <<(text)
|
104
|
+
if @pages.size == 0 || @pages.last.frozen?
|
105
|
+
start_html
|
106
|
+
end
|
107
|
+
@pages.last << text
|
108
|
+
end
|
109
|
+
|
110
|
+
def result
|
111
|
+
if !@pages.last.frozen?
|
112
|
+
end_html
|
113
|
+
end
|
114
|
+
|
115
|
+
@pages
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'nora_mark/html/util'
|
3
|
+
require 'nora_mark/html/pages'
|
4
|
+
require 'nora_mark/html/context'
|
5
|
+
require 'nora_mark/html/tag_writer'
|
6
|
+
require 'nora_mark/html/header_writer'
|
7
|
+
require 'nora_mark/html/paragraph_writer'
|
8
|
+
require 'nora_mark/html/writer_selector'
|
9
|
+
require 'nora_mark/html/abstract_item_writer'
|
10
|
+
module NoraMark
|
11
|
+
module Html
|
12
|
+
class Generator
|
13
|
+
include Util
|
14
|
+
attr_reader :context
|
15
|
+
def initialize(param = {})
|
16
|
+
@context = Context.new(param)
|
17
|
+
article_writer = TagWriter.create('article', self)
|
18
|
+
section_writer = TagWriter.create('section', self)
|
19
|
+
link_writer = TagWriter.create('a', self, trailer: '',
|
20
|
+
item_preprocessor: proc do |item|
|
21
|
+
(item[:attrs] ||= {}).merge!({:href => [ item[:args][0] ]})
|
22
|
+
item
|
23
|
+
end)
|
24
|
+
|
25
|
+
header_writer = HeaderWriter.new self
|
26
|
+
paragraph_writer = ParagraphWriter.new self
|
27
|
+
abstract_item_writer = AbstractItemWriter.new self
|
28
|
+
@writers = {
|
29
|
+
:page => abstract_item_writer,
|
30
|
+
:headers => abstract_item_writer,
|
31
|
+
:paragraph => paragraph_writer,
|
32
|
+
:paragraph_group => paragraph_writer,
|
33
|
+
:block =>
|
34
|
+
WriterSelector.new(self,
|
35
|
+
{
|
36
|
+
'd' => TagWriter.create('div', self),
|
37
|
+
'art' => article_writer,
|
38
|
+
'arti' => article_writer,
|
39
|
+
'article' => article_writer,
|
40
|
+
'sec' => section_writer,
|
41
|
+
'sect' => section_writer,
|
42
|
+
'section' => section_writer,
|
43
|
+
}),
|
44
|
+
:line_command =>
|
45
|
+
WriterSelector.new(self,
|
46
|
+
{
|
47
|
+
'image' =>
|
48
|
+
TagWriter.create('div', self,
|
49
|
+
item_preprocessor: proc do |item|
|
50
|
+
add_class_if_empty item, 'img-wrap'
|
51
|
+
item
|
52
|
+
end,
|
53
|
+
write_body_preprocessor: proc do |item|
|
54
|
+
src = item[:args][0].strip
|
55
|
+
alt = (item[:args][1] || '').strip
|
56
|
+
caption_before = item[:named_args][:caption_before]
|
57
|
+
if caption_before && children_not_empty(item)
|
58
|
+
output "<p>"; write_children item; output "</p>"
|
59
|
+
end
|
60
|
+
output "<img src='#{src}' alt='#{escape_html alt}' />"
|
61
|
+
if !caption_before && children_not_empty(item)
|
62
|
+
output "<p>"; write_children item; output "</p>"
|
63
|
+
end
|
64
|
+
:done
|
65
|
+
end
|
66
|
+
),
|
67
|
+
|
68
|
+
}),
|
69
|
+
:inline =>
|
70
|
+
WriterSelector.new(self,
|
71
|
+
{
|
72
|
+
'link' => link_writer,
|
73
|
+
'l' => link_writer,
|
74
|
+
's' => TagWriter.create('span', self),
|
75
|
+
'img' =>
|
76
|
+
TagWriter.create('img', self,
|
77
|
+
item_preprocessor: proc do |item|
|
78
|
+
item[:no_body] = true #TODO : it is not just an item's attribute, 'img_inline' has no body. maybe should specify in parser.{rb|kpeg}
|
79
|
+
(item[:attrs] ||= {}).merge!({:src => [item[:args][0] ]})
|
80
|
+
item[:attrs].merge!({:alt => [ escape_html(item[:args][1].strip)]}) if (item[:args].size > 1 && item[:args][1].size > 0)
|
81
|
+
item
|
82
|
+
end) ,
|
83
|
+
'tcy' =>
|
84
|
+
TagWriter.create('span', self,
|
85
|
+
item_preprocessor: proc do |item|
|
86
|
+
add_class item, 'tcy'
|
87
|
+
item
|
88
|
+
end),
|
89
|
+
'ruby' =>
|
90
|
+
TagWriter.create('ruby', self,
|
91
|
+
write_body_preprocessor: proc do |item|
|
92
|
+
write_children item
|
93
|
+
output "<rp>(</rp><rt>#{escape_html item[:args][0].strip}</rt><rp>)</rp>"
|
94
|
+
:done
|
95
|
+
end),
|
96
|
+
|
97
|
+
},
|
98
|
+
trailer_default:''
|
99
|
+
),
|
100
|
+
:ol => TagWriter.create('ol', self),
|
101
|
+
:ul => TagWriter.create('ul', self),
|
102
|
+
:li => TagWriter.create('li', self),
|
103
|
+
:dl => TagWriter.create('dl', self),
|
104
|
+
:dtdd =>
|
105
|
+
TagWriter.create('', self, chop_last_space: true, item_preprocessor: proc do |item| item[:no_tag] = true; item end,
|
106
|
+
write_body_preprocessor: proc do |item|
|
107
|
+
output "<dt>"; write_array item[:args][0]; output "</dt>"
|
108
|
+
output "<dd>"; write_array item[:args][1]; output "</dd>"
|
109
|
+
:done
|
110
|
+
end),
|
111
|
+
:newpage =>
|
112
|
+
TagWriter.create('div', self,
|
113
|
+
item_preprocessor: proc do |item|
|
114
|
+
item[:no_tag] = true
|
115
|
+
item
|
116
|
+
end,
|
117
|
+
write_body_preprocessor: proc do |item|
|
118
|
+
title = nil
|
119
|
+
if item[:args].size > 0 && item[:args][0].size > 0
|
120
|
+
title = escape_html item[:args].first
|
121
|
+
end
|
122
|
+
@context.title = title unless title.nil?
|
123
|
+
@context.end_html
|
124
|
+
:done
|
125
|
+
end
|
126
|
+
),
|
127
|
+
#headed-section
|
128
|
+
:h_section =>
|
129
|
+
TagWriter.create('section', self, write_body_preprocessor: proc do |item|
|
130
|
+
output "<h#{item[:level]}>#{item[:heading].strip}</h#{item[:level]}>\n"
|
131
|
+
:continue
|
132
|
+
end),
|
133
|
+
# headers
|
134
|
+
:stylesheets => header_writer,
|
135
|
+
:title => header_writer,
|
136
|
+
:lang => header_writer,
|
137
|
+
:paragraph_style => header_writer,
|
138
|
+
# pre-formatted
|
139
|
+
:preformatted =>
|
140
|
+
TagWriter.create('pre', self,write_body_preprocessor: proc do |item|
|
141
|
+
output "<code>" if item[:name] == 'precode'
|
142
|
+
output item[:children].join "\n"
|
143
|
+
output "</code>" if item[:name] == 'precode'
|
144
|
+
:done
|
145
|
+
end),
|
146
|
+
#break
|
147
|
+
:br =>
|
148
|
+
TagWriter.create('br', self, item_preprocessor: proc do |item|
|
149
|
+
item[:no_body] = true
|
150
|
+
item
|
151
|
+
end),
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
def convert(parsed_result)
|
156
|
+
parsed_result.each {
|
157
|
+
|item|
|
158
|
+
to_html(item)
|
159
|
+
}
|
160
|
+
@context.result
|
161
|
+
end
|
162
|
+
def to_html(item)
|
163
|
+
if item.is_a? String
|
164
|
+
@context << escape_html(item)
|
165
|
+
else
|
166
|
+
writer = @writers[item[:type]]
|
167
|
+
if writer.nil?
|
168
|
+
warn "can't find html generator for \"#{item}\""
|
169
|
+
@context << escape_html(item[:raw_text])
|
170
|
+
else
|
171
|
+
writer.write(item)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module NoraMark
|
2
|
+
module Html
|
3
|
+
class HeaderWriter
|
4
|
+
include Util
|
5
|
+
def initialize(generator)
|
6
|
+
@generator = generator
|
7
|
+
@context = generator.context
|
8
|
+
@writers = {
|
9
|
+
:stylesheets => proc do |item|
|
10
|
+
@context.stylesheets.concat( item[:stylesheets].map do
|
11
|
+
|s|
|
12
|
+
if s =~ /^(.+?\.css):\((.+?)\)$/
|
13
|
+
[$1, $2]
|
14
|
+
else
|
15
|
+
s
|
16
|
+
end
|
17
|
+
end)
|
18
|
+
end,
|
19
|
+
:title => proc do |item|
|
20
|
+
@context.title = escape_html item[:title].strip
|
21
|
+
end,
|
22
|
+
:lang => proc do |item|
|
23
|
+
@context.lang = escape_html item[:lang].strip
|
24
|
+
end,
|
25
|
+
:paragraph_style => proc do |item|
|
26
|
+
@context.paragraph_style = item[:paragraph_style].strip
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
def write(item)
|
31
|
+
@writers[item[:type]].call item
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
module NoraMark
|
3
|
+
module Html
|
4
|
+
class Context
|
5
|
+
class Pages
|
6
|
+
attr_reader :created_files
|
7
|
+
def initialize(filename_base = nil, sequence_format='%05d')
|
8
|
+
@filename_base = filename_base || "noramark_#{SecureRandom.uuid}"
|
9
|
+
@sequence_format = sequence_format || '%05d'
|
10
|
+
@result = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def last
|
14
|
+
@result.last[:content]
|
15
|
+
end
|
16
|
+
|
17
|
+
def size
|
18
|
+
@result.size
|
19
|
+
end
|
20
|
+
|
21
|
+
def <<(page)
|
22
|
+
seq = @result.size + 1
|
23
|
+
@result << { content: page, filename: "#{@filename_base}_#{@sequence_format%(seq)}.xhtml" }
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](num)
|
27
|
+
page = @result[num]
|
28
|
+
page.nil? ? nil : page[:content]
|
29
|
+
end
|
30
|
+
|
31
|
+
def pages
|
32
|
+
@result
|
33
|
+
end
|
34
|
+
|
35
|
+
def write_as_files(directory: nil)
|
36
|
+
dir = directory || Dir.pwd
|
37
|
+
Dir.chdir(dir) do
|
38
|
+
@result.each do
|
39
|
+
|page|
|
40
|
+
File.open(page[:filename], 'w+') do
|
41
|
+
|file|
|
42
|
+
file << page[:content]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
def write_as_single_file(filename)
|
48
|
+
File.open(filename, 'w+') {
|
49
|
+
|file|
|
50
|
+
file << @result[0][:content]
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|