review 0.9.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. data/.travis.yml +9 -0
  2. data/ChangeLog +326 -0
  3. data/Rakefile +3 -5
  4. data/VERSION +1 -1
  5. data/bin/review-compile +50 -50
  6. data/bin/review-epubmaker +62 -75
  7. data/bin/review-epubmaker-ng +185 -0
  8. data/bin/review-index +2 -1
  9. data/bin/review-pdfmaker +158 -101
  10. data/bin/review-vol +6 -2
  11. data/doc/format.rdoc +111 -46
  12. data/doc/libepubmaker/sample.yaml +90 -0
  13. data/doc/quickstart.rdoc +188 -0
  14. data/doc/sample.yaml +8 -0
  15. data/lib/epubmaker.rb +28 -0
  16. data/lib/epubmaker/content.rb +82 -0
  17. data/lib/epubmaker/epubv2.rb +419 -0
  18. data/lib/epubmaker/epubv3.rb +249 -0
  19. data/lib/epubmaker/producer.rb +204 -0
  20. data/lib/epubmaker/resource.rb +66 -0
  21. data/lib/review.rb +1 -1
  22. data/lib/review/book.rb +27 -4
  23. data/lib/review/builder.rb +153 -20
  24. data/lib/review/compiler.rb +61 -10
  25. data/lib/review/ewbbuilder.rb +3 -2
  26. data/lib/review/htmlbuilder.rb +174 -67
  27. data/lib/review/i18n.rb +30 -0
  28. data/lib/review/i18n.yaml +23 -0
  29. data/lib/review/idgxmlbuilder.rb +110 -63
  30. data/lib/review/index.rb +34 -12
  31. data/lib/review/latexbuilder.rb +128 -33
  32. data/lib/review/latexutils.rb +18 -1
  33. data/lib/review/textbuilder.rb +17 -0
  34. data/lib/review/tocparser.rb +3 -1
  35. data/lib/review/tocprinter.rb +1 -0
  36. data/lib/review/topbuilder.rb +397 -198
  37. data/review.gemspec +101 -100
  38. data/test/test_book.rb +27 -0
  39. data/test/test_epubmaker.rb +507 -0
  40. data/test/test_helper.rb +8 -0
  41. data/test/test_htmlbuilder.rb +295 -10
  42. data/test/test_i18n.rb +64 -0
  43. data/test/test_idgxmlbuilder.rb +268 -10
  44. data/test/test_latexbuilder.rb +316 -20
  45. data/test/test_preprocessor.rb +23 -0
  46. data/test/test_topbuilder.rb +246 -0
  47. metadata +46 -53
  48. data/doc/format.re +0 -505
  49. data/test/test_index.rb +0 -15
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'yaml'
3
+
4
+ module ReVIEW
5
+ class I18n
6
+ def self.setup
7
+ user_i18n = YAML.load_file(File.expand_path "locale.yaml", ENV["PWD"])
8
+ I18n.i18n user_i18n["locale"], user_i18n
9
+ rescue
10
+ I18n.i18n "ja"
11
+ end
12
+
13
+ def self.i18n(locale, user_i18n = {})
14
+ locale ||= "ja"
15
+ i18n_yaml_path = File.expand_path "i18n.yaml", File.dirname(__FILE__)
16
+ @i18n = YAML.load_file(i18n_yaml_path)[locale]
17
+ if @i18n
18
+ @i18n.merge!(user_i18n)
19
+ end
20
+ end
21
+
22
+ def self.t(str, args = nil)
23
+ @i18n[str] % args
24
+ rescue
25
+ str
26
+ end
27
+ end
28
+
29
+ I18n.setup
30
+ end
@@ -0,0 +1,23 @@
1
+ ja:
2
+ image: 図
3
+ table: 表
4
+ list: リスト
5
+ chapter: 第%d章
6
+ chapter_postfix: " "
7
+ numberless_image: "図:"
8
+ format_number: "%s.%d"
9
+ format_number_header: "%s.%d:"
10
+ format_number_without_chapter: "%d"
11
+ format_number_header_without_chapter: "%d:"
12
+
13
+ en:
14
+ image: "Figure "
15
+ table: "Table "
16
+ list: "List "
17
+ chapter: Chapter %d
18
+ chapter_postfix: ". "
19
+ numberless_image: "Figure:"
20
+ format_number: "%s.%d"
21
+ format_number_header: "%s.%d:"
22
+ format_number_without_chapter: "%d"
23
+ format_number_header_without_chapter: "%d:"
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  #
3
3
  # Copyright (c) 2002-2007 Minero Aoki
4
- # 2008-2010 Minero Aoki, Kenshi Muto
4
+ # 2008-2012 Minero Aoki, Kenshi Muto
5
5
  #
6
6
  # This program is free software.
7
7
  # You can distribute or modify this program under the terms of
@@ -20,9 +20,7 @@ module ReVIEW
20
20
  include TextUtils
21
21
  include HTMLUtils
22
22
 
23
- [:ttbold, :hint, :maru, :keytop, :labelref, :ref, :pageref, :icon, :balloon].each {|e|
24
- Compiler.definline(e)
25
- }
23
+ [:ttbold, :hint, :maru, :keytop, :labelref, :ref, :pageref, :balloon].each {|e| Compiler.definline(e) }
26
24
  Compiler.defsingle(:dtp, 1)
27
25
 
28
26
  Compiler.defblock(:insn, 0..1)
@@ -148,9 +146,9 @@ module ReVIEW
148
146
 
149
147
  print %Q(<chapter id="chap:#{@chapter.number}">) unless @secttags.nil?
150
148
  if @chapter.number.to_s =~ /\A\d+$/
151
- prefix = "第#{@chapter.number}章 "
149
+ prefix = "#{I18n.t("chapter", @chapter.number)}#{I18n.t("chapter_postfix")}"
152
150
  elsif !@chapter.number.nil? && !@chapter.number.to_s.empty?
153
- prefix = "#{@chapter.number} "
151
+ prefix = "#{@chapter.number}#{I18n.t("chapter_postfix")}"
154
152
  end
155
153
  @section = 0
156
154
  @subsection = 0
@@ -212,12 +210,23 @@ module ReVIEW
212
210
  puts %Q(<title#{label} aid:pstyle="h#{level}">#{prefix}#{compile_inline(caption)}</title><?dtp level="#{level}" section="#{prefix}#{escape_html(compile_inline(caption))}"?>)
213
211
  end
214
212
 
213
+
215
214
  def ul_begin
216
- puts '<ul>'
215
+ level = block_given? ? yield : ""
216
+ level = nil if level == 1
217
+ puts "<ul#{level == 1 ? nil : level}>"
217
218
  end
218
219
 
219
220
  def ul_item(lines)
220
- puts %Q(<li aid:pstyle="ul-item">#{lines.join("\n").chomp}</li>)
221
+ puts %Q(<li aid:pstyle="ul-item">#{lines.join.chomp}</li>)
222
+ end
223
+
224
+ def ul_item_begin(lines)
225
+ print %Q(<li aid:pstyle="ul-item">#{lines.join.chomp})
226
+ end
227
+
228
+ def ul_item_end
229
+ puts "</li>"
221
230
  end
222
231
 
223
232
  def choice_single_begin
@@ -237,7 +246,9 @@ module ReVIEW
237
246
  end
238
247
 
239
248
  def ul_end
240
- puts '</ul>'
249
+ level = block_given? ? yield : ""
250
+ level = nil if level == 1
251
+ puts "</ul#{level}>"
241
252
  end
242
253
 
243
254
  def ol_begin
@@ -245,7 +256,7 @@ module ReVIEW
245
256
  end
246
257
 
247
258
  def ol_item(lines, num)
248
- puts %Q(<li aid:pstyle="ol-item" num="#{num}">#{lines.join("\n").chomp}</li>)
259
+ puts %Q(<li aid:pstyle="ol-item" num="#{num}">#{lines.join.chomp}</li>)
249
260
  end
250
261
 
251
262
  def ol_end
@@ -261,7 +272,7 @@ module ReVIEW
261
272
  end
262
273
 
263
274
  def dd(lines)
264
- puts "<dd>#{lines.join("\n").chomp}</dd>"
275
+ puts "<dd>#{lines.join.chomp}</dd>"
265
276
  end
266
277
 
267
278
  def dl_end
@@ -282,27 +293,47 @@ module ReVIEW
282
293
  end
283
294
 
284
295
  def read(lines)
285
- blocked_lines = ReVIEW.book.param["deprecated-blocklines"].nil? ? split_paragraph(lines) : lines
286
- puts %Q[<p aid:pstyle="lead">#{blocked_lines.join}</p>]
296
+ if ReVIEW.book.param["deprecated-blocklines"].nil?
297
+ puts %Q[<lead>#{split_paragraph(lines).join}</lead>]
298
+ else
299
+ puts %Q[<p aid:pstyle="lead">#{lines.join}</p>]
300
+ end
287
301
  end
288
302
 
289
303
  alias :lead read
290
304
 
291
305
  def inline_list(id)
292
306
  chapter, id = extract_chapter_id(id)
293
- "<span type='list'>リスト#{getChap(chapter)}#{chapter.list(id).number}</span>"
307
+ if get_chap(chapter).nil?
308
+ "<span type='list'>#{I18n.t("list")}#{I18n.t("format_number_without_chapter", [chapter.list(id).number])}</span>"
309
+ else
310
+ "<span type='list'>#{I18n.t("list")}#{I18n.t("format_number", [get_chap(chapter), chapter.list(id).number])}</span>"
311
+ end
294
312
  end
295
313
 
296
314
  def list_header(id, caption)
297
315
  puts %Q[<codelist>]
298
- puts %Q[<caption>リスト#{getChap}#{@chapter.list(id).number} #{compile_inline(caption)}</caption>]
316
+ if get_chap.nil?
317
+ puts %Q[<caption>#{I18n.t("list")}#{I18n.t("format_number_without_chapter", [@chapter.list(id).number])} #{compile_inline(caption)}</caption>]
318
+ else
319
+ puts %Q[<caption>#{I18n.t("list")}#{I18n.t("format_number", [get_chap, @chapter.list(id).number])} #{compile_inline(caption)}</caption>]
320
+ end
299
321
  end
300
322
 
301
323
  def list_body(lines)
302
324
  print %Q(<pre>)
325
+ no = 1
303
326
  lines.each do |line|
327
+ unless ReVIEW.book.param["listinfo"].nil?
328
+ print "<listinfo line=\"#{no}\""
329
+ print " begin=\"1\"" if no == 1
330
+ print " end=\"#{no}\"" if no == lines.size
331
+ print ">"
332
+ end
304
333
  print detab(line)
305
334
  print "\n"
335
+ print "</listinfo>" unless ReVIEW.book.param["listinfo"].nil?
336
+ no += 1
306
337
  end
307
338
  puts "</pre></codelist>"
308
339
  end
@@ -364,39 +395,46 @@ module ReVIEW
364
395
 
365
396
  def inline_table(id)
366
397
  chapter, id = extract_chapter_id(id)
367
- "<span type='table'>表#{getChap(chapter)}#{chapter.table(id).number}</span>"
398
+ if get_chap(chapter).nil?
399
+ "<span type='table'>#{I18n.t("table")}#{I18n.t("format_number_without_chapter", [chapter.table(id).number])}</span>"
400
+ else
401
+ "<span type='table'>#{I18n.t("table")}#{I18n.t("format_number", [get_chap(chapter), chapter.table(id).number])}</span>"
402
+ end
368
403
  end
369
404
 
370
405
  def inline_img(id)
371
406
  chapter, id = extract_chapter_id(id)
372
- "<span type='image'>図#{getChap(chapter)}#{chapter.image(id).number}</span>"
407
+ if get_chap(chapter).nil?
408
+ "<span type='image'>#{I18n.t("image")}#{I18n.t("format_number_without_chapter", [chapter.image(id).number])}</span>"
409
+ else
410
+ "<span type='image'>#{I18n.t("image")}#{I18n.t("format_number", [get_chap(chapter), chapter.image(id).number])}</span>"
411
+ end
373
412
  end
374
-
375
- def parse_metric(metric)
376
- return [] if metric.nil? || metric.empty?
377
- params = []
378
- values = metric.split(/\s*?,\s*?/)
379
- return [] if values.size == 0
380
- values.each {|value|
381
- k, v = value.split("=", 2)
382
- params.push("#{k}=\"" + v.gsub("\"", '') + "\"")
383
- }
384
- return params
413
+
414
+ def handle_metric(str)
415
+ k, v = str.split('=', 2)
416
+ return %Q|#{k}=\"#{v.sub(/\A["']/, '').sub(/["']\Z/, '')}\"|
417
+ end
418
+
419
+ def result_metric(array)
420
+ " #{array.join(' ')}"
385
421
  end
386
422
 
387
423
  def image_image(id, caption, metric=nil)
424
+ metrics = parse_metric("idgxml", metric)
388
425
  puts "<img>"
389
- params = parse_metric(metric)
390
- puts %Q[<Image href="file://#{@chapter.image(id).path.sub(/\A.\//, "")}" #{params.join(" ")} />]
426
+ puts %Q[<Image href="file://#{@chapter.image(id).path.sub(/\A.\//, "")}"#{metrics} />]
391
427
  image_header id, caption
392
428
  puts "</img>"
393
429
  end
394
430
 
395
431
  def image_dummy(id, caption, lines)
396
- if ReVIEW.book.param["subdirmode"].nil?
397
- warn "image file not exist: images/#{@chapter.id}-#{id}.eps" unless File.exist?("images/#{@chapter.id}-#{id}.eps")
398
- else
432
+ if ReVIEW.book.param["subdirmode"]
399
433
  warn "image file not exist: images/#{@chapter.id}/#{id}.eps" unless File.exist?("images/#{@chapter.id}/#{id}.eps")
434
+ elsif ReVIEW.book.param["singledirmode"]
435
+ warn "image file not exist: images/#{@chapter.id}/#{id}.eps" unless File.exist?("images/#{id}.eps")
436
+ else
437
+ warn "image file not exist: images/#{@chapter.id}-#{id}.eps" unless File.exist?("images/#{@chapter.id}-#{id}.eps")
400
438
  end
401
439
  puts "<img>"
402
440
  print %Q[<pre aid:pstyle="dummyimage">]
@@ -410,7 +448,11 @@ module ReVIEW
410
448
  end
411
449
 
412
450
  def image_header(id, caption)
413
- puts %Q[<caption>図#{getChap}#{@chapter.image(id).number} #{compile_inline(caption)}</caption>]
451
+ if get_chap.nil?
452
+ puts %Q[<caption>#{I18n.t("image")}#{I18n.t("format_number_without_chapter", [@chapter.image(id).number])} #{compile_inline(caption)}</caption>]
453
+ else
454
+ puts %Q[<caption>#{I18n.t("image")}#{I18n.t("format_number", [get_chap, @chapter.image(id).number])} #{compile_inline(caption)}</caption>]
455
+ end
414
456
  end
415
457
 
416
458
  def texequation(lines)
@@ -448,17 +490,15 @@ module ReVIEW
448
490
  cellwidth = []
449
491
  unless tablewidth.nil?
450
492
  if @tsize.nil?
451
- col.times {|n|
452
- cellwidth[n] = tablewidth / col
453
- }
493
+ col.times {|n| cellwidth[n] = tablewidth / col }
454
494
  else
455
495
  cellwidth = @tsize.split(/\s*,\s*/)
456
496
  totallength = 0
457
- cellwidth.size.times {|n|
497
+ cellwidth.size.times do |n|
458
498
  cellwidth[n] = cellwidth[n].to_f / 0.351 # mm -> pt
459
499
  totallength = totallength + cellwidth[n]
460
500
  warn "total length exceeds limit for table: #{id}" if totallength > tablewidth
461
- }
501
+ end
462
502
  if cellwidth.size < col
463
503
  cw = (tablewidth - totallength) / (col - cellwidth.size)
464
504
  warn "auto cell sizing exceeds limit for table: #{id}" if cw <= 0
@@ -483,43 +523,46 @@ module ReVIEW
483
523
  end
484
524
 
485
525
  if sepidx
486
- sepidx.times do
526
+ sepidx.times do |y|
487
527
  if tablewidth.nil?
488
528
  puts %Q[<tr type="header">#{rows.shift}</tr>]
489
529
  else
490
530
  i = 0
491
- rows.shift.split(/\t/).each {|cell|
492
- print %Q[<td aid:table="cell" aid:theader="1" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf("%.13f", cellwidth[i])}">#{cell.sub("DUMMYCELLSPLITTER", "")}</td>]
531
+ rows.shift.split(/\t/).each_with_index do |cell, x|
532
+ print %Q[<td xyh="#{x + 1},#{y + 1},#{sepidx}" aid:table="cell" aid:theader="1" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf("%.13f", cellwidth[i])}">#{cell.sub("DUMMYCELLSPLITTER", "")}</td>]
493
533
  i += 1
494
- }
534
+ end
495
535
  end
496
536
  end
497
537
  end
498
- trputs(tablewidth, rows, cellwidth)
538
+ trputs(tablewidth, rows, cellwidth, sepidx)
499
539
  puts "</tbody></table>"
500
540
  @tsize = nil
501
541
  end
502
542
 
503
- def trputs(tablewidth, rows, cellwidth)
543
+ def trputs(tablewidth, rows, cellwidth, sepidx)
544
+ sepidx = 0 if sepidx.nil?
504
545
  if tablewidth.nil?
505
546
  lastline = rows.pop
506
- rows.each do |row|
507
- puts %Q[<tr>#{row}</tr>]
508
- end
547
+ rows.each {|row| puts %Q[<tr>#{row}</tr>] }
509
548
  puts %Q[<tr type="lastline">#{lastline}</tr>] unless lastline.nil?
510
549
  else
511
- rows.each do |row|
550
+ rows.each_with_index do |row, y|
512
551
  i = 0
513
- row.split(/\t/).each {|cell|
514
- print %Q[<td aid:table="cell" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf("%.13f", cellwidth[i])}">#{cell.sub("DUMMYCELLSPLITTER", "")}</td>]
552
+ row.split(/\t/).each_with_index do |cell, x|
553
+ print %Q[<td xyh="#{x + 1},#{y + 1 + sepidx},#{sepidx}" aid:table="cell" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf("%.13f", cellwidth[i])}">#{cell.sub("DUMMYCELLSPLITTER", "")}</td>]
515
554
  i += 1
516
- }
555
+ end
517
556
  end
518
557
  end
519
558
  end
520
559
 
521
560
  def table_header(id, caption)
522
- puts %Q[<caption>表#{getChap}#{@chapter.table(id).number} #{compile_inline(caption)}</caption>]
561
+ if get_chap.nil?
562
+ puts %Q[<caption>#{I18n.t("table")}#{I18n.t("format_number_without_chapter", [@chapter.table(id).number])} #{compile_inline(caption)}</caption>]
563
+ else
564
+ puts %Q[<caption>#{I18n.t("table")}#{I18n.t("format_number", [get_chap, @chapter.table(id).number])} #{compile_inline(caption)}</caption>]
565
+ end
523
566
  end
524
567
 
525
568
  def table_begin(ncols)
@@ -585,7 +628,7 @@ module ReVIEW
585
628
  end
586
629
 
587
630
  def inline_raw(str)
588
- %Q[#{str.gsub("\\n", "\n")}]
631
+ %Q[#{super(str).gsub("\\n", "\n")}]
589
632
  end
590
633
 
591
634
  def inline_hint(str)
@@ -597,15 +640,15 @@ module ReVIEW
597
640
  end
598
641
 
599
642
  def inline_maru(str)
600
- if str =~ /\A\d+$/
643
+ if str =~ /\A\d+\Z/
601
644
  sprintf("&#x%x;", 9311 + str.to_i)
602
- elsif str =~ /\A[A-Z]$/
645
+ elsif str =~ /\A[A-Z]\Z/
603
646
  begin
604
647
  sprintf("&#x%x;", 9398 + str.codepoints.to_a[0] - 65)
605
648
  rescue NoMethodError
606
649
  sprintf("&#x%x;", 9398 + str[0] - 65)
607
650
  end
608
- elsif str =~ /\A[a-z]$/
651
+ elsif str =~ /\A[a-z]\Z/
609
652
  begin
610
653
  sprintf("&#x%x;", 9392 + str.codepoints.to_a[0] - 65)
611
654
  rescue NoMethodError
@@ -940,10 +983,10 @@ module ReVIEW
940
983
  end
941
984
 
942
985
  def indepimage(id, caption=nil, metric=nil)
986
+ metrics = parse_metric("idgxml", metric)
943
987
  puts "<img>"
944
- params = parse_metric(metric)
945
988
  begin
946
- puts %Q[<Image href="file://#{@chapter.image(id).path.sub(/\A\.\//, "")}" #{params.join(" ")} />]
989
+ puts %Q[<Image href="file://#{@chapter.image(id).path.sub(/\A\.\//, "")}"#{metrics} />]
947
990
  rescue
948
991
  warn %Q[no such image: #{id}]
949
992
  end
@@ -979,7 +1022,7 @@ module ReVIEW
979
1022
  end
980
1023
 
981
1024
  def inline_code(str)
982
- %Q(<tt type='inline-code'>#{escape_html(str)}</tt>)
1025
+ %Q[<tt type='inline-code'>#{escape_html(str)}</tt>]
983
1026
  end
984
1027
 
985
1028
  def inline_br(str)
@@ -988,11 +1031,11 @@ module ReVIEW
988
1031
 
989
1032
  def rawblock(lines)
990
1033
  no = 1
991
- lines.each {|l|
1034
+ lines.each do |l|
992
1035
  print l.gsub("&lt;", "<").gsub("&gt;", ">").gsub("&quot;", "\"").gsub("&amp;", "&")
993
1036
  print "\n" unless lines.length == no
994
1037
  no = no + 1
995
- }
1038
+ end
996
1039
  end
997
1040
 
998
1041
  def text(str)
@@ -1055,13 +1098,17 @@ module ReVIEW
1055
1098
 
1056
1099
  def inline_recipe(id)
1057
1100
  # FIXME
1058
- %Q(<recipe idref="#{escape_html(id)}">[XXX]「#{escape_html(id)}」\tp.XX</recipe>)
1101
+ %Q(<recipe idref="#{escape_html(id)}">[XXX]「#{escape_html(id)}」 p.XX</recipe>)
1059
1102
  end
1060
1103
 
1061
1104
  def nofunc_text(str)
1062
1105
  escape_html(str)
1063
1106
  end
1064
1107
 
1108
+ def image_ext
1109
+ "eps"
1110
+ end
1111
+
1065
1112
  end
1066
1113
 
1067
1114
  end # module ReVIEW
data/lib/review/index.rb CHANGED
@@ -22,6 +22,9 @@ module ReVIEW
22
22
  if id = line.slice(/\[(.*?)\]/, 1)
23
23
  items.push item_class().new(id, seq)
24
24
  seq += 1
25
+ if id == ""
26
+ warn "warning: no ID of #{item_type()} in #{line}"
27
+ end
25
28
  end
26
29
  end
27
30
  new(items, *args)
@@ -43,7 +46,7 @@ module ReVIEW
43
46
  @items = items
44
47
  @index = {}
45
48
  items.each do |i|
46
- warn "warning: duplicate ID: #{i.id}" unless @index[i.id].nil?
49
+ warn "warning: duplicate ID: #{i.id} (#{i})" unless @index[i.id].nil?
47
50
  @index[i.id] = i
48
51
  end
49
52
  end
@@ -142,7 +145,7 @@ module ReVIEW
142
145
  end
143
146
 
144
147
  def ImageIndex.item_type
145
- 'image'
148
+ '(image|graph)'
146
149
  end
147
150
 
148
151
  def initialize(items, chapid, basedir, types)
@@ -157,32 +160,51 @@ module ReVIEW
157
160
 
158
161
  # internal use only
159
162
  def find_pathes(id)
160
- if ReVIEW.book.param["subdirmode"].nil?
161
- re = /\A#{@chapid}-#{id}(?i:#{@types.join('|')})\z/x
163
+ if ReVIEW.book.param["subdirmode"]
164
+ re = /\A#{id}(?i:#{@types.join('|')})\z/x
162
165
  entries().select {|ent| re =~ ent }\
163
- .sort_by {|ent| @types.index(File.extname(ent).downcase) }\
164
- .map {|ent| "#{@basedir}/#{ent}" }
165
- else
166
+ .sort_by {|ent| @types.index(File.extname(ent).downcase) }\
167
+ .map {|ent| "#{@basedir}/#{@chapid}/#{ent}" }
168
+ elsif ReVIEW.book.param["singledirmode"]
166
169
  re = /\A#{id}(?i:#{@types.join('|')})\z/x
167
170
  entries().select {|ent| re =~ ent }\
168
- .sort_by {|ent| @types.index(File.extname(ent).downcase) }\
169
- .map {|ent| "#{@basedir}/#{@chapid}/#{ent}" }
171
+ .sort_by {|ent| @types.index(File.extname(ent).downcase) }\
172
+ .map {|ent| "#{@basedir}/#{ent}" }
173
+ else
174
+ re = /\A#{@chapid}-#{id}(?i:#{@types.join('|')})\z/x
175
+ entries().select {|ent| re =~ ent }\
176
+ .sort_by {|ent| @types.index(File.extname(ent).downcase) }\
177
+ .map {|ent| "#{@basedir}/#{ent}" }
170
178
  end
171
179
  end
172
180
 
173
181
  private
174
182
 
175
183
  def entries
176
- if ReVIEW.book.param["subdirmode"].nil?
177
- @entries ||= Dir.entries(@basedir)
184
+ # @entries: do not cache for graph
185
+ if ReVIEW.book.param["subdirmode"]
186
+ @entries = Dir.entries(File.join(@basedir, @chapid))
178
187
  else
179
- @entries ||= Dir.entries(File.join(@basedir, @chapid))
188
+ @entries = Dir.entries(@basedir)
180
189
  end
181
190
  rescue Errno::ENOENT
182
191
  @entries = []
183
192
  end
184
193
  end
185
194
 
195
+ class IconIndex < ImageIndex
196
+ def IconIndex.parse(src, *args)
197
+ items = []
198
+ seq = 1
199
+ src.grep(%r!@<icon>!) do |line|
200
+ line.gsub(/@<icon>\{(.+?)\}/) do |m|
201
+ items.push item_class().new($1, seq)
202
+ seq += 1
203
+ end
204
+ end
205
+ new(items, *args)
206
+ end
207
+ end
186
208
 
187
209
  class FormatRef
188
210
  def initialize(locale, index)