tmtms-review 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +9 -0
  3. data/COPYING +515 -0
  4. data/ChangeLog +2083 -0
  5. data/README.rdoc +50 -0
  6. data/Rakefile +56 -0
  7. data/VERSION +1 -0
  8. data/bin/review-check +178 -0
  9. data/bin/review-checkdep +63 -0
  10. data/bin/review-compile +205 -0
  11. data/bin/review-epubmaker +661 -0
  12. data/bin/review-epubmaker-ng +176 -0
  13. data/bin/review-index +118 -0
  14. data/bin/review-pdfmaker +208 -0
  15. data/bin/review-preproc +142 -0
  16. data/bin/review-validate +51 -0
  17. data/bin/review-vol +102 -0
  18. data/debian/README.Debian +12 -0
  19. data/debian/README.source +5 -0
  20. data/debian/changelog +5 -0
  21. data/debian/compat +1 -0
  22. data/debian/control +22 -0
  23. data/debian/copyright +62 -0
  24. data/debian/docs +6 -0
  25. data/debian/manpage.1.ex +59 -0
  26. data/debian/patches/path.diff +91 -0
  27. data/debian/patches/series +1 -0
  28. data/debian/review.install +13 -0
  29. data/debian/review.links +4 -0
  30. data/debian/rules +13 -0
  31. data/debian/source/format +1 -0
  32. data/doc/format.rdoc +582 -0
  33. data/doc/format_idg.rdoc +180 -0
  34. data/doc/libepubmaker/sample.yaml +90 -0
  35. data/doc/quickstart.rdoc +188 -0
  36. data/doc/ruby-uuid/README +11 -0
  37. data/doc/ruby-uuid/README.ja +34 -0
  38. data/doc/sample.css +108 -0
  39. data/doc/sample.yaml +62 -0
  40. data/lib/epubmaker.rb +28 -0
  41. data/lib/epubmaker/content.rb +82 -0
  42. data/lib/epubmaker/epubv2.rb +418 -0
  43. data/lib/epubmaker/epubv3.rb +249 -0
  44. data/lib/epubmaker/producer.rb +204 -0
  45. data/lib/epubmaker/resource.rb +66 -0
  46. data/lib/lineinput.rb +155 -0
  47. data/lib/review.rb +3 -0
  48. data/lib/review/book.rb +46 -0
  49. data/lib/review/book/base.rb +235 -0
  50. data/lib/review/book/chapter.rb +81 -0
  51. data/lib/review/book/compilable.rb +159 -0
  52. data/lib/review/book/index.rb +339 -0
  53. data/lib/review/book/page_metric.rb +38 -0
  54. data/lib/review/book/parameters.rb +97 -0
  55. data/lib/review/book/part.rb +44 -0
  56. data/lib/review/book/volume.rb +65 -0
  57. data/lib/review/builder.rb +444 -0
  58. data/lib/review/compiler.rb +550 -0
  59. data/lib/review/configure.rb +38 -0
  60. data/lib/review/epubbuilder.rb +18 -0
  61. data/lib/review/exception.rb +21 -0
  62. data/lib/review/extentions.rb +3 -0
  63. data/lib/review/extentions/object.rb +9 -0
  64. data/lib/review/extentions/string.rb +33 -0
  65. data/lib/review/htmlbuilder.rb +1097 -0
  66. data/lib/review/htmllayout.rb +19 -0
  67. data/lib/review/htmlutils.rb +36 -0
  68. data/lib/review/i18n.rb +30 -0
  69. data/lib/review/i18n.yaml +34 -0
  70. data/lib/review/idgxmlbuilder.rb +1145 -0
  71. data/lib/review/latexbuilder.rb +815 -0
  72. data/lib/review/latexindex.rb +35 -0
  73. data/lib/review/latexutils.rb +79 -0
  74. data/lib/review/preprocessor.rb +563 -0
  75. data/lib/review/review.tex.erb +232 -0
  76. data/lib/review/textbuilder.rb +17 -0
  77. data/lib/review/textutils.rb +66 -0
  78. data/lib/review/tocparser.rb +342 -0
  79. data/lib/review/tocprinter.rb +221 -0
  80. data/lib/review/topbuilder.rb +785 -0
  81. data/lib/review/unfold.rb +138 -0
  82. data/lib/uuid.rb +312 -0
  83. data/review.gemspec +141 -0
  84. data/test/CHAPS +2 -0
  85. data/test/bib.re +13 -0
  86. data/test/book_test_helper.rb +35 -0
  87. data/test/test.re +43 -0
  88. data/test/test_book.rb +598 -0
  89. data/test/test_book_chapter.rb +418 -0
  90. data/test/test_book_parameter.rb +42 -0
  91. data/test/test_book_part.rb +50 -0
  92. data/test/test_builder.rb +144 -0
  93. data/test/test_compiler.rb +44 -0
  94. data/test/test_epubmaker.rb +507 -0
  95. data/test/test_helper.rb +27 -0
  96. data/test/test_htmlbuilder.rb +554 -0
  97. data/test/test_htmlutils.rb +28 -0
  98. data/test/test_i18n.rb +64 -0
  99. data/test/test_idgxmlbuilder.rb +589 -0
  100. data/test/test_index.rb +31 -0
  101. data/test/test_latexbuilder.rb +656 -0
  102. data/test/test_lineinput.rb +198 -0
  103. data/test/test_preprocessor.rb +23 -0
  104. data/test/test_textutils.rb +68 -0
  105. data/test/test_topbuilder.rb +244 -0
  106. data/test/test_uuid.rb +156 -0
  107. metadata +161 -0
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ #
4
+ # Copyright (c) 2010 Kenshi Muto and Masayoshi Takahashi
5
+ #
6
+ # This program is free software.
7
+ # You can distribute or modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ # For details of the GNU LGPL, see the file "COPYING".
10
+ #
11
+
12
+ require 'pathname'
13
+ bindir = Pathname.new(__FILE__).realpath.dirname
14
+ $LOAD_PATH.unshift((bindir + '../lib').realpath)
15
+ require 'review'
16
+ require 'epubmaker'
17
+ include EPUBMaker
18
+
19
+ def main
20
+ if ARGV.size != 1
21
+ puts "Usage: #{$0} configfile"
22
+ exit 0
23
+ end
24
+
25
+ yamlfile = ARGV[0]
26
+ @params = ReVIEW::Configure.values.merge(YAML.load_file(yamlfile))
27
+ @epub = Producer.new(@params)
28
+ @epub.load(yamlfile)
29
+ @params = @epub.params
30
+
31
+ bookname = @params["bookname"]
32
+
33
+ if File.exist?("#{bookname}.epub")
34
+ STDERR.puts "#{bookname}.epub exists. Please remove or rename it first."
35
+ exit 1
36
+ end
37
+ if @params["debug"] && File.exist?("#{bookname}")
38
+ STDERR.puts "#{bookname} debug directory exists. Please remove or rename it first."
39
+ exit 1
40
+ end
41
+
42
+ basetmp = Dir.mktmpdir
43
+
44
+ FileUtils.cp(@params["cover"], "#{basetmp}/#{@params["cover"]}") if !@params["cover"].nil? && File.exist?(@params["cover"])
45
+
46
+ if @params["titlepage"] # FIXME
47
+ FileUtils.cp(@params["titlepage"], "#{basetmp}/#{@params["titlepage"]}")
48
+ @epub.contents.push(Content.new("id" => "title", "file" => @params["titlepage"], "title" => @epub.res.v("titlepagetitle")))
49
+ end
50
+
51
+ makeBody(basetmp, yamlfile)
52
+
53
+ if @params["colophon"]
54
+ if @params["colophon"].instance_of?(String)
55
+ FileUtils.cp(@params["colophon"], "#{basetmp}/colophon.#{@params["htmlext"]}")
56
+ else
57
+ File.open("#{basetmp}/colophon.#{@params["htmlext"]}", "w") {|f| @epub.colophon(f) }
58
+ end
59
+ @epub.contents.push(Content.new("id" => "colophon", "file" => "colophon.#{@params["htmlext"]}", "title" => @epub.res.v("colophontitle")))
60
+ end
61
+
62
+ epubtmpdir = @params["debug"].nil? ? nil : "#{Dir.pwd}/#{bookname}"
63
+ unless @params["debug"].nil?
64
+ Dir.mkdir(bookname)
65
+ end
66
+ @epub.produce("#{bookname}.epub", basetmp, epubtmpdir)
67
+
68
+ FileUtils.rm_r(basetmp)
69
+ end
70
+
71
+ def makeBody(basetmp, yamlfile)
72
+ pre = 0
73
+ body = 0
74
+ post = 0
75
+ @manifeststr = ""
76
+ @ncxstr = ""
77
+ @tocdesc = Array.new
78
+ toccount = 2
79
+
80
+ if File.exists?("PREDEF")
81
+ File.open("PREDEF") do |chaps|
82
+ chaps.each_line do |l|
83
+ pre += 1
84
+ next if l =~ /\A#/
85
+ fork {
86
+ STDOUT.reopen("#{basetmp}/pre#{pre}.#{@params["htmlext"]}")
87
+ exec("review-compile --target=html --yaml=#{yamlfile} #{l}")
88
+ }
89
+ Process.waitall
90
+ getanchors(basetmp, "pre#{pre}.#{@params["htmlext"]}")
91
+ end
92
+ end
93
+ end
94
+
95
+ if File.exists?("CHAPS")
96
+ File.open("CHAPS") do |chaps|
97
+ chaps.each_line do |l|
98
+ body += 1
99
+ next if l =~ /\A#/
100
+ fork {
101
+ STDOUT.reopen("#{basetmp}/chap#{body}.#{@params["htmlext"]}")
102
+ exec("review-compile --target=html --yaml=#{yamlfile} #{l}")
103
+ }
104
+ Process.waitall
105
+ getanchors(basetmp, "chap#{body}.#{@params["htmlext"]}")
106
+ end
107
+ end
108
+ end
109
+
110
+ if File.exists?("POSTDEF")
111
+ File.open("POSTDEF") do |chaps|
112
+ chaps.each_line do |l|
113
+ post += 1
114
+ next if l =~ /^#/
115
+ fork {
116
+ STDOUT.reopen("#{basetmp}/post#{post}.#{@params["htmlext"]}")
117
+ exec("review-compile --target=html --yaml=#{yamlfile} #{l}")
118
+ }
119
+ Process.waitall
120
+ getanchors(basetmp, "post#{post}.#{@params["htmlext"]}")
121
+ end
122
+ end
123
+ end
124
+ if File.exist?("images")
125
+ Dir.mkdir("#{basetmp}/images")
126
+ copyImagesToDir("images", "#{basetmp}/images")
127
+ end
128
+ end
129
+
130
+ def getanchors(basetmp, filename)
131
+ File.open("#{basetmp}/#{filename}") do |f|
132
+ firsttime = true
133
+ f.each_line do |l|
134
+ if l =~ /\A<h(\d)><a id=\"(.+?)\" \/>(.+?)<\/h/
135
+ # level, ID, content
136
+ level = $1.to_i
137
+ id = $2
138
+ title = $3
139
+ if level == 1 && !firsttime.nil?
140
+ @epub.contents.push(Content.new({
141
+ "id" => "#{filename.sub(".#{@params["htmlext"]}", '')}",
142
+ "file" => "#{filename}",
143
+ "level" => level,
144
+ "title" => title
145
+ }))
146
+ firsttime = nil
147
+ else
148
+ @epub.contents.push(Content.new({
149
+ "id" => "#{filename.sub(".#{@params["htmlext"]}", '')}-#{id}",
150
+ "file" => "#{filename}##{id}",
151
+ "level" => level,
152
+ "title" => title
153
+ }))
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ def copyImagesToDir(dirname, copybase)
161
+ Dir.open(dirname) do |dir|
162
+ dir.each do |fname|
163
+ next if fname =~ /\A\./
164
+ if FileTest.directory?("#{dirname}/#{fname}")
165
+ copyImagesToDir("#{dirname}/#{fname}", "#{copybase}/#{fname}")
166
+ else
167
+ if fname =~ /\.(png|gif|jpg|jpeg|svg)\Z/i
168
+ Dir.mkdir(copybase) unless File.exist?(copybase)
169
+ FileUtils.cp "#{dirname}/#{fname}", copybase
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ main
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #
4
+ # Copyright (c) 1999-2007 Minero Aoki
5
+ # 2008-2010 Minero Aoki, Kenshi Muto
6
+ #
7
+ # This program is free software.
8
+ # You can distribute or modify this program under the terms of
9
+ # the GNU LGPL, Lesser General Public License version 2.1.
10
+ # For details of the GNU LGPL, see the file "COPYING".
11
+ #
12
+
13
+ require 'pathname'
14
+
15
+ bindir = Pathname.new(__FILE__).realpath.dirname
16
+ $LOAD_PATH.unshift((bindir + '../lib').realpath)
17
+
18
+ require 'review/book'
19
+ require 'review/tocparser'
20
+ require 'review/tocprinter'
21
+ require 'optparse'
22
+
23
+ def main
24
+ Signal.trap(:INT) { exit 1 }
25
+ if RUBY_PLATFORM !~ /mswin(?!ce)|mingw|cygwin|bccwin/
26
+ Signal.trap(:PIPE, 'IGNORE')
27
+ end
28
+ _main
29
+ rescue Errno::EPIPE
30
+ exit 0
31
+ end
32
+
33
+ def _main
34
+ $KCODE = 'UTF-8' unless defined?(Encoding)
35
+
36
+ printer_class = ReVIEW::TextTOCPrinter
37
+ source = nil
38
+ upper = ReVIEW::TOCPrinter.default_upper_level
39
+ param = {
40
+ "inencoding" => "UTF-8",
41
+ "outencoding" => "UTF-8"
42
+ }
43
+
44
+ parser = OptionParser.new
45
+ parser.on('--inencoding=ENCODING', 'Set input encoding. (UTF-8, EUC, JIS, and SJIS)') {|enc|
46
+ param["inencoding"] = enc
47
+ }
48
+ parser.on('--outencoding=ENCODING', 'Set output encoding. (UTF-8[default], EUC, JIS, and SJIS)') {|enc|
49
+ param["outencoding"] = enc
50
+ }
51
+ parser.on('-a', '--all', 'print all chapters.') {
52
+ begin
53
+ source = ReVIEW.book
54
+ rescue ReVIEW::Error => err
55
+ error_exit err.message
56
+ end
57
+ }
58
+ parser.on('-p', '--part N', 'list only part N.') {|n|
59
+ source = ReVIEW.book.part(Integer(n)) or
60
+ error_exit "part #{n} does not exist in this book"
61
+ }
62
+ parser.on('-c', '--chapter C', 'list only chapter C.') {|c|
63
+ begin
64
+ source = ReVIEW::Book::Part.new(nil, 1, [ReVIEW.book.chapter(c)])
65
+ rescue
66
+ error_exit "chapter #{c} does not exist in this book"
67
+ end
68
+ }
69
+ parser.on('-l', '--level N', 'list upto N level (1..4, default=4)') {|n|
70
+ upper = Integer(n)
71
+ unless (0..4).include?(upper) # 0 is hidden option
72
+ $stderr.puts "-l/--level option accepts only 1..4"
73
+ exit 1
74
+ end
75
+ }
76
+ parser.on('--text', 'output in plain text (default)') {
77
+ printer_class = ReVIEW::TextTOCPrinter
78
+ }
79
+ parser.on('--html', 'output in HTML (deprecated)') {
80
+ printer_class = ReVIEW::HTMLTOCPrinter
81
+ }
82
+ parser.on('--idg', 'output in InDesign XML') {
83
+ printer_class = ReVIEW::IDGTOCPrinter
84
+ }
85
+ parser.on('--help', 'print this message and quit.') {
86
+ puts parser.help
87
+ exit 0
88
+ }
89
+ begin
90
+ parser.parse!
91
+ rescue OptionParser::ParseError => err
92
+ $stderr.puts err.message
93
+ $stderr.puts parser.help
94
+ exit 1
95
+ end
96
+ if source
97
+ unless ARGV.empty?
98
+ error_exit '-a/-s option and file arguments are exclusive'
99
+ end
100
+ else
101
+ puts parser.help
102
+ exit 0
103
+ end
104
+
105
+ begin
106
+ printer_class.new(upper, param).print_book source
107
+ rescue ReVIEW::Error, Errno::ENOENT => err
108
+ raise if $DEBUG
109
+ error_exit err.message
110
+ end
111
+ end
112
+
113
+ def error_exit(msg)
114
+ $stderr.puts "#{File.basename($0)}: #{msg}"
115
+ exit 1
116
+ end
117
+
118
+ main
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ #
4
+ # Copyright (c) 2010 Kenshi Muto and Masayoshi Takahashi
5
+ #
6
+ # This program is free software.
7
+ # You can distribute or modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ # For details of the GNU LGPL, see the file "COPYING".
10
+ #
11
+
12
+ require 'tmpdir'
13
+ require 'yaml'
14
+ require 'fileutils'
15
+ require 'erb'
16
+
17
+ require 'pathname'
18
+ bindir = Pathname.new(__FILE__).realpath.dirname
19
+ $LOAD_PATH.unshift((bindir + '../lib').realpath)
20
+
21
+ require 'review'
22
+
23
+ def error(msg)
24
+ $stderr.puts "#{File.basename($0, '.*')}: error: #{msg}"
25
+ exit 1
26
+ end
27
+
28
+ def usage
29
+ $stderr.puts "Usage: #{$0} configfile"
30
+ exit 0
31
+ end
32
+
33
+ def check_book(values)
34
+ pdf_file = values["bookname"]+".pdf"
35
+ if File.exists? pdf_file
36
+ error "file already exists:#{pdf_file}"
37
+ end
38
+ end
39
+
40
+ def build_path(values)
41
+ if values["debug"].nil?
42
+ Dir.mktmpdir+"/#{values["bookname"]}-pdf"
43
+ else
44
+ "./#{values["bookname"]}-pdf"
45
+ end
46
+ end
47
+
48
+ def main
49
+ usage if ARGV.size != 1
50
+
51
+ yamlfile = ARGV[0]
52
+ values = ReVIEW::Configure.values.merge(YAML.load_file(yamlfile))
53
+ check_book(values)
54
+ @basedir = Dir.pwd
55
+ @path = build_path(values)
56
+ bookname = values["bookname"]
57
+ Dir.mkdir(@path)
58
+
59
+ @chaps_fnames = Hash.new{|h, key| h[key] = ""}
60
+
61
+ ReVIEW::Book.load(@basedir).parts.each do |part|
62
+ if part.name.present?
63
+ if part.file?
64
+ filename = "#{File.basename(part.path, ".*")}.tex"
65
+ output_chaps(filename, values)
66
+ @chaps_fnames["CHAPS"] << %Q|\\input{#{filename}}\n|
67
+ else
68
+ @chaps_fnames["CHAPS"] << %Q|\\part{#{part.name}}\n|
69
+ end
70
+ end
71
+
72
+ part.chapters.each do |chap|
73
+ filename = "#{File.basename(chap.path, ".*")}.tex"
74
+ output_chaps(filename, values)
75
+ @chaps_fnames["PREDEF"] << "\\input{#{filename}}\n" if chap.on_PREDEF?
76
+ @chaps_fnames["CHAPS"] << "\\input{#{filename}}\n" if chap.on_CHAPS?
77
+ @chaps_fnames["POSTDEF"] << "\\input{#{filename}}\n" if chap.on_POSTDEF?
78
+ end
79
+ end
80
+
81
+ values["pre_str"] = @chaps_fnames["PREDEF"]
82
+ values["chap_str"] = @chaps_fnames["CHAPS"]
83
+ values["post_str"] = @chaps_fnames["POSTDEF"]
84
+
85
+ values["usepackage"] = ""
86
+ if values["texstyle"]
87
+ values["usepackage"] = "\\usepackage{#{values['texstyle']}}"
88
+ end
89
+
90
+ copy_images("./images", "#{@path}/images")
91
+ copyStyToDir(Dir.pwd + "/sty", @path)
92
+ copyStyToDir(Dir.pwd, @path, "tex")
93
+
94
+ Dir.chdir(@path) {
95
+ template = get_template(values)
96
+ File.open("./book.tex", "wb"){|f| f.write(template)}
97
+
98
+ ## do compile
99
+ enc = values["params"].to_s.split(/\s+/).find{|i| i =~ /\A--outencoding=/ }
100
+ kanji = enc ? enc.split(/=/).last.gsub(/-/, '').downcase : 'utf8'
101
+ fork {
102
+ exec("platex -kanji=#{kanji} book.tex")
103
+ }
104
+ Process.waitall
105
+ fork {
106
+ exec("platex -kanji=#{kanji} book.tex")
107
+ }
108
+ Process.waitall
109
+ fork {
110
+ exec("platex -kanji=#{kanji} book.tex")
111
+ }
112
+ Process.waitall
113
+ fork {
114
+ exec("dvipdfmx -d 5 book.dvi")
115
+ }
116
+ Process.waitall
117
+ }
118
+ FileUtils.cp("#{@path}/book.pdf", "#{@basedir}/#{bookname}.pdf")
119
+ end
120
+
121
+ def output_chaps(filename, values)
122
+ fork {
123
+ STDOUT.reopen("#{@path}/#{filename}")
124
+ $stderr.puts "compiling #{filename}"
125
+ exec("review-compile --target=latex --level=#{values["secnolevel"]} --toclevel=#{values["toclevel"]} #{values["params"]} #{filename}")
126
+ }
127
+ Process.waitall
128
+ end
129
+
130
+ def copy_images(from, to)
131
+ if File.exist?(from)
132
+ Dir.mkdir(to)
133
+ ReVIEW::MakerHelper.copy_images_to_dir(from, to)
134
+ Dir.chdir(to) {
135
+ fork {
136
+ begin
137
+ exec("extractbb *.png *.jpg *.pdf */*.jpg */*.png */*.pdf;extractbb -m *.png *.jpg *.pdf */*.jpg */*.png */*.pdf")
138
+ rescue
139
+ exec("ebb *.png *.jpg *.pdf */*.jpg */*.png */*.pdf")
140
+ end
141
+ }
142
+ }
143
+ Process.waitall
144
+ end
145
+ end
146
+
147
+ def make_custom_titlepage(coverfile)
148
+ coverfile_sty = coverfile.to_s.sub(/\.[^.]+$/, ".tex")
149
+ if File.exist?(coverfile_sty)
150
+ File.read(coverfile_sty)
151
+ else
152
+ nil
153
+ end
154
+ end
155
+
156
+ def get_template(values)
157
+ dclass = values["texdocumentclass"] || []
158
+ documentclass = dclass[0] || "jsbook"
159
+ documentclassoption = dclass[1] || "oneside"
160
+
161
+ okuduke = ""
162
+ authors = ""
163
+ if values["aut"]
164
+ okuduke += "著 者 & #{values["aut"]} \\\\\n"
165
+ authors = values["aut"]+ "\\vspace*{1zh} 著"
166
+ end
167
+ if values["trl"]
168
+ authors += " \\\\\n"+values["trl"]+ "\\vspace*{1zh} 訳"
169
+ okuduke += "翻 訳 & #{values["trl"]} \\\\\n"
170
+ end
171
+ if values["edt"]
172
+ okuduke += "編集者 & #{values["edt"]} \\\\\n"
173
+ end
174
+ okuduke += <<EOB
175
+ 発行所 & #{values["prt"]} \\\\
176
+ EOB
177
+
178
+ custom_titlepage = make_custom_titlepage(values["coverfile"])
179
+
180
+ template = File.expand_path(File.dirname(__FILE__) +
181
+ '/../lib/review/review.tex.erb')
182
+ layout_file = File.join(@basedir, "layouts", "layout.tex.erb")
183
+ if File.exists?(layout_file)
184
+ template = layout_file
185
+ end
186
+
187
+ erb = ERB.new(File.open(template).read)
188
+ erb.result(binding)
189
+ end
190
+
191
+ def copyStyToDir(dirname, copybase, extname = "sty")
192
+ unless File.directory?(dirname)
193
+ $stderr.puts "No such directory - #{dirname}"
194
+ return
195
+ end
196
+
197
+ Dir.open(dirname) {|dir|
198
+ dir.each {|fname|
199
+ next if fname =~ /^\./
200
+ if fname =~ /\.(#{extname})$/i
201
+ Dir.mkdir(copybase) unless File.exist?(copybase)
202
+ FileUtils.cp "#{dirname}/#{fname}", copybase
203
+ end
204
+ }
205
+ }
206
+ end
207
+
208
+ main