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 ADDED
@@ -0,0 +1,19 @@
1
+ *~
2
+ \#*#
3
+ *.gem
4
+ *.rbc
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in arti_mark.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
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,12 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'singleton'
3
+
4
+ module ArtiMark
5
+ class ArticleParser
6
+ include CommonBlockParser, Singleton
7
+ def initialize
8
+ @command = /(art|article)/
9
+ @markup = 'article'
10
+ end
11
+ end
12
+ 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("&", "&amp;").
6
+ gsub("<", "&lt;").
7
+ gsub(">", "&gt;").
8
+ gsub('"', "&quot;")
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,12 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'singleton'
3
+
4
+ module ArtiMark
5
+ class DivParser
6
+ include CommonBlockParser, Singleton
7
+ def initialize
8
+ @command = /(d|div)/
9
+ @markup = 'div'
10
+ end
11
+ end
12
+ 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,14 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'singleton'
3
+
4
+ module ArtiMark
5
+ class OrderedListParser
6
+ include ListParser, Singleton
7
+
8
+ def initialize
9
+ @cmd = /[0-9]+/
10
+ @blockname = 'ol'
11
+ end
12
+
13
+ end
14
+ 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
@@ -0,0 +1,12 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'singleton'
3
+
4
+ module ArtiMark
5
+ class SectionParser
6
+ include CommonBlockParser, Singleton
7
+ def initialize
8
+ @command = /(sec|section)/
9
+ @markup = 'section'
10
+ end
11
+ end
12
+ end