review-retrovert 0.3.3 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/retrovert.yml +39 -0
  3. data/.gitignore +2 -2
  4. data/.ruby-version +1 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +67 -1
  7. data/README.md +6 -3
  8. data/lib/review/retrovert/converter.rb +231 -6
  9. data/lib/review/retrovert/version.rb +1 -1
  10. data/review-retrovert.gemspec +1 -1
  11. data/testdata/mybook/.gitignore +7 -0
  12. data/testdata/mybook/README.md +43 -0
  13. data/testdata/mybook/Rakefile +16 -0
  14. data/testdata/mybook/catalog.yml +33 -0
  15. data/testdata/mybook/config-starter.yml +139 -0
  16. data/testdata/mybook/config.yml +375 -0
  17. data/testdata/mybook/contents/00-preface.re +83 -0
  18. data/testdata/mybook/contents/01-install.re +272 -0
  19. data/testdata/mybook/contents/02-tutorial.re +1008 -0
  20. data/testdata/mybook/contents/03-syntax.re +2613 -0
  21. data/testdata/mybook/contents/04-customize.re +728 -0
  22. data/testdata/mybook/contents/05-faq.re +328 -0
  23. data/testdata/mybook/contents/06-bestpractice.re +971 -0
  24. data/testdata/mybook/contents/91-compare.re +18 -0
  25. data/testdata/mybook/contents/92-filelist.re +119 -0
  26. data/testdata/mybook/contents/93-background.re +267 -0
  27. data/testdata/mybook/contents/99-postface.re +38 -0
  28. data/testdata/mybook/css/normalize.css +349 -0
  29. data/testdata/mybook/css/webstyle.css +514 -0
  30. data/testdata/mybook/images/03-syntax/favicon-16x16.png +0 -0
  31. data/testdata/mybook/images/03-syntax/figure_heretop.png +0 -0
  32. data/testdata/mybook/images/03-syntax/tw-icon1.jpg +0 -0
  33. data/testdata/mybook/images/03-syntax/tw-icon2.jpg +0 -0
  34. data/testdata/mybook/images/03-syntax/tw-icon3.jpg +0 -0
  35. data/testdata/mybook/images/03-syntax/tw-icon4.jpg +0 -0
  36. data/testdata/mybook/images/04-customize/caption_pagebreak.png +0 -0
  37. data/testdata/mybook/images/04-customize/chaptitlepage_sample.png +0 -0
  38. data/testdata/mybook/images/05-faq/codeblock_rpadding1.png +0 -0
  39. data/testdata/mybook/images/05-faq/codeblock_rpadding2.png +0 -0
  40. data/testdata/mybook/images/06-bestpractice/figure_heretop.png +0 -0
  41. data/testdata/mybook/images/06-bestpractice/font_beramono.png +0 -0
  42. data/testdata/mybook/images/06-bestpractice/heading_design1.png +0 -0
  43. data/testdata/mybook/images/06-bestpractice/heading_design2.png +0 -0
  44. data/testdata/mybook/images/06-bestpractice/margin_book.png +0 -0
  45. data/testdata/mybook/images/06-bestpractice/multiline-title.png +0 -0
  46. data/testdata/mybook/images/06-bestpractice/preface_numbered.png +0 -0
  47. data/testdata/mybook/images/06-bestpractice/program_border.png +0 -0
  48. data/testdata/mybook/images/06-bestpractice/sechead_design_4.png +0 -0
  49. data/testdata/mybook/images/06-bestpractice/titlepage-samples.png +0 -0
  50. data/testdata/mybook/images/93-background/bug913.png +0 -0
  51. data/testdata/mybook/images/93-background/slide2.png +0 -0
  52. data/testdata/mybook/images/cover_a5.pdf +0 -0
  53. data/testdata/mybook/images/cover_b5.pdf +0 -0
  54. data/testdata/mybook/images/tw-icon.jpg +0 -0
  55. data/testdata/mybook/layouts/layout.epub.erb +29 -0
  56. data/testdata/mybook/layouts/layout.html5.erb +106 -0
  57. data/testdata/mybook/layouts/layout.tex.erb +546 -0
  58. data/testdata/mybook/lib/hooks/beforetexcompile.rb +55 -0
  59. data/testdata/mybook/lib/ruby/review-builder.rb +503 -0
  60. data/testdata/mybook/lib/ruby/review-cli.rb +58 -0
  61. data/testdata/mybook/lib/ruby/review-compiler.rb +523 -0
  62. data/testdata/mybook/lib/ruby/review-epubmaker.rb +606 -0
  63. data/testdata/mybook/lib/ruby/review-htmlbuilder.rb +661 -0
  64. data/testdata/mybook/lib/ruby/review-latexbuilder.rb +782 -0
  65. data/testdata/mybook/lib/ruby/review-maker.rb +235 -0
  66. data/testdata/mybook/lib/ruby/review-monkeypatch.rb +91 -0
  67. data/testdata/mybook/lib/ruby/review-pdfmaker.rb +468 -0
  68. data/testdata/mybook/lib/ruby/review-textbuilder.rb +36 -0
  69. data/testdata/mybook/lib/ruby/review-tocparser.rb +285 -0
  70. data/testdata/mybook/lib/ruby/review-webmaker.rb +433 -0
  71. data/testdata/mybook/lib/tasks/mytasks.rake +31 -0
  72. data/testdata/mybook/lib/tasks/review.rake +142 -0
  73. data/testdata/mybook/lib/tasks/review.rake.orig +72 -0
  74. data/testdata/mybook/lib/tasks/starter.rake +326 -0
  75. data/testdata/mybook/locale.yml +6 -0
  76. data/testdata/mybook/review-ext.rb +206 -0
  77. data/testdata/mybook/sty/jumoline.sty +310 -0
  78. data/testdata/mybook/sty/mycolophon.sty +81 -0
  79. data/testdata/mybook/sty/mystyle.sty +8 -0
  80. data/testdata/mybook/sty/mytextsize.sty +61 -0
  81. data/testdata/mybook/sty/mytitlepage.sty +103 -0
  82. data/testdata/mybook/sty/reviewmacro.sty +60 -0
  83. data/testdata/mybook/sty/starter-codeblock.sty +332 -0
  84. data/testdata/mybook/sty/starter-color.sty +79 -0
  85. data/testdata/mybook/sty/starter-font.sty +112 -0
  86. data/testdata/mybook/sty/starter-heading.sty +514 -0
  87. data/testdata/mybook/sty/starter-note.sty +127 -0
  88. data/testdata/mybook/sty/starter-section.sty +262 -0
  89. data/testdata/mybook/sty/starter-toc.sty +72 -0
  90. data/testdata/mybook/sty/starter.sty +554 -0
  91. data/testdata/mybook/style.css +597 -0
  92. metadata +100 -3
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ##
4
+ ## これはreviewstarterが用意したファイル。
5
+ ## ユーザ独自のRakeタスクをここに定義する。
6
+ ##
7
+
8
+
9
+ #
10
+ #def render_eruby_files(param) # 要 Ruby >= 2.2
11
+ # Dir.glob('**/*.eruby').each do |erubyfile|
12
+ # origfile = erubyfile.sub(/\.eruby$/, '')
13
+ # sh "erb -T 2 '#{param}' #{erubyfile} > #{origfile}"
14
+ # end
15
+ #end
16
+ #
17
+ #
18
+ #namespace :setup do
19
+ #
20
+ # desc "*印刷用に設定 (B5, 10pt, mono)"
21
+ # task :printing do
22
+ # render_eruby_files('buildmode=printing')
23
+ # end
24
+ #
25
+ # desc "*タブレット用に設定 (A5, 10pt, color)"
26
+ # task :tablet do
27
+ # render_eruby_files('buildmode=tablet')
28
+ # end
29
+ #
30
+ #end
31
+ #
@@ -0,0 +1,142 @@
1
+ require 'fileutils'
2
+ require 'rake/clean'
3
+
4
+ BOOK = 'book'
5
+ BOOK_PDF = BOOK + '.pdf'
6
+ BOOK_EPUB = BOOK + '.epub'
7
+ CONFIG_FILE = 'config.yml'
8
+ WEBROOT = 'webroot'
9
+
10
+ def build(mode, chapter)
11
+ sh "review-compile --target=#{mode} --footnotetext --stylesheet=style.css #{chapter} > tmp"
12
+ mode_ext = { 'html' => 'html', 'latex' => 'tex', 'idgxml' => 'xml' }
13
+ FileUtils.mv 'tmp', chapter.gsub(/re\z/, mode_ext[mode])
14
+ end
15
+
16
+ def build_all(mode)
17
+ sh "review-compile --target=#{mode} --footnotetext --stylesheet=style.css"
18
+ end
19
+
20
+ def config_file()
21
+ conf = ENV['config']
22
+ conf = CONFIG_FILE if conf.nil? || conf.empty?
23
+ return conf
24
+ end
25
+
26
+ task default: :html_all
27
+
28
+ desc 'build html (Usage: rake build re=target.re)'
29
+ task :html => :prepare do
30
+ if ENV['re'].nil?
31
+ puts 'Usage: rake build re=target.re'
32
+ exit
33
+ end
34
+ build('html', ENV['re'])
35
+ end
36
+
37
+ desc 'build all html'
38
+ task :html_all => :prepare do
39
+ build_all('html')
40
+ end
41
+
42
+ desc 'preproc all'
43
+ task :preproc => :prepare do
44
+ Dir.glob('*.re').each do |file|
45
+ sh "review-preproc --replace #{file}"
46
+ end
47
+ end
48
+
49
+ desc 'generate PDF and EPUB file'
50
+ task all: %i[pdf epub]
51
+
52
+ desc 'generate PDF file'
53
+ task :pdf => :prepare do
54
+ require 'review'
55
+ #require 'review/pdfmaker'
56
+ require './lib/ruby/review-pdfmaker'
57
+ #
58
+ FileUtils.rm_rf [BOOK_PDF, BOOK, BOOK + '-pdf']
59
+ begin
60
+ ReVIEW::PDFMaker.execute(config_file())
61
+ rescue RuntimeError => ex
62
+ if ex.message =~ /^failed to run command:/
63
+ abort "*\n* ERROR (review-pdfmaker):\n* #{ex.message}\n*"
64
+ else
65
+ raise
66
+ end
67
+ end
68
+ end
69
+
70
+ desc 'generate EPUB file'
71
+ task :epub => :prepare do
72
+ FileUtils.rm_rf [BOOK_EPUB, BOOK, BOOK + '-epub']
73
+ #sh "review-epubmaker #{config_file()}"
74
+ require 'review'
75
+ require './lib/ruby/review-epubmaker'
76
+ ReVIEW::EpubMaker.execute(config_file())
77
+ end
78
+
79
+ desc 'generate stagic HTML file for web'
80
+ task :web => :prepare do
81
+ FileUtils.rm_rf [WEBROOT]
82
+ #sh "review-webmaker #{config_file()}"
83
+ require 'review'
84
+ #require 'review/webmaker'
85
+ require './lib/ruby/review-webmaker'
86
+ ReVIEW::WEBMaker.execute(config_file())
87
+ end
88
+
89
+
90
+ #desc "+ copy *.re files under 'contents/' into here."
91
+ task :prepare do
92
+ require 'yaml'
93
+ config = YAML.load_file(config_file())
94
+ PREPARES.each do |x|
95
+ case x
96
+ when Proc; x.call(config)
97
+ else ; __send__(x, config)
98
+ end
99
+ end
100
+ end
101
+
102
+ ## 前処理を追加したい場合は、関数名またはProcオブジェクトをこの配列に追加する
103
+ PREPARES = [:copy_files_under_contentdir]
104
+
105
+ def copy_files_under_contentdir(config)
106
+ ## 設定ファイル (config.yml) の「contentdir:」の値を調べる
107
+ contdir = config['contentdir']
108
+ if contdir && contdir != '.' # '.' はカレントディレクトリを表すので対象外
109
+ ## もし contentdir が存在しなければエラー
110
+ unless File.directory?(contdir)
111
+ abort_with_message <<END
112
+ ERROR: Content directory '#{contdir}' not exist.
113
+ Please check 'contentdir:' value in config file,
114
+ or create '#{contdir}' directory and put *.re files into there.
115
+ END
116
+ end
117
+ ## カレントディレクトリに *.re ファイルがあればエラー
118
+ unless Dir.glob('*.re').empty?
119
+ re_file = Dir.glob('*.re').sort.first
120
+ abort_with_message <<END
121
+ ERROR: File '#{re_file}' found in current directory.
122
+ When 'contentdir:' specifieid in config file,
123
+ you must put all *.re files into that directory.
124
+ Please remove *.re files from current directory.
125
+ END
126
+ end
127
+ ## contentdir にある *.re ファイルをカレントディレクトリにコピー
128
+ cp Dir.glob(File.join(contdir, '*.re')), '.', :verbose=>false
129
+ ## コピーしたファイルをRakeプロセス終了時に削除
130
+ at_exit { rm_f Dir.glob('*.re'), :verbose=>false }
131
+ end
132
+ end
133
+
134
+ def abort_with_message(error_msg)
135
+ $stderr.puts "***"
136
+ $stderr.puts error_msg.gsub(/^/, '*** ')
137
+ $stderr.puts "***"
138
+ abort()
139
+ end
140
+
141
+
142
+ CLEAN.include([BOOK, BOOK_PDF, BOOK_EPUB, BOOK + '-pdf', BOOK + '-epub', WEBROOT, 'images/_review_math'])
@@ -0,0 +1,72 @@
1
+ require 'fileutils'
2
+ require 'rake/clean'
3
+
4
+ BOOK = 'book'
5
+ BOOK_PDF = BOOK + '.pdf'
6
+ BOOK_EPUB = BOOK + '.epub'
7
+ CONFIG_FILE = 'config.yml'
8
+ WEBROOT = 'webroot'
9
+
10
+ def build(mode, chapter)
11
+ sh "review-compile --target=#{mode} --footnotetext --stylesheet=style.css #{chapter} > tmp"
12
+ mode_ext = { 'html' => 'html', 'latex' => 'tex', 'idgxml' => 'xml' }
13
+ FileUtils.mv 'tmp', chapter.gsub(/re\z/, mode_ext[mode])
14
+ end
15
+
16
+ def build_all(mode)
17
+ sh "review-compile --target=#{mode} --footnotetext --stylesheet=style.css"
18
+ end
19
+
20
+ task default: :html_all
21
+
22
+ desc 'build html (Usage: rake build re=target.re)'
23
+ task :html do
24
+ if ENV['re'].nil?
25
+ puts 'Usage: rake build re=target.re'
26
+ exit
27
+ end
28
+ build('html', ENV['re'])
29
+ end
30
+
31
+ desc 'build all html'
32
+ task :html_all do
33
+ build_all('html')
34
+ end
35
+
36
+ desc 'preproc all'
37
+ task :preproc do
38
+ Dir.glob('*.re').each do |file|
39
+ sh "review-preproc --replace #{file}"
40
+ end
41
+ end
42
+
43
+ desc 'generate PDF and EPUB file'
44
+ task all: %i[pdf epub]
45
+
46
+ desc 'generate PDF file'
47
+ task pdf: BOOK_PDF
48
+
49
+ desc 'generate stagic HTML file for web'
50
+ task web: WEBROOT
51
+
52
+ desc 'generate EPUB file'
53
+ task epub: BOOK_EPUB
54
+
55
+ SRC = FileList['*.re'] + [CONFIG_FILE]
56
+
57
+ file BOOK_PDF => SRC do
58
+ FileUtils.rm_rf [BOOK_PDF, BOOK, BOOK + '-pdf']
59
+ sh "review-pdfmaker #{CONFIG_FILE}"
60
+ end
61
+
62
+ file BOOK_EPUB => SRC do
63
+ FileUtils.rm_rf [BOOK_EPUB, BOOK, BOOK + '-epub']
64
+ sh "review-epubmaker #{CONFIG_FILE}"
65
+ end
66
+
67
+ file WEBROOT => SRC do
68
+ FileUtils.rm_rf [WEBROOT]
69
+ sh "review-webmaker #{CONFIG_FILE}"
70
+ end
71
+
72
+ CLEAN.include([BOOK, BOOK_PDF, BOOK_EPUB, BOOK + '-pdf', BOOK + '-epub', WEBROOT, 'images/_review_math'])
@@ -0,0 +1,326 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ WEBSERVER_PORT = 9000
5
+
6
+
7
+ ##
8
+ ## 生成したファイルを削除
9
+ ##
10
+ task :clean do
11
+ require 'yaml'
12
+ config = File.open("config.yml", 'r', encoding: 'utf-8') {|f| YAML.load(f) }
13
+ x = config['bookname'] or abort("ERROR: missing 'bookname' in config.yml")
14
+ files = [x+".pdf", x+"-pdf", x+".epub", x+"-epub", "webroot"]
15
+ files = files.select {|x| File.exist?(x) }
16
+ rm_rf files unless files.empty?
17
+ end
18
+
19
+
20
+
21
+ ##
22
+ ## Docker用のタスク。
23
+ ##
24
+ namespace :docker do
25
+
26
+ docker_image = ENV['DOCKER_IMAGE']
27
+ docker_image = "kauplan/review2.5" if docker_image.to_s.empty?
28
+ docker_opts = "--rm -v $PWD:/work -w /work"
29
+ docker_opts += ENV.keys().grep(/^STARTER_/).map {|k| " -e #{k}" }.join()
30
+
31
+ desc "+ pull docker image for building PDF file"
32
+ task :setup do
33
+ sh "docker pull #{docker_image}"
34
+ end
35
+
36
+ docker_run = proc do |command, opt=nil|
37
+ sh "docker run #{docker_opts} #{opt} #{docker_image} #{command}"
38
+ end
39
+
40
+ desc "+ run 'rake pdf' on docker"
41
+ task :pdf do docker_run.call('rake pdf') end
42
+
43
+ desc "+ run 'rake pdf:nombre' on docker"
44
+ task :'pdf:nombre' do docker_run.call('rake pdf:nombre') end
45
+
46
+ desc "+ run 'rake epub' on docker"
47
+ task :epub do docker_run.call('rake epub') end
48
+
49
+ desc "+ run 'rake web' on docker"
50
+ task :web do docker_run.call('rake web') end
51
+
52
+ desc "+ run 'rake web:server' on docker"
53
+ task :'web:server' do
54
+ port = WEBSERVER_PORT
55
+ opt = "-it -p #{port}:#{port+1} -e WEBSERVER_PORT=#{port+1}"
56
+ docker_run.call('rake web:server', opt)
57
+ end
58
+
59
+ end
60
+
61
+
62
+ ##
63
+ ## PDFにノンブルを入れるためのRakeタスク。
64
+ ## ノンブルについては「ワンストップ!技術同人誌を書こう」第10章を参照のこと。
65
+ ## https://booth.pm/ja/items/708196
66
+ ##
67
+ namespace :pdf do
68
+
69
+ desc "+ add nombre (rake pdf:nombre [file=*.pdf] [out=*.pdf])"
70
+ task :nombre do
71
+ infile = ENV['file']; infile = nil if infile && infile.empty?
72
+ outfile = ENV['out'] ; outfile = nil if outfile && outfile.empty?
73
+ #
74
+ begin
75
+ require 'combine_pdf'
76
+ rescue LoadError
77
+ abort "ERROR: 'combine_pdf' gem not installed; please run `gem install combine_pdf` at first."
78
+ end
79
+ #
80
+ class CombinePDF::PDF
81
+ def add_nombre(options={})
82
+ start = options[:start] || 1
83
+ margin_h = options[:margin_h] || 5
84
+ margin_w = options[:margin_w] || 2
85
+ font = options[:font] || :Helvetica
86
+ size = options[:size] || 6
87
+ color = options[:color] || [0.5, 0.5, 0.5] # gray
88
+ binding = options[:binding] || :left
89
+ digit_w, digit_h = CombinePDF::Fonts.dimensions_of("9", font, size)
90
+ box_w = digit_w * 1.2
91
+ box_h = digit_h * 1.3
92
+ is_left = binding == :left
93
+ params = {
94
+ x: nil, y: nil, width: box_w, height: box_h,
95
+ font: font, font_size: size, font_color: color,
96
+ }
97
+ self.pages.each.with_index(start) do |page, page_num|
98
+ mediabox = page[:CropBox] || page[:MediaBox] or
99
+ abort "ERROR: failed to get page size of pdf"
100
+ page_w = mediabox[2]
101
+ page_h = mediabox[3]
102
+ top = page_h - margin_h
103
+ bottom = margin_h
104
+ left = margin_w
105
+ right = page_w - margin_w - box_w
106
+ params[:x] = is_left ? left : right
107
+ params[:y] = bottom
108
+ page_num.to_s.reverse.each_char do |c|
109
+ page.textbox(c, params)
110
+ params[:y] += box_h
111
+ end
112
+ is_left = ! is_left
113
+ end
114
+ self
115
+ end
116
+ end
117
+ #
118
+ if infile.nil?
119
+ require 'yaml'
120
+ config = File.open("config.yml", 'r', encoding: 'utf-8') {|f| YAML.load(f) }
121
+ bookname = config['bookname'] or abort("ERROR: missing 'bookname' in config.yml")
122
+ infile = bookname + ".pdf"
123
+ end
124
+ File.file?(infile) or abort("ERROR: #{infile}: pdf file not found.")
125
+ if outfile.nil?
126
+ #outfile = infile.sub(/\.pdf$/, '_nombre.pdf')
127
+ outfile = infile
128
+ end
129
+ #
130
+ #pdf = CombinePDF.parse(File.binread(infile))
131
+ #pdf.add_nombre()
132
+ #File.binwrite(outfile, pdf.to_pdf())
133
+ pdf = CombinePDF.load(infile)
134
+ pdf.add_nombre()
135
+ pdf.save(outfile)
136
+ end
137
+
138
+ end
139
+
140
+
141
+ ##
142
+ ## プレビュー用のサーバを起動する
143
+ ##
144
+ namespace :web do
145
+
146
+ invoke_web_task = proc do
147
+ #sh "rake web"
148
+ Process.fork { Rake::Task['web'].invoke() }
149
+ Process.wait()
150
+ end
151
+
152
+ helper_message_when_start_server = <<END
153
+ *
154
+ * Please open http://localhost:#{WEBSERVER_PORT}/ in browser.
155
+ *
156
+ END
157
+
158
+ helper_message_when_address_already_in_use = <<END
159
+ **
160
+ ** ERROR: Failed to start web server.
161
+ **
162
+ ** Other webserver process seems running. Kill it and restart webserver.
163
+ **
164
+ ** How to:
165
+ ** $ ps | head -1; ps | grep web[:]server
166
+ ** PID TTY TIME CMD
167
+ ** 12345 ttys002 0.00.35 /usr/bin/ruby /usr/bin/rake web:server
168
+ ** $ kill -KILL 12345
169
+ ** $ rake web:server
170
+ **
171
+ END
172
+
173
+ favicon_base64 = <<END
174
+ AAABAAEAEBACAAEAAQCwAAAAFgAAACgAAAAQAAAAIAAAAAEAAQAAAAAAgAAA
175
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAA
176
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/
177
+ /wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//
178
+ AAD//wAA//8AAP//AAD//wAA
179
+ END
180
+
181
+ desc "+ start web server for preview"
182
+ task :server do
183
+ rebuild_js = (ENV['STARTER_REBUILD_JS'] ||= '/rebuild.js')
184
+ invoke_web_task.call()
185
+ #
186
+ require 'yaml'
187
+ config = File.open('config.yml') {|f| YAML.load(f) }
188
+ contdir = config['contentdir']
189
+ #
190
+ require 'webrick'
191
+ root = 'webroot/'
192
+ host = '0.0.0.0' # don't use '127.0.0.1' to work on Docker
193
+ port = ENV['WEBSERVER_PORT'] ? ENV['WEBSERVER_PORT'].to_i : WEBSERVER_PORT
194
+ onstart = proc { puts helper_message_when_start_server }
195
+ srvconf = {DocumentRoot: root, BindAddress: host, Port: port, StartCallback: onstart}
196
+ begin
197
+ srv = WEBrick::HTTPServer.new(srvconf)
198
+ rescue Errno::EADDRINUSE => ex
199
+ at_exit { $stderr.puts helper_message_when_address_already_in_use }
200
+ raise
201
+ end
202
+ #
203
+ srv.mount_proc('/favicon.ico') do |req, res|
204
+ res.content_type = "image/x-icon"
205
+ res['Cache-Control'] = "public, max-age=#{60*60*24}"
206
+ res.body = favicon_base64.unpack("m")[0]
207
+ end
208
+ #
209
+ flag_quit = false
210
+ interval = 0.8 # seconds
211
+ srv.mount_proc(rebuild_js) do |req, res|
212
+ file = nil
213
+ if req.query_string =~ /\Afile=([^&]*)/
214
+ file = $1.strip
215
+ file = nil if file.empty?
216
+ end
217
+ #
218
+ errmsg = nil
219
+ if file.nil?
220
+ # pass
221
+ elsif file !~ /\A[-\w]+\.re\z/
222
+ errmsg = "invalid file"
223
+ else
224
+ file = File.join(contdir, file) if contdir
225
+ errmsg = "file not found." if ! File.exist?(file)
226
+ end
227
+ #
228
+ if errmsg
229
+ body = "alert('ERROR: #{errmsg}');"
230
+ else
231
+ body = "window.location.reload();"
232
+ ## sleep until '*.re' file modified
233
+ if file
234
+ mtime = File.mtime(file)
235
+ sleep interval while !flag_quit && mtime == File.mtime(file)
236
+ end
237
+ ## generate html file from '*.re'
238
+ invoke_web_task.call() unless flag_quit
239
+ end
240
+ res.content_type = "application/javascript"
241
+ msg = "Server seems down. Press OK to reload."
242
+ res.body = !flag_quit ? body : "alert('#{msg}');window.location.reload();"
243
+ end
244
+ #
245
+ trap(:INT) { flag_quit = true; srv.shutdown() }
246
+ srv.start()
247
+ end
248
+
249
+ end
250
+
251
+
252
+ ##
253
+ ## 高解像度用の画像から低解像度の画像を生成するRakeタスク。
254
+ ## 詳細は「ワンストップ!技術同人誌を書こう」第8章を参照のこと。
255
+ ## https://booth.pm/ja/items/708196
256
+ ##
257
+ desc "+ convert images (high resolution -> low resolution)"
258
+ task :images do
259
+ ## macOSならsipsコマンドを使い、それ以外ではImageMagickを使う
260
+ has_sips = File.exist?("/usr/bin/sips")
261
+ if ! has_sips
262
+ ok = system("convert --version >/dev/null")
263
+ if ! ok
264
+ abort "ERROR: 'convert' command not found; please install ImageMagick."
265
+ end
266
+ end
267
+ ## 高解像度の画像をもとに低解像度の画像を作成する
268
+ for src in Dir.glob("images_highres/**/*.{png,jpg,jpeg}")
269
+ ## 低解像度の画像を作成済みなら残りの処理をスキップ
270
+ dest = src.sub("images_highres/", "images_lowres/")
271
+ next if File.exist?(dest) && File.mtime(src) == File.mtime(dest)
272
+ ## 必要ならフォルダを作成
273
+ dir = File.dirname(dest)
274
+ mkdir_p dir if ! File.directory?(dir)
275
+ ## 高解像度の画像のDPIを変更(72dpi→360dpi)
276
+ if has_sips
277
+ sh "sips -s dpiHeight 360 -s dpiWidth 360 #{src}"
278
+ else
279
+ sh "convert -density 360 -units PixelsPerInch #{src} #{src}"
280
+ end
281
+ ## 低解像度の画像を作成(72dpi、横幅1/5)
282
+ if has_sips
283
+ `sips -g pixelWidth #{src}` =~ /pixelWidth: (\d+)/
284
+ option = "-s dpiHeight 72 -s dpiWidth 72 --resampleWidth #{$1.to_i / 5}"
285
+ sh "sips #{option} --out #{dest} #{src}"
286
+ else
287
+ sh "convert -density 72 -units PixelsPerInch -resize 20% #{src} #{dest}"
288
+ end
289
+ ## 低解像度の画像のタイムスタンプを、高解像度の画像と同じにする
290
+ ## (=画像のタイムスタンプが違ったら、画像が更新されたと見なす)
291
+ File.utime(File.atime(dest), File.mtime(src), dest)
292
+ end
293
+ ## 高解像度の画像が消されたら、低解像度の画像も消す
294
+ for dest in Dir.glob("images_lowres/**/*").sort().reverse()
295
+ src = dest.sub("images_lowres/", "images_highres/")
296
+ rm_r dest if ! File.exist?(src)
297
+ end
298
+ end
299
+
300
+
301
+ ##
302
+ ## 低解像度と高解像度を切り替えるRakeタスク。
303
+ ## 詳細は「ワンストップ!技術同人誌を書こう」第8章を参照のこと。
304
+ ## https://booth.pm/ja/items/708196
305
+ ##
306
+ namespace "images" do
307
+
308
+ desc "+ toggle image directories ('images_{lowres,highres}')"
309
+ task :toggle do
310
+ if ! File.symlink?("images")
311
+ msg = "ERROR: 'images' directory should be a symbolic link.\n"
312
+ msg << " rename it and create symbolic link, for example:\n"
313
+ msg << " $ mv images images_highres\n"
314
+ msg << " $ ln -s images_highres images\n"
315
+ abort msg
316
+ end
317
+ link = File.readlink("images")
318
+ rm "images"
319
+ if link == "images_lowres"
320
+ ln_s "images_highres", "images"
321
+ else
322
+ ln_s "images_lowres", "images"
323
+ end
324
+ end
325
+
326
+ end