pseudohikiparser 0.0.0.8.develop → 0.0.0.9.develop

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,331 +6,423 @@ require 'erb'
6
6
  require 'pseudohiki/blockparser'
7
7
  require 'pseudohiki/htmlformat'
8
8
  require 'pseudohiki/plaintextformat'
9
+ require 'pseudohiki/markdownformat'
9
10
  require 'htmlelement/htmltemplate'
10
11
  require 'htmlelement'
11
12
 
12
- include PseudoHiki
13
-
14
- OPTIONS = {
15
- :html_version => "html4",
16
- :lang => 'en',
17
- :encoding => 'utf8',
18
- :title => nil,
19
- :css => "default.css",
20
- :embed_css => nil,
21
- :base => nil,
22
- :template => nil,
23
- :output => nil,
24
- :force => false,
25
- :toc => nil,
26
- :split_main_heading => false
27
- }
28
-
29
- ENCODING_REGEXP = {
30
- /^u/io => 'utf8',
31
- /^e/io => 'euc-jp',
32
- /^s/io => 'sjis',
33
- /^l[a-zA-Z]*1/io => 'latin1'
34
- }
35
-
36
- HTML_VERSIONS = %w(html4 xhtml1 html5)
37
-
38
- FILE_HEADER_PAT = /^(\xef\xbb\xbf)?\/\//
39
- WRITTEN_OPTION_PAT = {}
40
- OPTIONS.keys.each {|opt| WRITTEN_OPTION_PAT[opt] = /^(\xef\xbb\xbf)?\/\/#{opt}:\s*(.*)$/ }
41
- HEADING_WITH_ID_PAT = /^(!{2,3})\[([A-Za-z][0-9A-Za-z_\-.:]*)\]\s*/o
42
-
43
- PlainFormat = PlainTextFormat.create
44
-
45
- class InputManager
46
- def formatter
47
- @formatter ||= OPTIONS.html_template.new
48
- end
13
+ module PseudoHiki
14
+ class PageComposer
15
+ HEADING_WITH_ID_PAT = /^(!{2,3})\[([A-Za-z][0-9A-Za-z_\-.:]*)\]\s*/o
49
16
 
50
- def to_plain(line)
51
- PlainFormat.format(BlockParser.parse(line.lines.to_a)).to_s.chomp
52
- end
17
+ PlainFormat = PlainTextFormat.create
53
18
 
54
- def create_table_of_contents(lines)
55
- return "" unless OPTIONS[:toc]
56
- toc_lines = lines.grep(HEADING_WITH_ID_PAT).map do |line|
57
- m = HEADING_WITH_ID_PAT.match(line)
58
- heading_depth, id = m[1].length, m[2].upcase
59
- "%s[[%s|#%s]]"%['*'*heading_depth, to_plain(line.sub(HEADING_WITH_ID_PAT,'')), id]
19
+ def initialize(options)
20
+ @options = options
60
21
  end
61
- OPTIONS.formatter.format(BlockParser.parse(toc_lines))
62
- end
63
22
 
64
- def split_main_heading(input_lines)
65
- return "" unless OPTIONS[:split_main_heading]
66
- h1_pos = input_lines.find_index {|line| /^![^!]/o =~ line }
67
- return "" unless h1_pos
68
- tree = BlockParser.parse([input_lines.delete_at(h1_pos)])
69
- OPTIONS.formatter.format(tree)
70
- end
23
+ def formatter
24
+ @formatter ||= @options.html_template.new
25
+ end
71
26
 
72
- def create_main(toc, body, h1)
73
- return nil unless OPTIONS[:toc]
74
- toc_container = formatter.create_element("section").tap do |element|
75
- element["id"] = "toc"
76
- element.push formatter.create_element("h2", OPTIONS[:toc]) unless OPTIONS[:toc].empty?
77
- element.push toc
27
+ def to_plain(line)
28
+ PlainFormat.format(BlockParser.parse(line.lines.to_a)).to_s.chomp
78
29
  end
79
- contents_container = formatter.create_element("section").tap do |element|
80
- element["id"] = "contents"
81
- element.push body
30
+
31
+ def create_plain_table_of_contents(lines)
32
+ toc_lines = lines.grep(HEADING_WITH_ID_PAT).map do |line|
33
+ m = HEADING_WITH_ID_PAT.match(line)
34
+ heading_depth = m[1].length
35
+ line.sub(/^!+/o, '*'*heading_depth)
36
+ end
37
+
38
+ @options.formatter.format(BlockParser.parse(toc_lines))
82
39
  end
83
- main = formatter.create_element("section").tap do |element|
84
- element["id"] = "main"
85
- element.push h1 unless h1.empty?
86
- element.push toc_container
87
- element.push contents_container
40
+
41
+ def create_html_table_of_contents(lines)
42
+ toc_lines = lines.grep(HEADING_WITH_ID_PAT).map do |line|
43
+ m = HEADING_WITH_ID_PAT.match(line)
44
+ heading_depth, id = m[1].length, m[2].upcase
45
+ "%s[[%s|#%s]]"%['*'*heading_depth, to_plain(line.sub(HEADING_WITH_ID_PAT,'')), id]
46
+ end
47
+ @options.formatter.format(BlockParser.parse(toc_lines)).tap do |toc|
48
+ toc.traverse do |element|
49
+ if element.kind_of? HtmlElement and element.tagname == "a"
50
+ element["title"] = "toc_item: " + element.children.join.chomp
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def create_table_of_contents(lines)
57
+ return "" unless @options[:toc]
58
+ return create_plain_table_of_contents(lines) unless @options.html_template
59
+ create_html_table_of_contents(lines)
88
60
  end
89
- end
90
61
 
91
- def create_style(path_to_css_file)
92
- style = formatter.create_element("style").tap do |element|
93
- element["type"] = "text/css"
94
- open(File.expand_path(path_to_css_file)) do |css_file|
95
- element.push css_file.read
62
+ def split_main_heading(input_lines)
63
+ return "" unless @options[:split_main_heading]
64
+ h1_pos = input_lines.find_index {|line| /^![^!]/o =~ line }
65
+ return "" unless h1_pos
66
+ tree = BlockParser.parse([input_lines.delete_at(h1_pos)])
67
+ @options.formatter.format(tree)
68
+ end
69
+
70
+ def create_plain_main(toc, body, h1)
71
+ contents = [body]
72
+ contents.unshift toc unless toc.empty?
73
+ contents.unshift @options.formatter.format(BlockParser.parse("!!" + @options[:toc])) if @options[:toc]
74
+ contents.unshift h1 unless h1.empty?
75
+ contents.join($/)
76
+ end
77
+
78
+ def create_html_main(toc, body, h1)
79
+ return nil unless @options[:toc]
80
+ toc_container = formatter.create_element("section").tap do |element|
81
+ element["id"] = "toc"
82
+ element.push formatter.create_element("h2", @options[:toc]) unless @options[:toc].empty?
83
+ element.push toc
84
+ end
85
+ contents_container = formatter.create_element("section").tap do |element|
86
+ element["id"] = "contents"
87
+ element.push body
88
+ end
89
+ main = formatter.create_element("section").tap do |element|
90
+ element["id"] = "main"
91
+ element.push h1 unless h1.empty?
92
+ element.push toc_container
93
+ element.push contents_container
96
94
  end
97
95
  end
98
- end
99
96
 
100
- def compose_body(input_lines)
101
- tree = BlockParser.parse(input_lines)
102
- OPTIONS.formatter.format(tree)
103
- end
97
+ def create_main(toc, body, h1)
98
+ return create_plain_main(toc, body, h1) unless @options.html_template
99
+ create_html_main(toc, body, h1)
100
+ end
104
101
 
105
- def compose_html(input_lines)
106
- h1 = split_main_heading(input_lines)
107
- css = OPTIONS[:css]
108
- toc = create_table_of_contents(input_lines)
109
- body = compose_body(input_lines)
110
- title = OPTIONS.title
111
- main = create_main(toc,body, h1)
102
+ def create_style(path_to_css_file)
103
+ style = formatter.create_element("style").tap do |element|
104
+ element["type"] = "text/css"
105
+ open(File.expand_path(path_to_css_file)) do |css_file|
106
+ element.push css_file.read
107
+ end
108
+ end
109
+ end
112
110
 
113
- if OPTIONS[:template]
114
- erb = ERB.new(OPTIONS.read_template_file)
115
- html = erb.result(binding)
116
- else
117
- html = OPTIONS.create_html_with_current_options
118
- html.head.push create_style(OPTIONS[:embed_css]) if OPTIONS[:embed_css]
119
- html.push main||body
111
+ def compose_body(input_lines)
112
+ tree = BlockParser.parse(input_lines)
113
+ @options.formatter.format(tree)
120
114
  end
121
115
 
122
- html
116
+ def compose_html(input_lines)
117
+ h1 = split_main_heading(input_lines)
118
+ css = @options[:css]
119
+ toc = create_table_of_contents(input_lines)
120
+ body = compose_body(input_lines)
121
+ title = @options.title
122
+ main = create_main(toc,body, h1)
123
+
124
+ if @options[:template]
125
+ erb = ERB.new(@options.read_template_file)
126
+ html = erb.result(binding)
127
+ else
128
+ html = @options.create_html_template_with_current_options
129
+ html.head.push create_style(@options[:embed_css]) if @options[:embed_css]
130
+ html.push main||body
131
+ end
132
+
133
+ html
134
+ end
123
135
  end
124
- end
125
136
 
126
- def win32?
127
- true if RUBY_PLATFORM =~ /win/i
128
- end
137
+ class OptionManager
138
+ include HtmlElement::CHARSET
129
139
 
130
- def value_given?(value)
131
- value and not value.empty?
132
- end
140
+ PlainVerboseFormat = PlainTextFormat.create(:verbose_mode => true)
141
+ MDFormat = MarkDownFormat.create
142
+ GFMFormat = MarkDownFormat.create(:gfm_style => true)
133
143
 
134
- class << OPTIONS
135
- include HtmlElement::CHARSET
136
- attr_accessor :need_output_file, :default_title
137
- attr_reader :input_file_basename
144
+ class Formatter < Struct.new(:version, :formatter, :template, :ext, :opt_pat)
145
+ end
138
146
 
139
- ENCODING_TO_CHARSET = {
140
- 'utf8' => UTF8,
141
- 'euc-jp' => EUC_JP,
142
- 'sjis' => SJIS,
143
- 'latin1' => LATIN1
144
- }
147
+ VERSIONS = [
148
+ ["html4", HtmlFormat, HtmlTemplate, ".html", /^h/io],
149
+ ["xhtml1", XhtmlFormat, XhtmlTemplate, ".html", /^x/io],
150
+ ["html5", Xhtml5Format, Xhtml5Template, ".html", /^h5/io],
151
+ ["plain", PageComposer::PlainFormat, nil, ".plain", /^p/io],
152
+ ["plain_verbose", PlainVerboseFormat, nil, ".plain", /^pv/io],
153
+ ["markdown", MDFormat, nil, ".md", /^m/io],
154
+ ["gfm", GFMFormat, nil, ".md", /^g/io]
155
+ ].map {|args| Formatter.new(*args) }
156
+
157
+ ENCODING_REGEXP = {
158
+ /^u/io => 'utf8',
159
+ /^e/io => 'euc-jp',
160
+ /^s/io => 'sjis',
161
+ /^l[a-zA-Z]*1/io => 'latin1'
162
+ }
163
+
164
+ BOM = "\xef\xbb\xbf"
165
+ BOM.force_encoding("ASCII-8BIT") if BOM.respond_to? :encoding
166
+ FILE_HEADER_PAT = /^\/\//
167
+
168
+ ENCODING_TO_CHARSET = {
169
+ 'utf8' => UTF8,
170
+ 'euc-jp' => EUC_JP,
171
+ 'sjis' => SJIS,
172
+ 'latin1' => LATIN1
173
+ }
174
+
175
+ attr_accessor :need_output_file, :default_title
176
+ attr_reader :input_file_basename
177
+
178
+ def self.remove_bom(input=ARGF)
179
+ bom = input.read(3)
180
+ input.rewind unless BOM == bom
181
+ end
145
182
 
146
- HTML_TEMPLATES = Hash[*HTML_VERSIONS.zip([HtmlTemplate, XhtmlTemplate, Xhtml5Template]).flatten]
147
- FORMATTERS = Hash[*HTML_VERSIONS.zip([HtmlFormat, XhtmlFormat, Xhtml5Format]).flatten]
183
+ def initialize(options=nil)
184
+ @options = options||{
185
+ :html_version => VERSIONS[0],
186
+ :lang => 'en',
187
+ :encoding => 'utf8',
188
+ :title => nil,
189
+ :css => "default.css",
190
+ :embed_css => nil,
191
+ :base => nil,
192
+ :template => nil,
193
+ :output => nil,
194
+ :force => false,
195
+ :toc => nil,
196
+ :split_main_heading => false
197
+ }
198
+ @written_option_pat = {}
199
+ @options.keys.each {|opt| @written_option_pat[opt] = /^\/\/#{opt}:\s*(.*)$/ }
200
+ end
148
201
 
149
- def html_template
150
- HTML_TEMPLATES[self[:html_version]]
151
- end
202
+ def [](key)
203
+ @options[key]
204
+ end
152
205
 
153
- def formatter
154
- FORMATTERS[self[:html_version]]
155
- end
206
+ def[]=(key, value)
207
+ @options[key] = value
208
+ end
156
209
 
157
- def charset
158
- ENCODING_TO_CHARSET[self[:encoding]]
159
- end
210
+ def win32?
211
+ true if RUBY_PLATFORM =~ /win/i
212
+ end
160
213
 
161
- def base
162
- base_dir = self[:base]
163
- if base_dir and base_dir !~ /[\/\\]\.*$/o
164
- base_dir = File.join(base_dir,".")
165
- base_dir = "file:///"+base_dir if base_dir !~ /^\./o and win32?
214
+ def value_given?(value)
215
+ value and not value.empty?
166
216
  end
167
- base_dir
168
- end
169
217
 
170
- def title
171
- OPTIONS[:title]||@default_title||"-"
172
- end
218
+ def html_template
219
+ self[:html_version].template
220
+ end
173
221
 
174
- def read_template_file
175
- File.read(File.expand_path(self[:template]))
176
- end
222
+ def formatter
223
+ self[:html_version].formatter
224
+ end
177
225
 
178
- def set_html_version(version)
179
- if HTML_VERSIONS.include? version
180
- self[:html_version] = version
181
- else
182
- case version
183
- when /^x/io
184
- self[:html_version] = HTML_VERSIONS[1] #xhtml1
185
- when /^h5/io
186
- self[:html_version] = HTML_VERSIONS[2] #html5
187
- end
188
- STDERR.puts "\"#{version}\" is an invalid option for --html_version. \"#{self[:html_version]}\" is chosen instead."
226
+ def charset
227
+ ENCODING_TO_CHARSET[self[:encoding]]
189
228
  end
190
- end
191
229
 
192
- def set_encoding(given_opt)
193
- if ENCODING_REGEXP.values.include? given_opt
194
- self[:encoding] = given_opt
195
- else
196
- ENCODING_REGEXP.each do |pat, encoding|
197
- self[:encoding] = encoding if pat =~ given_opt
230
+ def base
231
+ base_dir = self[:base]
232
+ if base_dir and base_dir !~ /[\/\\]\.*$/o
233
+ base_dir = File.join(base_dir,".")
234
+ base_dir = "file:///"+base_dir if base_dir !~ /^\./o and win32?
198
235
  end
199
- STDERR.puts "\"#{self[:encoding]}\" is chosen as an encoding system, instead of \"#{given_opt}\"."
236
+ base_dir
237
+ end
238
+
239
+ def title
240
+ self[:title]||@default_title||"-"
241
+ end
242
+
243
+ def read_template_file
244
+ File.read(File.expand_path(self[:template]), :encoding => self.charset)
200
245
  end
201
- end
202
246
 
203
- def set_options_from_input_file(input_lines)
204
- input_lines.each do |line|
205
- break if FILE_HEADER_PAT !~ line
206
- line = line.chomp
207
- self.keys.each do |opt|
208
- if WRITTEN_OPTION_PAT[opt] =~ line and not self[:force]
209
- self[opt] = $2
247
+ def set_html_version(version)
248
+ VERSIONS.each do |v|
249
+ if v.version == version
250
+ return self[:html_version] = v
251
+ else
252
+ self[:html_version] = v if v.opt_pat =~ version
210
253
  end
211
254
  end
255
+ STDERR.puts "\"#{version}\" is an invalid option for --format-version. \"#{self[:html_version].version}\" is chosen instead."
212
256
  end
213
- end
214
257
 
215
- def create_html_with_current_options
216
- html = self.html_template.new
217
- html.charset = self.charset
218
- html.language = self[:lang]
219
- html.default_css = self[:css] if self[:css]
220
- html.base = self.base if self[:base]
221
- html.title = self.title
222
- html
223
- end
224
-
225
- def read_input_filename(filename)
226
- @input_file_dir, @input_file_name = File.split(File.expand_path(filename))
227
- @input_file_basename = File.basename(@input_file_name,".*")
228
- end
258
+ def set_html_encoding(given_opt)
259
+ if ENCODING_REGEXP.values.include? given_opt
260
+ self[:encoding] = given_opt
261
+ else
262
+ ENCODING_REGEXP.each do |pat, encoding|
263
+ self[:encoding] = encoding if pat =~ given_opt
264
+ end
265
+ STDERR.puts "\"#{self[:encoding]}\" is chosen as an encoding system, instead of \"#{given_opt}\"."
266
+ end
267
+ end
229
268
 
230
- def output_file_name
231
- return nil unless self.need_output_file
232
- if self[:output]
233
- File.expand_path(self[:output])
234
- else
235
- File.join(@input_file_dir, @input_file_basename+".html")
269
+ def set_encoding(given_opt)
270
+ return nil unless String.new.respond_to? :encoding
271
+ external, internal = given_opt.split(/:/o)
272
+ Encoding.default_external = external if external
273
+ Encoding.default_interanl = internal if internal
236
274
  end
237
- end
238
- end
239
275
 
240
- OptionParser.new("** Convert texts written in a Hiki-like notation into HTML **
276
+ def parse_command_line_options
277
+ OptionParser.new("** Convert texts written in a Hiki-like notation into HTML **
241
278
  USAGE: #{File.basename(__FILE__)} [options]") do |opt|
242
- opt.on("-h [html_version]", "--html_version [=html_version]",
243
- "HTML version to be used. Choose html4, xhtml1 or html5 (default: #{OPTIONS[:html_version]})") do |version|
244
- OPTIONS.set_html_version(version)
245
- end
279
+ opt.on("-f [html_version]", "--format-version [=format_version]",
280
+ "HTML version to be used. Choose html4, xhtml1, html5, plain, plain_verbose, markdown or gfm (default: #{self[:html_version].version})") do |version|
281
+ self.set_html_version(version)
282
+ end
246
283
 
247
- opt.on("-l [lang]", "--lang [=lang]",
248
- "Set the value of charset attributes (default: #{OPTIONS[:lang]})") do |lang|
249
- OPTIONS[:lang] = lang if value_given?(lang)
250
- end
284
+ opt.on("-l [lang]", "--lang [=lang]",
285
+ "Set the value of charset attributes (default: #{self[:lang]})") do |lang|
286
+ self[:lang] = lang if value_given?(lang)
287
+ end
251
288
 
252
- opt.on("-e [encoding]", "--encoding [=encoding]",
253
- "Available options: utf8, euc-jp, sjis, latin1 (default: #{OPTIONS[:encoding]})") do |given_opt|
254
- OPTIONS.set_encoding(given_opt)
255
- end
289
+ opt.on("-e [encoding]", "--format-encoding [=encoding]",
290
+ "Available options: utf8, euc-jp, sjis, latin1 (default: #{self[:encoding]})") do |given_opt|
291
+ self.set_html_encoding(given_opt)
292
+ end
256
293
 
257
- #use '-w' to avoid the conflict with the short option for '[-t]emplate'
258
- opt.on("-w [(window) title]", "--title [=title]",
259
- "Set the value of the <title> element (default: the basename of the input file)") do |title|
260
- OPTIONS[:title] = title if value_given?(title)
261
- end
294
+ opt.on("-E [ex[:in]]", "--encoding [=ex[:in]]",
295
+ "Specify the default external and internal character encodings (same as the option of MRI") do |given_opt|
296
+ self.set_encoding(given_opt)
297
+ end
262
298
 
263
- opt.on("-c [css]", "--css [=css]",
264
- "Set the path to a css file to be used (default: #{OPTIONS[:css]})") do |css|
265
- OPTIONS[:css] = css
266
- end
299
+ #use '-w' to avoid the conflict with the short option for '[-t]emplate'
300
+ opt.on("-w [(window) title]", "--title [=title]",
301
+ "Set the value of the <title> element (default: the basename of the input file)") do |title|
302
+ self[:title] = title if value_given?(title)
303
+ end
267
304
 
268
- opt.on("-C [path_to_css_file]", "--embed-css [=path_to_css_file]",
269
- "Set the path to a css file to embed (default: not to embed)") do |path_to_css_file|
270
- OPTIONS[:embed_css] = path_to_css_file
271
- end
305
+ opt.on("-c [css]", "--css [=css]",
306
+ "Set the path to a css file to be used (default: #{self[:css]})") do |css|
307
+ self[:css] = css
308
+ end
272
309
 
273
- opt.on("-b [base]", "--base [=base]",
274
- "Specify the value of href attribute of the <base> element (default: not specified)") do |base_dir|
275
- OPTIONS[:base] = base_dir if value_given?(base_dir)
276
- end
310
+ opt.on("-C [path_to_css_file]", "--embed-css [=path_to_css_file]",
311
+ "Set the path to a css file to embed (default: not to embed)") do |path_to_css_file|
312
+ self[:embed_css] = path_to_css_file
313
+ end
277
314
 
278
- opt.on("-t [template]", "--template [=template]",
279
- "Specify a template file written in eruby format with \"<%= body %>\" inside (default: not specified)") do |template|
280
- OPTIONS[:template] = template if value_given?(template)
281
- end
315
+ opt.on("-b [base]", "--base [=base]",
316
+ "Specify the value of href attribute of the <base> element (default: not specified)") do |base_dir|
317
+ self[:base] = base_dir if value_given?(base_dir)
318
+ end
282
319
 
283
- opt.on("-o [output]", "--output [=output]",
284
- "Output to the specified file. If no file is given, \"[input_file_basename].html\" will be used.(default: STDOUT)") do |output|
285
- OPTIONS[:output] = File.expand_path(output) if value_given?(output)
286
- OPTIONS.need_output_file = true
287
- end
320
+ opt.on("-t [template]", "--template [=template]",
321
+ "Specify a template file written in eruby format with \"<%= body %>\" inside (default: not specified)") do |template|
322
+ self[:template] = template if value_given?(template)
323
+ end
288
324
 
289
- opt.on("-f", "--force",
290
- "Force to apply command line options.(default: false)") do |force|
291
- OPTIONS[:force] = force
292
- end
325
+ opt.on("-o [output]", "--output [=output]",
326
+ "Output to the specified file. If no file is given, \"[input_file_basename].html\" will be used.(default: STDOUT)") do |output|
327
+ self[:output] = File.expand_path(output) if value_given?(output)
328
+ self.need_output_file = true
329
+ end
293
330
 
294
- opt.on("-m [contents-title]", "--table-of-contents [=contents-title]",
295
- "Include the list of h2 and/or h3 headings with ids.(default: nil)") do |toc_title|
296
- OPTIONS[:toc] = toc_title
297
- end
331
+ opt.on("-F", "--force",
332
+ "Force to apply command line options.(default: false)") do |force|
333
+ self[:force] = force
334
+ end
298
335
 
299
- opt.on("-s", "--split-main-heading",
300
- "Split the first h1 element") do |should_be_split|
301
- OPTIONS[:split_main_heading] = should_be_split
302
- end
336
+ opt.on("-m [contents-title]", "--table-of-contents [=contents-title]",
337
+ "Include the list of h2 and/or h3 headings with ids.(default: nil)") do |toc_title|
338
+ self[:toc] = toc_title
339
+ end
303
340
 
304
- opt.parse!
305
- end
341
+ opt.on("-s", "--split-main-heading",
342
+ "Split the first h1 element") do |should_be_split|
343
+ self[:split_main_heading] = should_be_split
344
+ end
306
345
 
307
- if $KCODE
308
- ENCODING_REGEXP.each do |pat, encoding|
309
- OPTIONS[:encoding] = encoding if pat =~ $KCODE and not OPTIONS[:force]
310
- end
311
- end
346
+ opt.parse!
347
+ end
348
+ end
312
349
 
313
- input_manager = InputManager.new
350
+ def check_argv
351
+ case ARGV.length
352
+ when 0
353
+ if self.need_output_file and not self[:output]
354
+ raise "You must specify a file name for output"
355
+ end
356
+ when 1
357
+ self.read_input_filename(ARGV[0])
358
+ end
359
+ end
360
+
361
+ def set_options_from_command_line
362
+ parse_command_line_options
363
+ check_argv
364
+ @default_title = @input_file_basename
365
+ end
314
366
 
315
- case ARGV.length
316
- when 0
317
- if OPTIONS.need_output_file and not OPTIONS[:output]
318
- raise "You must specify a file name for output"
367
+ def set_options_from_input_file(input_lines)
368
+ input_lines.each do |line|
369
+ break if FILE_HEADER_PAT !~ line
370
+ line = line.chomp
371
+ @options.keys.each do |opt|
372
+ if @written_option_pat[opt] =~ line and not self[:force]
373
+ self[opt] = $1
374
+ end
375
+ end
376
+ end
377
+ end
378
+
379
+ def create_html_template_with_current_options
380
+ return [] unless self.html_template
381
+ html = self.html_template.new
382
+ html.charset = self.charset
383
+ html.language = self[:lang]
384
+ html.default_css = self[:css] if self[:css]
385
+ html.base = self.base if self[:base]
386
+ html.title = self.title
387
+ html
388
+ end
389
+
390
+ def read_input_filename(filename)
391
+ @input_file_dir, @input_file_name = File.split(File.expand_path(filename))
392
+ @input_file_basename = File.basename(@input_file_name,".*")
393
+ end
394
+
395
+ def output_filename
396
+ return nil unless self.need_output_file
397
+ if self[:output]
398
+ File.expand_path(self[:output])
399
+ else
400
+ File.join(@input_file_dir, @input_file_basename + self[:html_version].ext)
401
+ end
402
+ end
403
+
404
+ def open_output
405
+ if self.output_filename
406
+ open(self.output_filename, "w") {|f| yield f }
407
+ else
408
+ yield STDOUT
409
+ end
410
+ end
319
411
  end
320
- when 1
321
- OPTIONS.read_input_filename(ARGV[0])
322
412
  end
323
413
 
324
- input_lines = ARGF.readlines
414
+ options = PseudoHiki::OptionManager.new
415
+ options.set_options_from_command_line
325
416
 
326
- OPTIONS.set_options_from_input_file(input_lines)
327
- OPTIONS.default_title = OPTIONS.input_file_basename
417
+ if $KCODE
418
+ PseudoHiki::OptionManager::ENCODING_REGEXP.each do |pat, encoding|
419
+ options[:encoding] = encoding if pat =~ $KCODE and not options[:force]
420
+ end
421
+ end
328
422
 
329
- html = input_manager.compose_html(input_lines)
330
- output_file_name = OPTIONS.output_file_name
423
+ PseudoHiki::OptionManager.remove_bom
424
+ input_lines = ARGF.readlines.map {|line| line.encode(options.charset) }
425
+ options.set_options_from_input_file(input_lines)
426
+ html = PseudoHiki::PageComposer.new(options).compose_html(input_lines)
331
427
 
332
- if output_file_name
333
- open(output_file_name, "w") {|f| f.puts html }
334
- else
335
- STDOUT.puts html
336
- end
428
+ options.open_output {|out| out.puts html }