review 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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)