narou 1.5.11 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of narou might be problematic. Click here for more details.

Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/ChangeLog.md +619 -432
  4. data/Gemfile +9 -0
  5. data/README.md +101 -76
  6. data/lib/color.rb +62 -22
  7. data/lib/command.rb +21 -19
  8. data/lib/command/alias.rb +9 -9
  9. data/lib/command/backup.rb +11 -4
  10. data/lib/command/browser.rb +8 -7
  11. data/lib/command/convert.rb +25 -77
  12. data/lib/command/diff.rb +67 -36
  13. data/lib/command/download.rb +5 -4
  14. data/lib/command/flag.rb +32 -6
  15. data/lib/command/folder.rb +7 -5
  16. data/lib/command/freeze.rb +21 -11
  17. data/lib/command/help.rb +29 -17
  18. data/lib/command/init.rb +7 -7
  19. data/lib/command/inspect.rb +6 -5
  20. data/lib/command/list.rb +106 -25
  21. data/lib/command/mail.rb +6 -7
  22. data/lib/command/remove.rb +9 -7
  23. data/lib/command/send.rb +6 -5
  24. data/lib/command/setting.rb +51 -16
  25. data/lib/command/tag.rb +179 -0
  26. data/lib/command/update.rb +9 -8
  27. data/lib/command/version.rb +4 -4
  28. data/lib/commandbase.rb +79 -8
  29. data/lib/commandline.rb +14 -8
  30. data/lib/converterbase.rb +78 -28
  31. data/lib/database.rb +3 -3
  32. data/lib/device.rb +26 -13
  33. data/lib/device/ibooks.rb +116 -0
  34. data/lib/device/ibunko.rb +45 -0
  35. data/lib/device/kindle.rb +4 -0
  36. data/lib/device/kobo.rb +4 -0
  37. data/lib/device/library/windows.rb +12 -4
  38. data/lib/device/reader.rb +9 -0
  39. data/lib/diffviewer.rb +147 -0
  40. data/lib/downloader.rb +195 -80
  41. data/lib/extensions/jruby.rb +33 -0
  42. data/lib/extensions/windows.rb +8 -9
  43. data/lib/helper.rb +79 -37
  44. data/lib/illustration.rb +1 -1
  45. data/lib/inspector.rb +2 -2
  46. data/lib/inventory.rb +48 -0
  47. data/lib/logger.rb +28 -4
  48. data/lib/narou.rb +9 -7
  49. data/lib/narou/api.rb +7 -2
  50. data/lib/novelconverter.rb +46 -19
  51. data/lib/novelinfo.rb +13 -3
  52. data/lib/novelsetting.rb +17 -9
  53. data/lib/version.rb +1 -1
  54. data/narou.gemspec +106 -27
  55. data/narou.rb +2 -2
  56. data/spec/convert_spec.rb +102 -0
  57. data/spec/data/convert_test/auto_indent/correct_test_auto_indent.txt +18 -0
  58. data/spec/data/convert_test/auto_indent/test_auto_indent.txt +21 -0
  59. data/spec/data/convert_test/auto_join_bracket/correct_test_auto_join_bracket.txt +12 -0
  60. data/spec/data/convert_test/auto_join_bracket/test_auto_join_bracket.txt +16 -0
  61. data/spec/data/convert_test/auto_join_line/correct_test_auto_join_line.txt +36 -0
  62. data/spec/data/convert_test/auto_join_line/test_auto_join_line.txt +51 -0
  63. data/spec/data/convert_test/convert_page_break/correct_test_convert_page_break.txt +21 -0
  64. data/spec/data/convert_test/convert_page_break/setting.ini +5 -0
  65. data/spec/data/convert_test/convert_page_break/test_convert_page_break.txt +60 -0
  66. data/spec/data/convert_test/force_indent_special_chapter/correct_test_force_indent_special_chapter.txt +64 -0
  67. data/spec/data/convert_test/force_indent_special_chapter/test_force_indent_special_chapter.txt +61 -0
  68. data/spec/data/convert_test/horizontal_ellipsis/correct_test_horizontal_ellipsis.txt +52 -0
  69. data/spec/data/convert_test/horizontal_ellipsis/test_horizontal_ellipsis.txt +57 -0
  70. data/spec/data/convert_test/kanji_num/correct_test_kanji_num.txt +49 -0
  71. data/spec/data/convert_test/kanji_num/test_kanji_num.txt +56 -0
  72. data/spec/data/convert_test/nonokagi/correct_test_nonokagi.txt +29 -0
  73. data/spec/data/convert_test/nonokagi/test_nonokagi.txt +34 -0
  74. data/spec/data/convert_test/replace/correct_test_replace.txt +12 -0
  75. data/spec/data/convert_test/replace/replace.txt +7 -0
  76. data/spec/data/convert_test/replace/test_replace.txt +14 -0
  77. data/spec/data/convert_test/ruby/correct_test_ruby.txt +131 -0
  78. data/spec/data/convert_test/ruby/test_ruby.txt +170 -0
  79. data/spec/data/convert_test/ruby_youon/correct_test_ruby_youon.txt +12 -0
  80. data/spec/data/convert_test/ruby_youon/setting.ini +2 -0
  81. data/spec/data/convert_test/ruby_youon/test_ruby_youon.txt +14 -0
  82. data/spec/data/convert_test/sesame/correct_test_sesame.txt +40 -0
  83. data/spec/data/convert_test/sesame/test_sesame.txt +52 -0
  84. data/spec/data/convert_test/to_odd_leader/correct_test_to_odd_leader.txt +20 -0
  85. data/spec/data/convert_test/to_odd_leader/test_to_odd_leader.txt +21 -0
  86. data/spec/device_spec.rb +3 -3
  87. data/spec/generator/convert_spec_gen.rb +95 -0
  88. data/spec/html_spec.rb +9 -8
  89. data/spec/ini_spec.rb +31 -31
  90. data/spec/novelinfo_spec.rb +2 -2
  91. data/spec/num_to_kanji_spec.rb +2 -2
  92. data/template/diff.txt.erb +5 -2
  93. data/template/ibunko_novel.txt.erb +2 -1
  94. data/template/novel.txt.erb +16 -3
  95. data/template/setting.ini.erb +1 -1
  96. data/webnovel/ncode.syosetu.com.yaml +7 -7
  97. data/webnovel/novel18.syosetu.com.yaml +7 -7
  98. data/webnovel/syosetu.org.yaml +8 -11
  99. metadata +193 -23
  100. data/lib/globalsetting.rb +0 -64
  101. data/lib/localsetting.rb +0 -63
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2013 whiteleaf. All rights reserved.
4
+ #
5
+
6
+ if Helper.os_windows?
7
+ require "fileutils"
8
+
9
+ module FileUtils
10
+ # マルチバイト文字を含むパスを認識出来ないため
11
+ def self.cp(src, dst, opt = nil)
12
+ open(src, "rb") do |fp|
13
+ File.binwrite(dst, fp.read)
14
+ end
15
+ end
16
+ end
17
+
18
+ class File
19
+ # 何故かエンコーディングエラーが出るため
20
+ def self.binwrite(path, data)
21
+ open(path, "wb") do |fp|
22
+ fp.write(data)
23
+ end
24
+ end
25
+
26
+ # -Dfile.encoding=UTF-8 を指定するとなぜか File.mtime がマルチバイト文字を含むパスを認識出来ないため
27
+ def self.mtime(path)
28
+ java_path = java.nio.file.FileSystems.default.getPath(path)
29
+ java_file_time = java.nio.file.Files.getLastModifiedTime(java_path)
30
+ Time.parse(java_file_time.to_s).getlocal("+09:00")
31
+ end
32
+ end
33
+ end
@@ -13,16 +13,15 @@ module WinAPI
13
13
  extend DL::Importer
14
14
  end
15
15
 
16
- class InvalidOS < StandardError; end
17
-
18
16
  begin
19
- dlload "kernel32"
20
- extern "long GetLogicalDriveStrings(long, void*)"
21
- extern "unsigned long SetConsoleTextAttribute(unsigned long, unsigned long)"
22
- extern "unsigned long GetConsoleScreenBufferInfo(unsigned long, void*)"
23
- extern "unsigned long GetStdHandle(unsigned long)"
24
- extern "long GetLastError()"
17
+ dlload "msvcrt", "kernel32"
25
18
  rescue DL::DLError
26
- raise InvalidOS, "not Windows"
19
+ dlload "crtdll", "kernel32"
27
20
  end
21
+ extern "long GetLogicalDrives()"
22
+ extern "unsigned long SetConsoleTextAttribute(unsigned long, unsigned long)"
23
+ extern "unsigned long GetConsoleScreenBufferInfo(unsigned long, void*)"
24
+ extern "unsigned long GetStdHandle(unsigned long)"
25
+ extern "long GetLastError()"
26
+ extern "unsigned long _getch()"
28
27
  end
data/lib/helper.rb CHANGED
@@ -11,16 +11,18 @@ require "open3"
11
11
  module Helper
12
12
  extend self
13
13
 
14
+ HOST_OS = RbConfig::CONFIG["host_os"]
15
+
14
16
  def os_windows?
15
- @@os_is_windows ||= RUBY_PLATFORM =~ /mswin(?!ce)|mingw|bccwin/i
17
+ @@os_is_windows ||= HOST_OS =~ /mswin(?!ce)|mingw|bccwin/i
16
18
  end
17
19
 
18
20
  def os_mac?
19
- @@os_is_mac ||= RUBY_PLATFORM =~ /darwin/
21
+ @@os_is_mac ||= HOST_OS =~ /darwin/i
20
22
  end
21
23
 
22
24
  def os_cygwin?
23
- @@os_is_cygwin ||= RUBY_PLATFORM =~ /cygwin/i
25
+ @@os_is_cygwin ||= HOST_OS =~ /cygwin/i
24
26
  end
25
27
 
26
28
  def determine_os
@@ -36,16 +38,38 @@ module Helper
36
38
  end
37
39
  end
38
40
 
39
- def confirm(message)
41
+ def engine_jruby?
42
+ @@engine_is_jruby ||= RUBY_ENGINE == "jruby"
43
+ end
44
+
45
+ if engine_jruby? && os_windows?
46
+ require_relative "extensions/windows"
47
+ def $stdin.getch
48
+ WinAPI._getch.chr
49
+ end
50
+ else
51
+ require "io/console"
52
+ end
53
+
54
+ #
55
+ # キーボード入力による確認をする
56
+ #
57
+ # :default: エンターを押した場合に返ってくる値
58
+ # :nontty_default: pipe等から接続された場合に返ってくる値
59
+ #
60
+ def confirm(message, default = false, nontty_default = true)
61
+ return nontty_default unless STDIN.tty?
40
62
  confirm_msg = "#{message} (y/n)?: "
41
63
  STDOUT.print confirm_msg # Logger でロギングされないように直接標準出力に表示
42
- while input = $stdin.gets
43
- case input[0].downcase
64
+ while input = $stdin.getch
65
+ STDOUT.puts input
66
+ case input.downcase
44
67
  when "y"
45
68
  return true
46
69
  when "n"
47
70
  return false
48
71
  else
72
+ return default if input.strip == ""
49
73
  STDOUT.print confirm_msg
50
74
  end
51
75
  end
@@ -54,22 +78,22 @@ module Helper
54
78
  def open_browser_linux(address, error_message)
55
79
  %w(xdg-open firefox w3m).each do |browser|
56
80
  system(%!#{browser} "#{address}"!)
57
- return if $?.exitstatus != 127
81
+ return if $?.success?
58
82
  end
59
83
  error error_message
60
84
  end
61
85
 
62
86
  def open_directory(path, confirm_message = nil)
63
87
  if confirm_message
64
- return unless confirm(confirm_message)
88
+ return unless confirm(confirm_message, false, false)
65
89
  end
66
90
  case determine_os
67
91
  when :windows
68
- `explorer "file:///#{path.encode(Encoding::Windows_31J)}"`
92
+ system(%!explorer "file:///#{path.encode(Encoding::Windows_31J)}"!)
69
93
  when :cygwin
70
- `cygstart "#{path}"`
94
+ system(%!cygstart "#{path}"!)
71
95
  when :mac
72
- `open "#{path}"`
96
+ system(%!open "#{path}"!)
73
97
  else
74
98
  open_browser_linux(path, "フォルダが開けませんでした")
75
99
  end
@@ -80,11 +104,11 @@ module Helper
80
104
  when :windows
81
105
  escaped_url = url.gsub("%", "%^").gsub("&", "^&")
82
106
  # MEMO: start の引数を "" で囲むと動かない
83
- `start #{escaped_url}`
107
+ system(%!start #{escaped_url}!)
84
108
  when :cygwin
85
- `cygstart #{url}`
109
+ system(%!cygstart #{url}!)
86
110
  when :mac
87
- `open "#{url}"`
111
+ system(%!open "#{url}"!)
88
112
  else
89
113
  open_browser_linux(url, "ブラウザが見つかりませんでした")
90
114
  end
@@ -130,6 +154,25 @@ module Helper
130
154
  `cygpath -aw \"#{path}\"`.strip
131
155
  end
132
156
 
157
+ #
158
+ # アンパサンドをエンティティに変換
159
+ #
160
+ def ampersand_to_entity(str)
161
+ str.gsub(/&(?!amp;)/mi, "&amp;")
162
+ end
163
+
164
+ #
165
+ # 文章の中から挿絵注記を分離する
166
+ #
167
+ def extract_illust_chuki(str)
168
+ illust_chuki_array = []
169
+ extracted_str = str.gsub(/[  \t]*?([#挿絵(.+?)入る])\n?/) do
170
+ illust_chuki_array << $1
171
+ ""
172
+ end
173
+ [extracted_str, illust_chuki_array]
174
+ end
175
+
133
176
  #
134
177
  # 外部コマンド実行中の待機ループの処理を書けるクラス
135
178
  #
@@ -142,29 +185,28 @@ module Helper
142
185
  #
143
186
  class AsyncCommand
144
187
  def self.exec(command, sleep_time = 0.5, &block)
145
- async_command = new(command)
146
- while async_command.running?
147
- block.call
148
- sleep(sleep_time)
149
- end
150
- async_command.response
151
- end
152
-
153
- def initialize(command)
154
- @command_response = nil
155
- @command_running = true
156
- Thread.new do
157
- @command_response = Open3.capture3(command)
158
- @command_running = false
159
- end
160
- end
161
-
162
- def running?
163
- @command_running
164
- end
165
-
166
- def response
167
- @command_response
188
+ Thread.new {
189
+ loop do
190
+ block.call if block
191
+ sleep(sleep_time)
192
+ end
193
+ }.tap { |th|
194
+ if Helper::engine_jruby?
195
+ # MEMO:
196
+ # Open3.capture3 - 全く動かない
197
+ # `` バッククウォート - 出力が文字化けする
198
+ res = Open3.popen3(command) { |i, o, e|
199
+ i.close
200
+ `cd` # create dummy Process::Status object to $?
201
+ [o.read, e.read, $?]
202
+ }
203
+ else
204
+ res = Open3.capture3(command)
205
+ end
206
+ th.kill
207
+ return res
208
+ }
168
209
  end
169
210
  end
170
211
  end
212
+
data/lib/illustration.rb CHANGED
@@ -11,7 +11,7 @@ require "open-uri"
11
11
  class Illustration
12
12
  ILLUST_DIR = "挿絵/"
13
13
  NAROU_ILLUST_URL = "http://%s.mitemin.net/userpageimage/viewimage/icode/%s/"
14
- NAROU_ILLUST_TAG_PATTERN = /^<(i[0-9]+)\|([0-9]+)>\n?/m
14
+ NAROU_ILLUST_TAG_PATTERN = /[  \t]*?<(i[0-9]+)\|([0-9]+)>\n?/m
15
15
 
16
16
  MIME = { "image/jpeg" => "jpg", "image/png" => "png", "image/gif" => "gif", "image/bmp" => "bmp" }
17
17
 
data/lib/inspector.rb CHANGED
@@ -19,7 +19,7 @@ class Inspector
19
19
 
20
20
  KLASS_TAG = { ERROR => "エラー", WARNING => "警告", INFO => "INFO" }
21
21
 
22
- IGNORE_INDENT_CHAR = "((「『〈《≪【〔―・※[〝"
22
+ IGNORE_INDENT_CHAR = "((「『〈《≪【〔―・※[〝\n"
23
23
  AUTO_INDENT_THRESHOLD_RATIO = 0.5 # 括弧等を除く全ての行のうちこの割合以上字下げされてなければ強制字下げする
24
24
 
25
25
  attr_writer :messages, :subtitle
@@ -197,7 +197,7 @@ class Inspector
197
197
  target_line_count = a.count
198
198
  }.each { |line|
199
199
  head = line[0]
200
- unless head == " " || head == " "
200
+ if head != " " && head != " "
201
201
  dont_indent_line_count += 1
202
202
  end
203
203
  }
data/lib/inventory.rb ADDED
@@ -0,0 +1,48 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2013 whiteleaf. All rights reserved.
4
+ #
5
+
6
+ require "yaml"
7
+ require_relative "narou"
8
+
9
+ #
10
+ # Narou.rbのシステムが記録するデータ単位
11
+ #
12
+ # .narou ディレクトリにYAMLファイルとして保存される
13
+ #
14
+ module Inventory
15
+ def self.load(name, scope)
16
+ @@cache ||= {}
17
+ return @@cache[name] if @@cache[name]
18
+ {}.tap { |h|
19
+ h.extend(Inventory)
20
+ h.init(name, scope)
21
+ @@cache[name] = h
22
+ }
23
+ end
24
+
25
+ def init(name, scope)
26
+ dir = case scope
27
+ when :local
28
+ Narou.get_local_setting_dir
29
+ when :global
30
+ Narou.get_global_setting_dir
31
+ else
32
+ raise "Unknown scope"
33
+ end
34
+ return nil unless dir
35
+ @inventory_file_path = File.join(dir, name + ".yaml")
36
+ if File.exists?(@inventory_file_path)
37
+ self.merge!(YAML.load_file(@inventory_file_path))
38
+ end
39
+ end
40
+
41
+ def save
42
+ unless @inventory_file_path
43
+ raise "not initialized setting dir yet"
44
+ end
45
+ File.write(@inventory_file_path, YAML.dump(self))
46
+ end
47
+ end
48
+
data/lib/logger.rb CHANGED
@@ -7,6 +7,18 @@ require "singleton"
7
7
  require "stringio"
8
8
  require_relative "color"
9
9
 
10
+ class String
11
+ def escape
12
+ TermColor.escape(self)
13
+ end
14
+
15
+ if RUBY_ENGINE == "jruby"
16
+ def termcolor
17
+ TermColor.parse(self.dup.force_encoding(Encoding::ASCII_8BIT))
18
+ end
19
+ end
20
+ end
21
+
10
22
  if $disable_color
11
23
  class String
12
24
  def termcolor
@@ -26,6 +38,18 @@ module LoggerModule
26
38
  end
27
39
 
28
40
  def silent
41
+ if block_given?
42
+ if /^(.+?):(\d+)/ =~ caller.first
43
+ file = $1
44
+ line = $2.to_i
45
+ error_msg = "Did you mean: silence\n"
46
+ str = File.read(file).split("\n")[line-1]
47
+ error_msg += "in #{file}:#{line}\n"
48
+ error_msg += str + "\n"
49
+ error_msg += " " * str.index("silent") + "~~~~~~"
50
+ raise error_msg
51
+ end
52
+ end
29
53
  @is_silent
30
54
  end
31
55
 
@@ -46,7 +70,7 @@ module LoggerModule
46
70
  end
47
71
 
48
72
  def save(path)
49
- File.write(path, string)
73
+ File.write(path, strip_color(string))
50
74
  end
51
75
 
52
76
  def write_console(str, target)
@@ -73,7 +97,7 @@ class Logger < StringIO
73
97
  if str.encoding == Encoding::ASCII_8BIT
74
98
  str.force_encoding(Encoding::UTF_8)
75
99
  end
76
- super(strip_color(str))
100
+ super(str)
77
101
  write_console(str, STDOUT)
78
102
  end
79
103
  end
@@ -91,13 +115,13 @@ class LoggerError < StringIO
91
115
  if str.encoding == Encoding::ASCII_8BIT
92
116
  str.force_encoding(Encoding::UTF_8)
93
117
  end
94
- super(strip_color(str))
118
+ super(str)
95
119
  write_console(str, STDERR)
96
120
  end
97
121
  end
98
122
 
99
123
  def error(str)
100
- warn "<red>[ERROR]</red> #{str}".termcolor
124
+ warn "<bold><red>[ERROR]</red></bold> #{TermColor.escape(str)}".termcolor
101
125
  end
102
126
 
103
127
  $stdout = Logger.get
data/lib/narou.rb CHANGED
@@ -5,8 +5,10 @@
5
5
 
6
6
  require "fileutils"
7
7
  require_relative "helper"
8
- require_relative "localsetting"
9
- require_relative "globalsetting"
8
+ require_relative "inventory"
9
+ if Helper.engine_jruby?
10
+ require_relative "extensions/jruby"
11
+ end
10
12
 
11
13
  module Narou
12
14
  extend self
@@ -32,7 +34,7 @@ module Narou
32
34
  drive_letter = $&
33
35
  end
34
36
  while path != ""
35
- if File.directory?("#{path}/#{LOCAL_SETTING_DIR}")
37
+ if File.directory?("#{drive_letter}#{path}/#{LOCAL_SETTING_DIR}")
36
38
  @@root_dir = drive_letter + path
37
39
  break
38
40
  end
@@ -75,7 +77,7 @@ module Narou
75
77
  end
76
78
 
77
79
  def alias_to_id(target)
78
- aliases = LocalSetting.get["alias"]
80
+ aliases = Inventory.load("alias", :local)
79
81
  if aliases[target]
80
82
  return aliases[target]
81
83
  end
@@ -84,7 +86,7 @@ module Narou
84
86
 
85
87
  def novel_frozen?(target)
86
88
  id = Downloader.get_id_by_target(target) or return false
87
- LocalSetting.get["freeze"].include?(id)
89
+ Inventory.load("freeze", :local).include?(id)
88
90
  end
89
91
 
90
92
  def get_preset_dir
@@ -110,7 +112,7 @@ module Narou
110
112
  #
111
113
  def get_aozoraepub3_path
112
114
  return @@aozora_jar_path if @@aozora_jar_path
113
- global_setting_aozora_path = GlobalSetting.get["global_setting"]["aozoraepub3dir"]
115
+ global_setting_aozora_path = Inventory.load("global_setting", :global)["aozoraepub3dir"]
114
116
  if global_setting_aozora_path
115
117
  aozora_jar_path = create_aozoraepub3_jar_path(global_setting_aozora_path)
116
118
  if File.exists?(aozora_jar_path)
@@ -149,7 +151,7 @@ module Narou
149
151
  require_relative "device"
150
152
 
151
153
  def get_device(device_name = nil)
152
- device_name = LocalSetting.get["local_setting"]["device"] unless device_name
154
+ device_name = Inventory.load("local_setting", :local)["device"] unless device_name
153
155
  if device_name && Device.exists?(device_name)
154
156
  return Device.create(device_name)
155
157
  end