arti_mark 0.0.1.beta4 → 0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: abd2001b34dc838a27ba1c9f1e188fde512e2468
4
- data.tar.gz: 3d683b3d4c7e09efd3414ab6c62503d09d804503
3
+ metadata.gz: 62679290ba21c0b408d4fff89c820958fa789ff6
4
+ data.tar.gz: a16462606130c072726ce1d86bb0e677ce267ed3
5
5
  SHA512:
6
- metadata.gz: a01c7e24864ca6fa710ca1b22e13c3c8e00f2ab13d2aa0036aa268be4501d63c82266d5a7192dc7420750816495417b46ca9d8090037c817711558037a592d14
7
- data.tar.gz: 51e4d4bef90306fb68f879fcaf8db6305bc54a6b52a402f50b62cf4db2628d963352a9bfeac09a75e14e8973014152aab239dd53812fbfd88a09dc648f110976
6
+ metadata.gz: 33bdc6ff8f9b6bf47352876b60fbac750a6ea4f616c9f85197af9ce9a08d9773ac33ef6450ee4f63b33ac6bb6696eefa03a7f394c6d46243eb9ced1cc8977122
7
+ data.tar.gz: 946a6ef094042486ab500081851c7d8d19e613ae356d5fe0fc98c67eeb3780fe9dd271543f98f6a0cb2f9655849b6976d195126f02c6c951b9efd79c3c555e1c
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # version 0.1beta1 (pre NoraText)
2
+
3
+ * Totally rewrite using kpeg.
4
+ * degrage : toc feature removed (for the old toc feature is so poor)
5
+ * degrade : removed custom BlockParser. Instead of the feature, easy and powerful customization will be introduced in NoraText 0.1)
6
+ * markup change: alternate block notation starting with 'd{---' has removed
7
+ * markup change: inline image notation is changed form [img(alt-text){src}] to [img(src, alt)]
8
+
9
+ * will change the name from ArtiMark to NoraText on next release 0.1rc1
10
+
11
+
12
+
data/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  ArtiMark is a simple text markup language. It is designed to create XHTML files for EPUB books. It is optimized for Japanese text for the present.
4
4
 
5
- **CAUTION This is very early alpha version, so it's not stable at all. Even the markup syntax will change. **
5
+ **CAUTION This is very early alpha version, so it's not stable at all.**
6
6
 
7
- I hope it will be partly stable by the end of Feburary, 2013
7
+ Reimplemented new version will be released on the end of Feb. 2014. Some syntax will be changed on the new version. The name of the library may change.
8
8
 
9
9
  ## Installation
10
10
 
data/Rakefile CHANGED
@@ -1,2 +1,12 @@
1
1
  #!/usr/bin/env rake
2
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/arti_mark/parser.kpeg.rb"] do
11
+ system 'rspec'
12
+ end
data/arti_mark.gemspec CHANGED
@@ -15,6 +15,8 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = ArtiMark::VERSION
17
17
 
18
- gem.add_development_dependency "rspec", "~> 2.11"
19
- gem.add_development_dependency "nokogiri", "~> 1.5.6"
18
+ gem.required_ruby_version = '>= 2.0.0'
19
+ gem.add_dependency "kpeg"
20
+ gem.add_development_dependency "rspec", "~> 2.14"
21
+ gem.add_development_dependency "nokogiri", "~> 1.6.0"
20
22
  end
@@ -19,8 +19,8 @@ module ArtiMark
19
19
 
20
20
  r << "<div#{ids_string(lexed[:ids])}#{class_string(lexed[:cls])}>"
21
21
  r << "<p>#{caption}</p>" if !caption.nil? && caption.size > 0 && caption_before
22
- r << "<img src='#{src}' alt='#{alt}' />"
23
- r << "<p>#{caption}</p>" if !caption.nil? && caption.size > 0 && !caption_before
22
+ r << "<img src='#{src}' alt='#{escape_html alt}' />"
23
+ r << "<p>#{escape_html caption}</p>" if !caption.nil? && caption.size > 0 && !caption_before
24
24
  r << "</div>\n"
25
25
  end
26
26
  end
@@ -1,4 +1,5 @@
1
1
  module ArtiMark
2
+ module Html
2
3
  class Context
3
4
  attr_accessor :title, :head_inserters, :toc, :lang, :stylesheets, :enable_pgroup
4
5
  def initialize(param = {})
@@ -25,7 +26,10 @@ module ArtiMark
25
26
  ret
26
27
  end
27
28
  end
28
-
29
+ def chop_last_space
30
+ @pages.last.sub!(/[[:space:]]+$/, '')
31
+ end
32
+
29
33
  def head_inserter(&block)
30
34
  head_inserters << block
31
35
  end
@@ -91,3 +95,4 @@ module ArtiMark
91
95
  end
92
96
  end
93
97
  end
98
+ end
@@ -0,0 +1,159 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'arti_mark/html/util'
3
+ require 'arti_mark/html/result'
4
+ require 'arti_mark/html/context'
5
+ require 'arti_mark/html/tag_writer'
6
+ require 'arti_mark/html/header_writer'
7
+ require 'arti_mark/html/writer_selector'
8
+ module ArtiMark
9
+ module Html
10
+ class Generator
11
+ include Util
12
+ attr_reader :context
13
+ def initialize(param = {})
14
+ @context = Context.new(param)
15
+ article_writer = TagWriter.create('article', self)
16
+ link_writer = TagWriter.create('a', self, trailer: '',
17
+ item_preprocessor: proc do |item|
18
+ (item[:attrs] ||= {}).merge!({:href => [ item[:args][0] ]})
19
+ item
20
+ end)
21
+
22
+ header_writer = HeaderWriter.new self
23
+
24
+ @writers = {
25
+ :paragraph =>
26
+ TagWriter.create('p', self, chop_last_space: true,
27
+ item_preprocessor: proc do |item|
28
+ add_class(item, 'noindent') if item[:children][0] =~/^(「|『|()/ # TODO: should be plaggable}
29
+ item
30
+ end
31
+ ),
32
+ :paragraph_group =>
33
+ TagWriter.create("div", self,
34
+ item_preprocessor: proc do |item|
35
+ add_class item, 'pgroup'
36
+ item[:no_tag] = true unless @context.enable_pgroup
37
+ item
38
+ end
39
+ ),
40
+
41
+ :block =>
42
+ WriterSelector.new(self,
43
+ {
44
+ 'd' => TagWriter.create('div', self),
45
+ 'art' => article_writer,
46
+ 'article' => article_writer
47
+ }),
48
+ :line_command =>
49
+ WriterSelector.new(self,
50
+ {
51
+ 'image' =>
52
+ TagWriter.create('div', self,
53
+ item_preprocessor: proc do |item|
54
+ add_class_if_empty item, 'img-wrap'
55
+ item
56
+ end,
57
+ write_body_preprocessor: proc do |item|
58
+ src = item[:args][0].strip
59
+ alt = (item[:args][1] || '').strip
60
+ caption_before = item[:named_args][:caption_before]
61
+ if caption_before && children_not_empty(item)
62
+ output "<p>"; write_children item; output "</p>"
63
+ end
64
+ output "<img src='#{src}' alt='#{escape_html alt}' />"
65
+ if !caption_before && children_not_empty(item)
66
+ output "<p>"; write_children item; output "</p>"
67
+ end
68
+ :done
69
+ end
70
+ ),
71
+ 'newpage' =>
72
+ TagWriter.create('div', self,
73
+ item_preprocessor: proc do |item|
74
+ item[:no_tag] = true
75
+ item
76
+ end,
77
+ write_body_preprocessor: proc do |item|
78
+ title = nil
79
+ if item[:args].size > 0 && item[:args][0].size > 0
80
+ title = escape_html item[:args].first
81
+ end
82
+ @context.start_html(title)
83
+ :done
84
+ end
85
+ ),
86
+
87
+ }),
88
+ :inline =>
89
+ WriterSelector.new(self,
90
+ {
91
+ 'link' => link_writer,
92
+ 'l' => link_writer,
93
+ 's' => TagWriter.create('span', self),
94
+ 'img' =>
95
+ TagWriter.create('img', self,
96
+ item_preprocessor: proc do |item|
97
+ 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}
98
+ (item[:attrs] ||= {}).merge!({:src => [item[:args][0] ]})
99
+ item[:attrs].merge!({:alt => [ escape_html(item[:args][1].strip)]}) if (item[:args].size > 1 && item[:args][1].size > 0)
100
+ item
101
+ end) ,
102
+ 'tcy' =>
103
+ TagWriter.create('span', self,
104
+ item_preprocessor: proc do |item|
105
+ add_class item, 'tcy'
106
+ item
107
+ end),
108
+ 'ruby' =>
109
+ TagWriter.create('ruby', self,
110
+ write_body_preprocessor: proc do |item|
111
+ write_children item
112
+ output "<rp>(</rp><rt>#{escape_html item[:args][0].strip}</rt><rp>)</rp>"
113
+ :done
114
+ end),
115
+
116
+ },
117
+ trailer_default:''
118
+ ),
119
+ :ol => TagWriter.create('ol', self),
120
+ :ul => TagWriter.create('ul', self),
121
+ :li => TagWriter.create('li', self),
122
+ :dl => TagWriter.create('dl', self),
123
+ :dtdd =>
124
+ TagWriter.create('', self, chop_last_space: true, item_preprocessor: proc do |item| item[:no_tag] = true; item end,
125
+ write_body_preprocessor: proc do |item|
126
+ output "<dt>"; write_array item[:args][0]; output "</dt>"
127
+ output "<dd>"; write_array item[:args][1]; output "</dd>"
128
+ :done
129
+ end),
130
+ # headers
131
+ :stylesheets => header_writer,
132
+ :title => header_writer,
133
+ :lang => header_writer,
134
+ }
135
+ end
136
+
137
+ def convert(parsed_result)
138
+ parsed_result.each {
139
+ |item|
140
+ to_html(item)
141
+ }
142
+ @context.result
143
+ end
144
+ def to_html(item)
145
+ if item.is_a? String
146
+ @context << escape_html(item)
147
+ else
148
+ writer = @writers[item[:type]]
149
+ if writer.nil?
150
+ warn "can't find html generator for \"#{item}\""
151
+ @context << escape_html(item[:raw_text])
152
+ else
153
+ writer.write(item)
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,32 @@
1
+ module ArtiMark
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
+ }
26
+ end
27
+ def write(item)
28
+ @writers[item[:type]].call item
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ module ArtiMark
2
+ module Html
3
+ class Context
4
+ class Result < Array
5
+ def initialize
6
+ super
7
+ end
8
+
9
+ def write_as_files(prefix, format='%03d')
10
+ self.each_with_index {
11
+ |converted, i|
12
+ File.open("#{prefix}_#{format%(i+1)}.xhtml", 'w+') {
13
+ |file|
14
+ file << converted
15
+ }
16
+ }
17
+ end
18
+ def write_as_single_file(filename)
19
+ File.open(filename, 'w+') {
20
+ |file|
21
+ file << self[0]
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,110 @@
1
+ module ArtiMark
2
+ module Html
3
+ class TagWriter
4
+ include Util
5
+ attr_accessor :trailer, :item_preprocessors, :write_body_preprocessors
6
+
7
+ def self.create(tag_name, generator, item_preprocessor: nil, write_body_preprocessor: nil, trailer: "\n", chop_last_space: false)
8
+ instance = TagWriter.new(tag_name, generator, chop_last_space: chop_last_space)
9
+ instance.item_preprocessors << item_preprocessor unless item_preprocessor.nil?
10
+ instance.write_body_preprocessors << write_body_preprocessor unless write_body_preprocessor.nil?
11
+ instance.trailer = trailer
12
+ yield instance if block_given?
13
+ instance
14
+ end
15
+
16
+ def initialize(tag_name, generator, **param)
17
+ @tag_name = tag_name
18
+ @generator = generator
19
+ @context = generator.context
20
+ @trailer = trailer
21
+ @item_preprocessors = []
22
+ @write_body_preprocessors = []
23
+ @param = param
24
+ end
25
+
26
+ def attr_string(attrs)
27
+ attrs.map do
28
+ |name, vals|
29
+ if vals.size == 0
30
+ ''
31
+ else
32
+ " #{name}='#{vals.join(' ')}'"
33
+ end
34
+ end.join('')
35
+ end
36
+
37
+ def class_string(cls_array)
38
+ attr_string({'class' => cls_array})
39
+ end
40
+
41
+ def ids_string(ids_array)
42
+ attr_string({'id' => ids_array})
43
+ end
44
+
45
+ def add_class(item, cls)
46
+ (item[:classes] ||= []) << cls
47
+ end
48
+
49
+ def add_class_if_empty(item, cls)
50
+ add_class(item, cls) if item[:classes].nil? || item[:classes].size == 0
51
+ end
52
+
53
+ def tag_start(item)
54
+ return if item[:no_tag]
55
+ ids = item[:ids] || []
56
+ classes = item[:classes] || []
57
+ attr = item[:attrs] || {}
58
+ tag_name = @tag_name || item[:name]
59
+ @context << "<#{tag_name}#{ids_string(ids)}#{class_string(classes)}#{attr_string(attr)}"
60
+ if item[:no_body]
61
+ @context << " />"
62
+ else
63
+ @context << ">"
64
+ end
65
+ end
66
+
67
+ def output(string)
68
+ @context << string
69
+ end
70
+
71
+ def tag_end(item)
72
+ return if item[:no_tag]
73
+ tag_name = @tag_name || item[:name]
74
+ @context << "</#{tag_name}>#{@trailer}"
75
+ end
76
+
77
+ def write(item)
78
+ @item_preprocessors.each { |x| item = instance_exec item.dup, &x }
79
+ @context.enable_pgroup, saved_ep = !(item[:args].include?('wo-pgroup') || !@context.enable_pgroup), @context.enable_pgroup
80
+ tag_start item
81
+ write_body item if !item[:no_body]
82
+ tag_end item if !item[:no_body]
83
+ @context.enable_pgroup = saved_ep
84
+ end
85
+
86
+ def write_body(item)
87
+ @write_body_preprocessors.each {
88
+ |x|
89
+ return if instance_exec(item, &x) == :done
90
+ }
91
+ write_children item
92
+ end
93
+
94
+ def write_children(item)
95
+ write_array(item[:children])
96
+ end
97
+
98
+ def write_array(array)
99
+ return if array.nil? || array.size == 0
100
+ array.each { |x| @generator.to_html x }
101
+ @generator.context.chop_last_space if (@param[:chop_last_space])
102
+ end
103
+
104
+ def children_not_empty(item)
105
+ !item[:children].nil? && item[:children].size > 0 && item[:children].select { |x| (x.is_a? String) ? x.size >0 : !x.nil? }.size > 0
106
+ end
107
+
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,12 @@
1
+ module ArtiMark
2
+ module Html
3
+ module Util
4
+ def escape_html(string)
5
+ string.to_s.gsub("&", "&amp;").
6
+ gsub("<", "&lt;").
7
+ gsub(">", "&gt;").
8
+ gsub('"', "&quot;")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module ArtiMark
2
+ module Html
3
+ class WriterSelector
4
+ def initialize(generator, tag_writers = {}, trailer_default: "\n" )
5
+ @generator = generator
6
+ @common_tag_writer = TagWriter.create(nil, @generator, trailer: trailer_default)
7
+ @tag_writers = tag_writers
8
+ if !trailer_default.nil?
9
+ @tag_writers.each { |k, t|
10
+ if t.is_a? TagWriter
11
+ t.trailer = trailer_default
12
+ end
13
+ }
14
+ end
15
+
16
+ end
17
+
18
+ def write(item)
19
+ writer = @tag_writers[item[:name]] || @common_tag_writer
20
+ writer.write(item)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,97 @@
1
+ %% name = ArtiMark::Parser
2
+
3
+ # literals
4
+ eof = !.
5
+ space = ' ' | '\t'
6
+ eof_comment = lh space* "#" (!eof .)*
7
+ comment = lh space* "#" (!nl .)* nl
8
+
9
+ - = ( space | comment )*
10
+ empty_line = lh - nl
11
+ nl = /\r?\n/
12
+ lh = /^/
13
+ le = nl | /$/
14
+ word = < /[\w0-9]/ ( '-' | /[\w0-9]/ )* > { text }
15
+ num = < [0-9]+ > { text.to_i }
16
+
17
+ #common syntax
18
+ classname = '.' word:classname { classname }
19
+ classnames = (classname)*:classnames { classnames }
20
+ idname = '#' word:idname { idname }
21
+ idnames = (idname)*:idnames { idnames }
22
+
23
+ commandname = word:name idnames?:idnames classnames?:classes { {:name => name, :ids => idnames, :classes => classes} }
24
+ parameter = < ( /[^,)]/* | '"' /[^"]/* '"' | "'" /[^']/* "'" ) > { text }
25
+ parameters = < parameter (',' parameter)* > { text }
26
+ command = commandname:commandname ('(' - parameters:arg - ')')? { arg ||= ''; commandname.merge({ :args => arg.split(',') }) }
27
+
28
+ # paragraph
29
+ implicit_paragraph = < (!paragraph_delimiter - documentline - ):paragraph > { create_item(:paragraph, nil, paragraph, raw: text) }
30
+ paragraph = explicit_paragraph | implicit_paragraph
31
+
32
+ # paragraph_group
33
+ paragraph_group = < (paragraph nl | paragraph )+:paragraphs empty_line* > { create_item(:paragraph_group, nil, paragraphs, raw: text) }
34
+
35
+ # explicit block
36
+ blockhead = lh - command:command - '{' - le { command }
37
+ blockend = lh - '}' - le
38
+ blockbody = (!blockend block)+:body { body }
39
+ explicit_block = < blockhead:head blockbody:body blockend > { create_item(:block, head, body, raw: text) }
40
+
41
+ # inline command
42
+ inline = img_inline | common_inline
43
+ common_inline = < '[' command:command '{' documentcontent_except('}'):content '}' ']' > { create_item(:inline, command, content, raw: text) }
44
+
45
+ #img inline
46
+ img_command = command:command &{ command[:name] == 'img' && command[:args].size == 2}
47
+ img_inline = < '[' img_command:command ']' > { create_item(:inline, command, nil, raw: text) }
48
+
49
+ # special line commands
50
+ # newpage
51
+ newpage = line_command:item &{ item[:name] == 'newpage' }
52
+ # explicit paragraph
53
+ explicit_paragraph_command = command:command &{ command[:name] == 'p' }
54
+ explicit_paragraph = < lh - explicit_paragraph_command:command ':' documentcontent?:content le > { create_item(:paragraph, command, content, raw:text) }
55
+
56
+ # unordered list
57
+ unordered_list = < unordered_item+:items > { create_item(:ul, nil, items, raw: text) }
58
+ unordered_item = < lh '*:' documentcontent:content le > { create_item(:li, nil, content, raw: text) }
59
+
60
+ # ordered list
61
+ ordered_list = < ordered_item+:items > { create_item(:ol, nil, items, raw: text) }
62
+ ordered_item = < lh num ':' documentcontent:content le > { create_item(:li, nil, content, raw: text) }
63
+
64
+ # definition list
65
+ definition_list = < definition_item+:items > { create_item(:dl, nil, items, raw: text) }
66
+ definition_item = < lh ';:' - documentcontent_except(':'):term ':' - documentcontent:definition le > { create_item(:dtdd, {:args => [term, definition]}, nil, raw: text) }
67
+
68
+ items_list = unordered_list | ordered_list | definition_list
69
+
70
+
71
+ # generic line command
72
+ line_command = < lh - (!explicit_paragraph_command command):command ':' documentcontent?:content le > { create_item(:line_command, command, content, raw: text) }
73
+
74
+ # blocks
75
+ block = items_list | line_command | explicit_block | paragraph_group | empty_line+
76
+ block_delimiter = blockhead | blockend | newpage
77
+ paragraph_delimiter = block | block_delimiter
78
+
79
+ # texts
80
+ char = < /[[:print:]]/ > { text }
81
+ charstring = < char* > { text }
82
+ char_except(e) = char:c &{ c != e }
83
+ charstring_except(e) = < char_except(e)* > { text }
84
+ documentcontent_except(e) = (inline | !inline char_except(e))+:content ~parse_text(content)
85
+ documentcontent = (inline | !inline char)+:content ~parse_text(content)
86
+ documentline = lh documentcontent:content /$/ { content }
87
+
88
+ #header
89
+ stylesheets = < lh - 'stylesheets:' (!le charstring):stylesheets le > { create_item(:stylesheets, {:stylesheets => stylesheets.split(',').map(&:strip)}, nil, raw:text) }
90
+ title = < lh - 'title:' (!le charstring):title le > { create_item(:title, {:title => title }, nil, raw:text) }
91
+ lang = < lh - 'lang:' (!le charstring):lang le > { create_item(:lang, {:lang => lang }, nil, raw:text) }
92
+ header = stylesheets | title | lang
93
+
94
+ #root
95
+ root = header*:headers block*:blocks eof_comment? eof { headers + blocks }
96
+
97
+