arti_mark 0.0.1.beta0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +75 -0
- data/Rakefile +2 -0
- data/arti_mark.gemspec +20 -0
- data/lib/arti_mark/article_parser.rb +12 -0
- data/lib/arti_mark/base_parser.rb +25 -0
- data/lib/arti_mark/block_image_parser.rb +24 -0
- data/lib/arti_mark/command_lexer.rb +58 -0
- data/lib/arti_mark/common_block_parser.rb +34 -0
- data/lib/arti_mark/context.rb +78 -0
- data/lib/arti_mark/definition_list_parser.rb +23 -0
- data/lib/arti_mark/div_parser.rb +12 -0
- data/lib/arti_mark/head_parser.rb +18 -0
- data/lib/arti_mark/list_parser.rb +27 -0
- data/lib/arti_mark/ordered_list_parser.rb +14 -0
- data/lib/arti_mark/paragraph_parser.rb +28 -0
- data/lib/arti_mark/result_holder.rb +74 -0
- data/lib/arti_mark/section_parser.rb +12 -0
- data/lib/arti_mark/syntax.rb +123 -0
- data/lib/arti_mark/universal_block_parser.rb +10 -0
- data/lib/arti_mark/unordered_list_parser.rb +14 -0
- data/lib/arti_mark/version.rb +3 -0
- data/lib/arti_mark.rb +45 -0
- data/memo.txt +22 -0
- data/spec/arti_mark_spec.rb +457 -0
- data/spec/fixture/test_src_ja.arti +48 -0
- data/spec/nokogiri_test_helper.rb +41 -0
- data/spec/spec_helper.rb +29 -0
- metadata +111 -0
data/.gitignore
ADDED
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,75 @@
|
|
1
|
+
# ArtiMark
|
2
|
+
|
3
|
+
ArtiMark is a simple text markup language. It focuses on creating XHTML files for EPUB books. It is optimized for Japanese text for the present.
|
4
|
+
|
5
|
+
**CAUTION This is very early alpha version, so it's not stable at all. Even the markup syntax will change. **
|
6
|
+
|
7
|
+
I hope it will be partly stable by the end of Feburary, 2013
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Note: This gem is not yet released to rubygems.org.
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'arti_mark'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install arti_mark
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
require 'arti_mark'
|
28
|
+
|
29
|
+
document = ArtiMark::Document.new(:lang => 'ja')
|
30
|
+
document.read(string_or_io)
|
31
|
+
put document.result[0] # outputs 1st page of converted XHTML file
|
32
|
+
|
33
|
+
Source text looks like this.
|
34
|
+
|
35
|
+
art {
|
36
|
+
h1: header 1
|
37
|
+
article comes here.
|
38
|
+
linebreak will produce paragraph.
|
39
|
+
|
40
|
+
blank line will procude div.pgroup.
|
41
|
+
|
42
|
+
d.column {
|
43
|
+
This block will produce div.column.
|
44
|
+
Inline commands like [l(http://github.com/skoji/arti_mark/){this}] and [s.strong{this}] is available.
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
It is converted to XHTML like this, sorrounded with appropriate html,head and body tags.
|
49
|
+
|
50
|
+
<article>
|
51
|
+
<h1>header 1</h1>
|
52
|
+
<div class='pgroup'>
|
53
|
+
<p>article comes here.</p>
|
54
|
+
<p>linebreak will produce paragraph.</p>
|
55
|
+
</div>
|
56
|
+
<div class='pgroup'>
|
57
|
+
<p>blank line will produce</p>
|
58
|
+
</div>
|
59
|
+
<div class='column'>
|
60
|
+
<div class='pgroup'>
|
61
|
+
<p>This block will produce div.column.</p>
|
62
|
+
<p>Inline commands like <a href='http://github.com/skoji/arti_mark/'>this</a> and <span class='strong'>this</span> is available.</p>
|
63
|
+
</div>
|
64
|
+
</div>
|
65
|
+
</article>
|
66
|
+
|
67
|
+
In a near future version, you will be able to add custom commands.
|
68
|
+
|
69
|
+
## Contributing
|
70
|
+
|
71
|
+
1. Fork it
|
72
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
73
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
74
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
75
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/arti_mark.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/arti_mark/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["KOJIMA Satoshi"]
|
6
|
+
gem.email = ["skoji@mac.com"]
|
7
|
+
gem.description = %q{simple and customizable text markup language for EPUB}
|
8
|
+
gem.summary = %q{simple and customizable text markup language for EPUB}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "arti_mark"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = ArtiMark::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency "rspec", "~> 2.11"
|
19
|
+
gem.add_development_dependency "nokogiri", "~> 1.5.6"
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module ArtiMark
|
3
|
+
module BaseParser
|
4
|
+
include CommandLexer
|
5
|
+
|
6
|
+
|
7
|
+
def paragraph(line, syntax, cls_array = [])
|
8
|
+
if line =~/^(「|『|()/ # TODO: should be plaggable
|
9
|
+
cls_array << 'noindent'
|
10
|
+
end
|
11
|
+
"<p#{class_string(cls_array)}>#{line}</p>\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_line(line, syntax, context)
|
15
|
+
line = escape_html line
|
16
|
+
line = replace_inline_commands(line, syntax, context)
|
17
|
+
lexed = lex_line_command(line)
|
18
|
+
if !lexed[:cmd].nil? && syntax.linecommand_handler.respond_to?(lexed[:cmd].to_sym)
|
19
|
+
syntax.linecommand_handler.send(lexed[:cmd], lexed, context)
|
20
|
+
else
|
21
|
+
paragraph(line, syntax)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#require 'singleton'
|
2
|
+
|
3
|
+
module ArtiMark
|
4
|
+
class BlockImageParser
|
5
|
+
include BaseParser, Singleton
|
6
|
+
def accept?(lines)
|
7
|
+
lex_line_command(lines[0])[:cmd] =~ /image/
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(lines, r, syntax)
|
11
|
+
lexed = lex_line_command(lines[0])
|
12
|
+
raise 'HeadParser called for #{lines[0]}' unless lexed[:cmd] =~ /image/
|
13
|
+
lines.shift
|
14
|
+
lexed[:cls] << 'img-wrap' if lexed[:cls].size == 0
|
15
|
+
src = lexed[:params][0].strip
|
16
|
+
alt = lexed[:params][1].strip
|
17
|
+
caption = lexed[:text].strip
|
18
|
+
|
19
|
+
r << "<div#{class_string(lexed[:cls])}><img src='#{src}' alt='#{alt}' />"
|
20
|
+
r << "<p>#{caption}</p>" if !caption.nil? && caption.size > 0
|
21
|
+
r << "</div>\n"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module ArtiMark
|
3
|
+
module CommandLexer
|
4
|
+
def escape_html(string)
|
5
|
+
string.to_s.gsub("&", "&").
|
6
|
+
gsub("<", "<").
|
7
|
+
gsub(">", ">").
|
8
|
+
gsub('"', """)
|
9
|
+
end
|
10
|
+
|
11
|
+
def class_string(cls_array)
|
12
|
+
if cls_array.size == 0
|
13
|
+
''
|
14
|
+
else
|
15
|
+
" class='#{cls_array.join(' ')}'"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def class_array(cls_part)
|
20
|
+
cls_array = []
|
21
|
+
if !cls_part.nil? && cls_part.size > 0
|
22
|
+
cls_array = cls_part[1..-1].split('.')
|
23
|
+
end
|
24
|
+
cls_array
|
25
|
+
end
|
26
|
+
|
27
|
+
def param_array(param_part)
|
28
|
+
r = []
|
29
|
+
if !param_part.nil? && param_part.size > 0
|
30
|
+
r = param_part.split(',')
|
31
|
+
end
|
32
|
+
r
|
33
|
+
end
|
34
|
+
|
35
|
+
def lex_line_command(line)
|
36
|
+
line =~ /^([\w\*;]+?)((?:\.[A-Za-z0-9_\-]+?)*)(?:\((.+?)\))?\s*:(.*?)$/
|
37
|
+
return { :cmd => $1, :cls => class_array($2), :params => param_array($3), :text => $4 }
|
38
|
+
end
|
39
|
+
|
40
|
+
def lex_block_command(line)
|
41
|
+
line =~ /^(\w+?)((?:\.[A-Za-z0-9_\-]+?)*)(?:\((.+?)\))?\s*{\s*$/
|
42
|
+
return { :cmd => $1, :cls => class_array($2), :params => param_array($3)}
|
43
|
+
end
|
44
|
+
|
45
|
+
def replace_inline_commands(line, syntax, context)
|
46
|
+
line.gsub(/\[(\w+?)((?:\.[A-Za-z0-9_\-]+?)*)(?:\((.+?)\))?\s*{(.*?)}\]/) {
|
47
|
+
|matched|
|
48
|
+
lexed = {:cmd => $1, :cls => class_array($2), :params => param_array($3), :text => $4 }
|
49
|
+
if !lexed[:cmd].nil?
|
50
|
+
syntax.inline_handler.send(lexed[:cmd], lexed, context)
|
51
|
+
else
|
52
|
+
matched
|
53
|
+
end
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module ArtiMark
|
5
|
+
module CommonBlockParser
|
6
|
+
include BaseParser
|
7
|
+
def accept?(lines)
|
8
|
+
lex_block_command(lines[0])[:cmd] =~ @command
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(lines, r, syntax)
|
12
|
+
lexed = lex_block_command(lines.shift)
|
13
|
+
throw 'something wrong here #{lines}' unless lexed[:cmd] =~ @command
|
14
|
+
@markup = lexed[:cmd] if @markup.nil?
|
15
|
+
process_block(lines, r, syntax, lexed[:cls], lexed[:params])
|
16
|
+
end
|
17
|
+
|
18
|
+
def process_block(lines, r, syntax, cls_array, params)
|
19
|
+
previous_pgroup , r.enable_pgroup = r.enable_pgroup , false if params.member? 'wo-pgroup'
|
20
|
+
r << "<#{@markup}#{class_string(cls_array)}>\n"
|
21
|
+
while lines.size > 0
|
22
|
+
if lines[0] == '}'
|
23
|
+
lines.shift
|
24
|
+
break
|
25
|
+
else
|
26
|
+
syntax.determine_parser(lines, :get_default => true).call(lines, r, syntax)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
r << "</#{@markup}>\n"
|
30
|
+
r.enable_pgroup = previous_pgroup if !previous_pgroup.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module ArtiMark
|
2
|
+
class Context
|
3
|
+
attr_accessor :title, :head_inserters, :toc, :stylesheets, :enable_pgroup
|
4
|
+
def initialize(param = {})
|
5
|
+
@head_inserters = []
|
6
|
+
@toc = []
|
7
|
+
@lang = param[:lang] || 'en'
|
8
|
+
@title = param[:title] || 'ArtiMark generated document'
|
9
|
+
@stylesheets = param[:stylesheets] || []
|
10
|
+
@stylesheets_alt = param[:stylesheets_alt] || []
|
11
|
+
@enable_pgroup = param[:enable_pgroup] || true
|
12
|
+
@pages = []
|
13
|
+
head_inserter do
|
14
|
+
ret = ""
|
15
|
+
@stylesheets.each { |s|
|
16
|
+
if s.is_a? String
|
17
|
+
ret << "<link rel=\"stylesheet\" type=\"text/css\" href=\"#{s}\" />\n"
|
18
|
+
elsif s.is_a? Array
|
19
|
+
ret << "<link rel=\"stylesheet\" type=\"text/css\" media=\"#{s[1]}\" href=\"#{s[0]}\" />\n"
|
20
|
+
else
|
21
|
+
raise "Can't use #{s} as a stylesheet"
|
22
|
+
end
|
23
|
+
}
|
24
|
+
ret
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def head_inserter(&block)
|
29
|
+
head_inserters << block
|
30
|
+
end
|
31
|
+
|
32
|
+
def start_html(title = nil)
|
33
|
+
@title = title if !title.nil?
|
34
|
+
if @pages.size >0 && !@pages.last.frozen?
|
35
|
+
end_html
|
36
|
+
end
|
37
|
+
page = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
38
|
+
page << "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"#{@lang}\" xml:lang=\"#{@lang}\">\n"
|
39
|
+
page << "<head>\n"
|
40
|
+
page << "<title>#{@title}</title>\n"
|
41
|
+
@head_inserters.each {
|
42
|
+
|f|
|
43
|
+
page << f.call
|
44
|
+
}
|
45
|
+
page << "</head>\n"
|
46
|
+
page << "<body>\n"
|
47
|
+
@pages << page
|
48
|
+
@toc << title
|
49
|
+
end
|
50
|
+
|
51
|
+
def end_html
|
52
|
+
page = @pages.last
|
53
|
+
if !page.frozen?
|
54
|
+
page << "</body>\n"
|
55
|
+
page << "</html>\n"
|
56
|
+
page.freeze
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def toc=(label)
|
61
|
+
@toc[-1] = label if @toc.size > 0
|
62
|
+
end
|
63
|
+
|
64
|
+
def <<(text)
|
65
|
+
if @pages.size == 0 || @pages.last.frozen?
|
66
|
+
start_html
|
67
|
+
end
|
68
|
+
@pages.last << text
|
69
|
+
end
|
70
|
+
|
71
|
+
def result
|
72
|
+
if !@pages.last.frozen?
|
73
|
+
end_html
|
74
|
+
end
|
75
|
+
@pages
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module ArtiMark
|
5
|
+
class DefinitionListParser
|
6
|
+
include ListParser, Singleton
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@cmd = /;/
|
10
|
+
@blockname = 'dl'
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_block(lines, r, syntax)
|
14
|
+
while lines.size > 0
|
15
|
+
lexed = lex_line_command(lines[0])
|
16
|
+
return unless lexed[:cmd] =~ @cmd
|
17
|
+
dt, dd = lexed[:text].split(':', 2).map(&:strip)
|
18
|
+
r << "<dt>#{escape_html dt}</dt><dd>#{escape_html dd}</dd>\n"
|
19
|
+
lines.shift
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#require 'singleton'
|
2
|
+
|
3
|
+
module ArtiMark
|
4
|
+
class HeadParser
|
5
|
+
include BaseParser, Singleton
|
6
|
+
def accept?(lines)
|
7
|
+
lex_line_command(lines[0])[:cmd] =~ /h[1-6]/
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(lines, r, syntax)
|
11
|
+
lexed = lex_line_command(lines[0])
|
12
|
+
raise 'HeadParser called for #{lines[0]}' unless lexed[:cmd] =~ /h([1-6])/
|
13
|
+
lines.shift
|
14
|
+
r << "<#{lexed[:cmd]}#{class_string(lexed[:cls])}>#{escape_html lexed[:text].strip}</#{lexed[:cmd]}>\n"
|
15
|
+
r.toc = lexed[:text].strip if lexed[:params].member? 'in-toc'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module ArtiMark
|
4
|
+
module ListParser
|
5
|
+
include BaseParser
|
6
|
+
|
7
|
+
def accept?(lines)
|
8
|
+
lex_line_command(lines[0])[:cmd] =~ @cmd
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(lines, r, syntax)
|
12
|
+
lexed = lex_line_command(lines[0])
|
13
|
+
r << "<#{@blockname}#{class_string(lexed[:cls])}>\n"
|
14
|
+
process_block(lines, r, syntax)
|
15
|
+
r << "</#{@blockname}>\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
def process_block(lines, r, syntax)
|
19
|
+
while lines.size > 0
|
20
|
+
lexed = lex_line_command(lines[0])
|
21
|
+
return unless lexed[:cmd] =~ @cmd
|
22
|
+
r << "<li>#{escape_html lexed[:text].strip}</li>\n"
|
23
|
+
lines.shift
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module ArtiMark
|
5
|
+
class ParagraphParser
|
6
|
+
include BaseParser, Singleton
|
7
|
+
|
8
|
+
def accept?(lines)
|
9
|
+
lines[0].size == 0
|
10
|
+
end
|
11
|
+
def parse(lines, context, syntax)
|
12
|
+
lines.shift while lines[0].size == 0
|
13
|
+
return unless syntax.determine_parser(lines).nil?
|
14
|
+
context << process_paragraph_group(lines, '', syntax, context)
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_paragraph_group(lines, paragraph, syntax, context)
|
18
|
+
paragraph << "<div class='pgroup'>\n" if context.enable_pgroup
|
19
|
+
while (lines.size > 0 &&
|
20
|
+
lines[0] != '}' && # TODO: is this correct...?
|
21
|
+
syntax.determine_parser(lines).nil?)
|
22
|
+
paragraph << process_line(lines.shift, syntax, context)
|
23
|
+
end
|
24
|
+
paragraph << "</div>\n" if context.enable_pgroup
|
25
|
+
paragraph
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module ArtiMark
|
2
|
+
class Context
|
3
|
+
attr_accessor :title, :head_inserters, :toc
|
4
|
+
def initialize(param = {})
|
5
|
+
@head_inserters = []
|
6
|
+
@toc = []
|
7
|
+
@lang = param[:lang] || 'en'
|
8
|
+
@title = param[:title] || 'ArtiMark generated document'
|
9
|
+
@stylesheets = param[:stylesheets] || []
|
10
|
+
@stylesheets_alt = param[:stylesheets_alt] || []
|
11
|
+
@pages = []
|
12
|
+
head_inserter do
|
13
|
+
ret = ""
|
14
|
+
@stylesheets.each { |s|
|
15
|
+
ret << "<link rel=\"stylesheet\" type=\"text/css\" href=\"#{s}\" />\n"
|
16
|
+
}
|
17
|
+
@stylesheets_alt.each { |s,m|
|
18
|
+
ret << "<link rel=\"stylesheet\" type=\"text/css\" media = \"#{m}\" href=\"#{s}\" />\n"
|
19
|
+
}
|
20
|
+
ret
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def head_inserter(&block)
|
25
|
+
head_inserters << block
|
26
|
+
end
|
27
|
+
|
28
|
+
def start_html(title = nil)
|
29
|
+
@title = title if !title.nil?
|
30
|
+
if @pages.size >0 && !@pages.last.frozen?
|
31
|
+
end_html
|
32
|
+
end
|
33
|
+
page = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
34
|
+
page << "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"#{@lang}\" xml:lang=\"#{@lang}\">\n"
|
35
|
+
page << "<head>\n"
|
36
|
+
page << "<title>#{@title}</title>\n"
|
37
|
+
@head_inserters.each {
|
38
|
+
|f|
|
39
|
+
page << f.call
|
40
|
+
}
|
41
|
+
page << "</head>\n"
|
42
|
+
page << "<body>\n"
|
43
|
+
@pages << page
|
44
|
+
@toc << title
|
45
|
+
end
|
46
|
+
|
47
|
+
def end_html
|
48
|
+
page = @pages.last
|
49
|
+
if !page.frozen?
|
50
|
+
page << "</body>\n"
|
51
|
+
page << "</html>\n"
|
52
|
+
page.freeze
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def toc=(label)
|
57
|
+
@toc[-1] = label if @toc.size > 0
|
58
|
+
end
|
59
|
+
|
60
|
+
def <<(text)
|
61
|
+
if @pages.size == 0 || @pages.last.frozen?
|
62
|
+
start_html
|
63
|
+
end
|
64
|
+
@pages.last << text
|
65
|
+
end
|
66
|
+
|
67
|
+
def result
|
68
|
+
if !@pages.last.frozen?
|
69
|
+
end_html
|
70
|
+
end
|
71
|
+
@pages
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|