eturem 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -2
- data/LICENSE.txt +1 -1
- data/README.ja.md +48 -5
- data/README.md +4 -0
- data/eturem.gemspec +11 -17
- data/exe/eturem +15 -0
- data/lib/eturem.rb +48 -28
- data/lib/eturem/base.rb +263 -259
- data/lib/eturem/en.rb +1 -215
- data/lib/eturem/en/main.rb +213 -0
- data/lib/eturem/en/warning.rb +11 -0
- data/lib/eturem/ja.rb +1 -382
- data/lib/eturem/ja/argument_error.rb +56 -0
- data/lib/eturem/ja/dxruby_error.rb +13 -0
- data/lib/eturem/ja/error_enoent.rb +19 -0
- data/lib/eturem/ja/interrupt.rb +12 -0
- data/lib/eturem/ja/load_error.rb +14 -0
- data/lib/eturem/ja/main.rb +220 -0
- data/lib/eturem/ja/name_error.rb +50 -0
- data/lib/eturem/ja/no_memory_error.rb +12 -0
- data/lib/eturem/ja/syntax_error.rb +88 -0
- data/lib/eturem/ja/system_stack_error.rb +10 -0
- data/lib/eturem/ja/type_error.rb +13 -0
- data/lib/eturem/ja/uncaught_throw_error.rb +11 -0
- data/lib/eturem/ja/warning.rb +42 -0
- data/lib/eturem/ja/zero_division_error.rb +10 -0
- data/lib/eturem/version.rb +1 -1
- data/lib/eturem/warning.rb +13 -0
- metadata +28 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 767768a9b608e0cf83064badb5717aecec8d95d729cd6f578944e69240410145
|
4
|
+
data.tar.gz: 91f5d7e50048c588b5ec8ee922ee7db379173b64e731382f0f4e14f07c1b81ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 288c49a8a1093d696fcc897f076a21c800640ee9b6229a48325f68ed769acf366fcdb4c085b09ebb2f0f3a1386f9f95d2d417f2f99a96733c50bb238d030b834
|
7
|
+
data.tar.gz: c658ff6c2fa82566e5052b515306b78cd096bca286d2a41875f2ef0aec1271dcb7a0f44962e7bb51c8d466485f37d4d86a5f79a840d471569b31dbf4689a16d9
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.ja.md
CHANGED
@@ -12,6 +12,10 @@ Easy To Understand Ruby Error Message の略。
|
|
12
12
|
|
13
13
|
$ ruby -returem/ja <your_script.rb>
|
14
14
|
|
15
|
+
または
|
16
|
+
|
17
|
+
$ eturem lang=ja <your_script.rb>
|
18
|
+
|
15
19
|
と使用すればよいのですが、最初に書いたとおり初心者が使用することを想定した gem ですので、そんなことを初心者に強いるのは酷というもの。だれか詳しい人が、事前に ```gem install eturem``` した上で、環境変数 RUBYOPT に ```-returem/ja``` を追加しておいてあげましょう。
|
16
20
|
|
17
21
|
## 使用するとどうなるか
|
@@ -129,7 +133,7 @@ Eturem を使用すると、次のようなエラー表示になります。
|
|
129
133
|
=> 2: puts "a" if a = 1
|
130
134
|
```
|
131
135
|
|
132
|
-
|
136
|
+
現状あまり多くの種類の警告に対応できてはいませんが、上記のように日本語での警告に加えて該当行を表示することができます。
|
133
137
|
|
134
138
|
### 例5:エラー発生時に自動で binding.irb
|
135
139
|
|
@@ -139,9 +143,33 @@ Eturem を使用すると、次のようなエラー表示になります。
|
|
139
143
|
|
140
144
|
なお、この機能だけを切り出した gem「[autoirb](https://github.com/nodai2hITC/autoirb)」もあります。
|
141
145
|
|
146
|
+
### その他細かなこと
|
147
|
+
|
148
|
+
#### 全角空白・全角記号による NameError
|
149
|
+
|
150
|
+
日本人ならきっと誰もがやったことがあり、そして意外と気付けない全角空白や全角記号によるエラー。通常の NameError の場合とは異なるメッセージでわかりやすくしています。(下の表示ではわかりませんが、実際には全角空白部分に下線が引かれています。)
|
151
|
+
|
152
|
+
```
|
153
|
+
【エラー】ファイル"example5.rb" 1行目:(NoMethodError)
|
154
|
+
スクリプト中に全角空白が混じっています。
|
155
|
+
=> 1: puts "こんにちは世界"
|
156
|
+
```
|
157
|
+
|
158
|
+
#### 大文字・小文字を間違えた場合の NameError
|
159
|
+
|
160
|
+
did_you_mean は、例えば `Time.now` と書くべきところを `time.now` と間違えて小文字で書いてしまった場合、 `Time` をサジェストしないようになっています。(サジェスト範囲を広げると誤反応が多くなるため、敢えてそうしているのだそうです。)
|
161
|
+
|
162
|
+
とはいえ、初心者は大文字小文字が区別されるという意識が無く、つい小文字で入力してしまうことが少なからずあるように思えます。そこでスペルが同一で大文字小文字のみが異なる場合に限り、定数もサジェスト対象になるようにしています。
|
163
|
+
|
164
|
+
```
|
165
|
+
【エラー】ファイル"example6.rb" 1行目:(NameError)
|
166
|
+
変数/メソッド「time」は存在しません。「Time」の入力ミスではありませんか?
|
167
|
+
=> 1: start_time = time.now
|
168
|
+
```
|
169
|
+
|
142
170
|
## .eturem ファイルによる設定
|
143
171
|
|
144
|
-
HOME
|
172
|
+
HOME またはカレントディレクトリに「.eturem」というファイルを用意すると、詳細設定ができます。(下の例の設定が、各項目を省略した際に使用される初期値です。)
|
145
173
|
|
146
174
|
```
|
147
175
|
enable: true
|
@@ -150,6 +178,7 @@ lang: en
|
|
150
178
|
output_backtrace: true
|
151
179
|
output_original: true
|
152
180
|
output_script: true
|
181
|
+
override_warning: true
|
153
182
|
use_coderay: false
|
154
183
|
before_line_num: 2
|
155
184
|
after_line_num: 2
|
@@ -157,13 +186,27 @@ repl: nil
|
|
157
186
|
```
|
158
187
|
|
159
188
|
- enable: eturem の使用/不使用を切り替えます。
|
160
|
-
- debug: eturem
|
161
|
-
- lang:
|
189
|
+
- debug: eturem 自体をデバッグするための機能なので、通常は使う必要はありません。
|
190
|
+
- lang: 表示言語を切り替えます。ただし `-returem/ja` のように言語を指定して使用した場合、この設定よりもそちらが優先されます。
|
162
191
|
- output_backtrace: バックトレース表示の有無を切り替えます。
|
163
192
|
- output_original: Ruby 本来のエラーメッセージの表示の有無を切り替えます。
|
164
193
|
- output_script: エラーの起きた個所のスクリプト表示の有無を切り替えます。
|
194
|
+
- override_warning: 警告に対してもわかりやすいメッセージを表示するかを設定します。
|
165
195
|
- before_line_num / after_line_num: スクリプト表示の際、エラー行の前後何行を表示するかを設定します。
|
166
|
-
- repl: irb または pry
|
196
|
+
- repl: irb または pry と書いておくと、エラー発生時に自動的に binding.irb / binding.pry します。
|
197
|
+
|
198
|
+
## 簡単な仕組み
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
begin
|
202
|
+
load($PROGRAM_NAME)
|
203
|
+
rescue Exception => e
|
204
|
+
# エラー表示処理
|
205
|
+
end
|
206
|
+
exit
|
207
|
+
```
|
208
|
+
|
209
|
+
実際はもう少しいろいろやっていますが、このように本来のスクリプト実行が始まる前に `-returem` オプションで eturem を呼び出し、そこから `load` でスクリプトを実行しているのがポイントです。これにより、SyntaxError 等も取得できるようになっています。
|
167
210
|
|
168
211
|
## Contributing
|
169
212
|
|
data/README.md
CHANGED
@@ -14,6 +14,10 @@ install it yourself as:
|
|
14
14
|
|
15
15
|
$ ruby -returem <your_script.rb>
|
16
16
|
|
17
|
+
or
|
18
|
+
|
19
|
+
$ eturem <your_script.rb>
|
20
|
+
|
17
21
|
## Contributing
|
18
22
|
|
19
23
|
Bug reports and pull requests are welcome on GitHub at https://github.com/nodai2hITC/eturem. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/eturem.gemspec
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "eturem/version"
|
2
|
+
require_relative 'lib/eturem/version'
|
5
3
|
|
6
4
|
Gem::Specification.new do |spec|
|
7
5
|
spec.name = "eturem"
|
@@ -13,24 +11,20 @@ Gem::Specification.new do |spec|
|
|
13
11
|
spec.description = %q{Easy To Understand Ruby Error Message.}
|
14
12
|
spec.homepage = "https://github.com/nodai2hITC/eturem"
|
15
13
|
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
-
"public gem pushes."
|
24
|
-
end
|
16
|
+
# spec.metadata["allowed_push_host"] = "Set to 'http://mygemserver.com'"
|
17
|
+
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
20
|
+
# spec.metadata["changelog_uri"] = spec.homepage
|
25
21
|
|
26
|
-
|
27
|
-
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
28
26
|
end
|
29
27
|
spec.bindir = "exe"
|
30
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
29
|
spec.require_paths = ["lib"]
|
32
|
-
|
33
|
-
spec.add_development_dependency "bundler", "~> 1.16"
|
34
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
36
30
|
end
|
data/exe/eturem
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lang = nil
|
4
|
+
if ARGV.first.to_s =~ /^lang=(.+)$/
|
5
|
+
lang = $1
|
6
|
+
ARGV.shift
|
7
|
+
end
|
8
|
+
|
9
|
+
if ARGV.empty?
|
10
|
+
puts "usage: eturem (lang=**) script.rb"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
|
14
|
+
$PROGRAM_NAME = ARGV.shift
|
15
|
+
require lang ? "eturem/#{lang}" : "eturem"
|
data/lib/eturem.rb
CHANGED
@@ -4,39 +4,59 @@ lang = "en"
|
|
4
4
|
output_backtrace = true
|
5
5
|
output_original = true
|
6
6
|
output_script = true
|
7
|
+
override_warning = true
|
7
8
|
use_coderay = false
|
8
9
|
before_line_num = 2
|
9
10
|
after_line_num = 2
|
10
11
|
repl = nil
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
13
|
+
config_file = File.exist?("./.eturem") ? "./.eturem" : File.join(Dir.home, ".eturem")
|
14
|
+
if File.exist?(config_file)
|
15
|
+
config = File.read(config_file).gsub(/#.*/, "")
|
16
|
+
enable = false if config.match(/^enable\s*\:\s*(?:false|off|0)/i)
|
17
|
+
debug = true if config.match(/^debug\s*\:\s*(?:true|on|1)/i)
|
18
|
+
lang = Regexp.last_match(:lang) if config.match(/^lang\s*\:\s*(?<lang>\S+)/i)
|
19
|
+
output_backtrace = false if config.match(/^output_backtrace\s*\:\s*(?:false|off|0)/i)
|
20
|
+
output_original = false if config.match( /^output_original\s*\:\s*(?:false|off|0)/i)
|
21
|
+
output_script = false if config.match( /^output_script\s*\:\s*(?:false|off|0)/i)
|
22
|
+
override_warning = false if config.match(/^override_warning\s*\:\s*(?:false|off|0)/i)
|
23
|
+
use_coderay = true if config.match( /^use_coderay\s*\:\s*(?:true|on|1)/i)
|
24
|
+
before_line_num = Regexp.last_match(:num).to_i if config.match(/^before_line_num\s*\:\s*(?<num>\d+)/i)
|
25
|
+
after_line_num = Regexp.last_match(:num).to_i if config.match( /^after_line_num\s*\:\s*(?<num>\d+)/i)
|
26
|
+
repl = Regexp.last_match(:repl).downcase if config.match(/^repl\s*\:\s*(?<repl>irb|pry)/i)
|
27
|
+
end
|
28
|
+
|
29
|
+
if enable
|
30
|
+
require "eturem/#{lang}/main" unless defined?(Eturem)
|
31
|
+
require "eturem/warning" if override_warning
|
32
|
+
Eturem::Base.output_backtrace = output_backtrace
|
33
|
+
Eturem::Base.output_original = output_original
|
34
|
+
Eturem::Base.output_script = output_script
|
35
|
+
Eturem::Base.use_coderay = use_coderay
|
36
|
+
Eturem::Base.before_line_num = before_line_num
|
37
|
+
Eturem::Base.after_line_num = after_line_num
|
38
|
+
|
39
|
+
eturem_path = File.expand_path("..", __FILE__)
|
40
|
+
last_binding = nil
|
41
|
+
tracepoint = TracePoint.trace(:raise) do |tp|
|
42
|
+
last_binding = tp.binding unless File.expand_path(tp.path).start_with?(eturem_path)
|
26
43
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
exception = Eturem.load(File.expand_path(Eturem.program_name))
|
45
|
+
tracepoint.disable
|
46
|
+
|
47
|
+
if exception.is_a?(Exception)
|
48
|
+
begin
|
49
|
+
Eturem.extend_exception(exception)
|
50
|
+
$stderr.write exception.eturem_full_message
|
51
|
+
rescue Exception => e
|
52
|
+
raise debug ? e : exception
|
53
|
+
end
|
54
|
+
|
55
|
+
repl ||= $eturem_repl if defined?($eturem_repl)
|
56
|
+
if repl && last_binding && exception.is_a?(StandardError)
|
57
|
+
require repl
|
58
|
+
last_binding.public_send(repl)
|
59
|
+
end
|
41
60
|
end
|
61
|
+
exit
|
42
62
|
end
|
data/lib/eturem/base.rb
CHANGED
@@ -1,309 +1,313 @@
|
|
1
1
|
require "eturem/version"
|
2
2
|
|
3
3
|
module Eturem
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
Kernel.load(file)
|
12
|
-
rescue Exception => exception
|
13
|
-
raise exception if exception.is_a? SystemExit
|
14
|
-
eturem.exception = exception
|
15
|
-
end
|
16
|
-
eturem.exception ? eturem : nil
|
4
|
+
@program_name = $PROGRAM_NAME.encode("utf-8")
|
5
|
+
|
6
|
+
def self.rescue
|
7
|
+
yield
|
8
|
+
rescue Exception => exception
|
9
|
+
raise exception if exception.is_a? SystemExit
|
10
|
+
exception
|
17
11
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
begin
|
27
|
-
TOPLEVEL_BINDING.eval(script, file, 1)
|
28
|
-
tp.disable
|
29
|
-
eturem.comeback_stderr
|
30
|
-
rescue Exception => exception
|
31
|
-
tp.disable
|
32
|
-
eturem.comeback_stderr
|
33
|
-
raise exception if exception.is_a? SystemExit
|
34
|
-
repl ||= $eturem_repl
|
35
|
-
use_repl = repl && last_binding && exception.is_a?(StandardError)
|
36
|
-
begin
|
37
|
-
eturem.exception = exception
|
38
|
-
$stderr.write eturem.inspect
|
39
|
-
rescue Exception => e
|
40
|
-
raise debug ? e : eturem.exception
|
41
|
-
end
|
42
|
-
return unless use_repl
|
43
|
-
require repl
|
44
|
-
last_binding.public_send(repl)
|
12
|
+
|
13
|
+
# load script and return exception if exception raised
|
14
|
+
# @param [String] filename script file
|
15
|
+
# @return [Exception] if exception raised
|
16
|
+
# @return [true] if exception did not raise
|
17
|
+
def self.load(filename, wrap = false)
|
18
|
+
self.rescue do
|
19
|
+
Kernel.load(filename, wrap)
|
45
20
|
end
|
46
21
|
end
|
47
|
-
|
22
|
+
|
48
23
|
def self.eval(expr, bind = nil, fname = "(eval)", lineno = 1)
|
49
|
-
|
50
|
-
begin
|
24
|
+
self.rescue do
|
51
25
|
bind ? Kernel.eval(expr, bind, fname, lineno) : Kernel.eval(expr)
|
52
|
-
rescue Exception => exception
|
53
|
-
raise exception if exception.is_a? SystemExit
|
54
|
-
eturem.exception = exception
|
55
26
|
end
|
56
|
-
return eturem.exception ? eturem : nil
|
57
27
|
end
|
58
|
-
|
59
|
-
def self.
|
60
|
-
|
28
|
+
|
29
|
+
def self.extend_exception(exception)
|
30
|
+
ext = _extend_exception(exception) ||
|
31
|
+
case exception
|
32
|
+
when SyntaxError then SyntaxErrorExt
|
33
|
+
when NameError then NameErrorExt
|
34
|
+
when ArgumentError then ArgumentErrorExt
|
35
|
+
else ExceptionExt
|
36
|
+
end
|
37
|
+
exception.extend ext
|
38
|
+
exception.eturem_prepare
|
61
39
|
end
|
62
|
-
|
63
|
-
def self.
|
64
|
-
|
65
|
-
if File.exist?(file)
|
66
|
-
script = File.binread(file)
|
67
|
-
encoding = "utf-8"
|
68
|
-
if script.match(/\A(?:#!.*\R)?#.*coding *[:=] *(?<encoding>[^\s:]+)/)
|
69
|
-
encoding = Regexp.last_match(:encoding)
|
70
|
-
end
|
71
|
-
script.force_encoding(encoding)
|
72
|
-
end
|
73
|
-
return script
|
40
|
+
|
41
|
+
def self.program_name
|
42
|
+
@program_name
|
74
43
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
@@
|
80
|
-
@@
|
81
|
-
@@
|
82
|
-
@@
|
83
|
-
@@
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
def self.inspect_methods
|
89
|
-
return @inspect_methods
|
44
|
+
|
45
|
+
|
46
|
+
module Base
|
47
|
+
@@eturem_output_backtrace = true
|
48
|
+
@@eturem_output_original = true
|
49
|
+
@@eturem_output_script = true
|
50
|
+
@@eturem_use_coderay = false
|
51
|
+
@@eturem_before_line_num = 2
|
52
|
+
@@eturem_after_line_num = 2
|
53
|
+
|
54
|
+
def self.output_backtrace=(value)
|
55
|
+
@@eturem_output_backtrace = value
|
90
56
|
end
|
91
|
-
|
92
|
-
def self.
|
93
|
-
@@
|
94
|
-
@@output_original = config[:output_original] if config.has_key?(:output_original)
|
95
|
-
@@output_script = config[:output_script] if config.has_key?(:output_script)
|
96
|
-
@@use_coderay = config[:use_coderay] if config.has_key?(:use_coderay)
|
97
|
-
@@before_line_num = config[:before_line_num] if config.has_key?(:before_line_num)
|
98
|
-
@@after_line_num = config[:after_line_num] if config.has_key?(:after_line_num)
|
57
|
+
|
58
|
+
def self.output_original=(value)
|
59
|
+
@@eturem_output_original = value
|
99
60
|
end
|
100
|
-
|
101
|
-
def
|
102
|
-
|
103
|
-
@scripts = {}
|
104
|
-
@decoration = {}
|
105
|
-
if replace_stderr
|
106
|
-
@stderr = $stderr
|
107
|
-
$stderr = self
|
108
|
-
end
|
61
|
+
|
62
|
+
def self.output_script=(value)
|
63
|
+
@@eturem_output_script = value
|
109
64
|
end
|
110
|
-
|
111
|
-
def
|
112
|
-
|
113
|
-
@exception_s = exception.to_s
|
114
|
-
|
115
|
-
eturem_path = File.dirname(File.expand_path(__FILE__))
|
116
|
-
@backtrace_locations = (@exception.backtrace_locations || []).reject do |location|
|
117
|
-
path = File.expand_path(location.path)
|
118
|
-
path.start_with?(eturem_path) || path.end_with?("/rubygems/core_ext/kernel_require.rb")
|
119
|
-
end
|
120
|
-
|
121
|
-
if @exception.is_a?(SyntaxError) && @exception_s.match(/\A(?<path>.+?)\:(?<lineno>\d+)/)
|
122
|
-
@path = Regexp.last_match(:path)
|
123
|
-
@lineno = Regexp.last_match(:lineno).to_i
|
124
|
-
else
|
125
|
-
backtrace_locations_shift
|
126
|
-
end
|
127
|
-
|
128
|
-
@script_lines = read_script(@path) || []
|
129
|
-
@output_linenos = default_output_linenos
|
130
|
-
prepare
|
65
|
+
|
66
|
+
def self.use_coderay=(value)
|
67
|
+
@@eturem_use_coderay = value
|
131
68
|
end
|
132
|
-
|
133
|
-
def
|
134
|
-
|
135
|
-
error_message = exception_inspect
|
136
|
-
if error_message.empty?
|
137
|
-
str << original_exception_inspect
|
138
|
-
else
|
139
|
-
str = "#{original_exception_inspect}\n#{str}" if @@output_original
|
140
|
-
str << "#{error_message}\n"
|
141
|
-
end
|
142
|
-
str << script_inspect if @@output_script
|
143
|
-
return str
|
69
|
+
|
70
|
+
def self.before_line_num=(value)
|
71
|
+
@@eturem_before_line_num = value
|
144
72
|
end
|
145
|
-
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
str = "#{traceback_most_recent_call_last}\n"
|
150
|
-
backtraces = []
|
151
|
-
size = @backtrace_locations.size
|
152
|
-
format = "%#{8 + size.to_s.length}d: %s\n"
|
153
|
-
@backtrace_locations.reverse.each_with_index do |location, i|
|
154
|
-
backtraces.push(sprintf(format, size - i, location_inspect(location)))
|
155
|
-
end
|
156
|
-
|
157
|
-
if @exception_s == "stack level too deep"
|
158
|
-
str << backtraces[0..7].join
|
159
|
-
str << " ... #{backtraces.size - 12} levels...\n"
|
160
|
-
str << backtraces[-4..-1].join
|
161
|
-
else
|
162
|
-
str << backtraces.join
|
163
|
-
end
|
164
|
-
return str
|
73
|
+
|
74
|
+
def self.after_line_num=(value)
|
75
|
+
@@eturem_after_line_num = value
|
165
76
|
end
|
166
|
-
|
167
|
-
def
|
168
|
-
|
169
|
-
inspect_methods.keys.reverse_each do |key|
|
170
|
-
if (key.is_a?(Class) && @exception.is_a?(key)) ||
|
171
|
-
(key.is_a?(String) && @exception.class.to_s == key)
|
172
|
-
method = inspect_methods[key]
|
173
|
-
return method ? public_send(method) : ""
|
174
|
-
end
|
175
|
-
end
|
176
|
-
return ""
|
77
|
+
|
78
|
+
def self.highlight(str, pattern, highlight)
|
79
|
+
str.sub!(pattern) { "#{highlight}#{$1 || $&}\e[0m#{$2}" } if str
|
177
80
|
end
|
178
|
-
|
179
|
-
def
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
81
|
+
|
82
|
+
def self.unhighlight(str)
|
83
|
+
str.gsub(/\e\[[0-9;]*m/, "")
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.read_script(filename)
|
87
|
+
return [] unless File.exist?(filename)
|
88
|
+
script = File.binread(filename)
|
89
|
+
encoding = "utf-8"
|
90
|
+
if script.match(/\A(?:#!.*\R)?#.*coding *[:=] *(?<encoding>[^\s:]+)/)
|
91
|
+
encoding = Regexp.last_match(:encoding)
|
187
92
|
end
|
93
|
+
script.force_encoding(encoding).encode!("utf-8")
|
94
|
+
if @@eturem_use_coderay
|
95
|
+
require "coderay"
|
96
|
+
script = CodeRay.scan(script, :ruby).terminal
|
97
|
+
end
|
98
|
+
[""] + script.lines(chomp: true)
|
188
99
|
end
|
189
|
-
|
190
|
-
def
|
191
|
-
script_lines = read_script(path)
|
192
|
-
return "" unless script_lines
|
193
|
-
|
100
|
+
|
101
|
+
def self.script(lines, linenos, lineno)
|
194
102
|
str = ""
|
195
103
|
max_lineno_length = linenos.max.to_s.length
|
196
|
-
last_i = linenos.min - 1
|
104
|
+
last_i = linenos.min.to_i - 1
|
197
105
|
linenos.uniq.sort.each do |i|
|
198
|
-
line =
|
199
|
-
|
200
|
-
str
|
201
|
-
str
|
202
|
-
str
|
106
|
+
line = lines[i]
|
107
|
+
next unless line
|
108
|
+
str += " #{' ' * max_lineno_length} :\n" if last_i + 1 != i
|
109
|
+
str += (lineno == i ? " => " : " ")
|
110
|
+
str += sprintf("\e[1;34m%#{max_lineno_length}d\e[0m: %s\e[0m\n", i, line)
|
203
111
|
last_i = i
|
204
112
|
end
|
205
|
-
|
113
|
+
str
|
206
114
|
end
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
115
|
+
|
116
|
+
|
117
|
+
def eturem_prepare
|
118
|
+
this_filepath = File.expand_path(__FILE__)
|
119
|
+
@eturem_backtrace_locations = self.backtrace_locations || []
|
120
|
+
index = @eturem_backtrace_locations.index do |location|
|
121
|
+
File.expand_path(location.path) == this_filepath
|
122
|
+
end
|
123
|
+
@eturem_backtrace_locations = @eturem_backtrace_locations[0...index] if index
|
124
|
+
|
125
|
+
program_filepath = File.expand_path(Eturem.program_name)
|
126
|
+
@eturem_backtrace_locations.each do |location|
|
127
|
+
if File.expand_path(location.path) == program_filepath
|
128
|
+
def location.path; Eturem.program_name; end
|
129
|
+
if location.label == "<top (required)>"
|
130
|
+
def location.label; "<main>"; end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
@eturem_message = self.message
|
136
|
+
unless @eturem_message.encoding == Encoding::UTF_8
|
137
|
+
@eturem_message.force_encoding("utf-8")
|
138
|
+
unless @eturem_message.valid_encoding?
|
139
|
+
@eturem_message.force_encoding(Encoding.locale_charmap).encode!("utf-8")
|
140
|
+
end
|
213
141
|
end
|
214
|
-
|
215
|
-
|
142
|
+
|
143
|
+
if self.is_a?(SyntaxError) && @eturem_message.match(/\A(?<path>.+?)\:(?<lineno>\d+):\s*/)
|
144
|
+
@eturem_path = Regexp.last_match(:path)
|
145
|
+
@eturem_lineno = Regexp.last_match(:lineno).to_i
|
146
|
+
@eturem_message = Regexp.last_match.post_match
|
147
|
+
@eturem_path = Eturem.program_name if @eturem_path == program_filepath
|
216
148
|
else
|
217
|
-
|
149
|
+
eturem_backtrace_locations_shift
|
218
150
|
end
|
151
|
+
|
152
|
+
@eturem_script_lines = Eturem::Base.read_script(@eturem_path)
|
153
|
+
@eturem_output_linenos = eturem_default_output_linenos
|
219
154
|
end
|
220
|
-
|
221
|
-
def
|
222
|
-
|
155
|
+
|
156
|
+
def eturem_original_error_message()
|
157
|
+
@eturem_message.match(/\A(?<first_line>.*)/)
|
158
|
+
"#{@eturem_path}:#{@eturem_lineno}:in `#{@eturem_label}': " +
|
159
|
+
"\e[1m#{Regexp.last_match(:first_line)} (\e[4m#{self.class}\e[0;1m)" +
|
160
|
+
"#{Regexp.last_match.post_match.chomp}\e[0m\n"
|
223
161
|
end
|
224
|
-
|
225
|
-
def
|
226
|
-
@
|
162
|
+
|
163
|
+
def eturem_backtrace_str(order = :bottom)
|
164
|
+
str = @eturem_backtrace_locations.empty? ? "" : eturem_traceback(order)
|
165
|
+
str + (order == :top ? eturem_backtrace_str_top : eturem_backtrace_str_bottom)
|
227
166
|
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
case @exception
|
233
|
-
when NameError then prepare_name_error
|
234
|
-
when ArgumentError then prepare_argument_error
|
167
|
+
|
168
|
+
def eturem_backtrace
|
169
|
+
eturem_backtrace_locations.map do |location|
|
170
|
+
eturem_location_to_s(location)
|
235
171
|
end
|
236
172
|
end
|
237
|
-
|
238
|
-
def
|
239
|
-
|
240
|
-
@did_you_mean = Regexp.last_match.post_match.strip.scan(/\S+/)
|
241
|
-
@decoration[@lineno] = [@exception.name.to_s, "\e[1;31m\e[4m"]
|
242
|
-
|
243
|
-
@did_you_mean.each do |name|
|
244
|
-
index = @script_lines.index { |line| line.include?(name) }
|
245
|
-
next unless index
|
246
|
-
@decoration[index] = [name, "\e[1;33m"]
|
247
|
-
@output_linenos.push(index)
|
248
|
-
end
|
173
|
+
|
174
|
+
def eturem_location_to_s(location)
|
175
|
+
"#{location.path}:#{location.lineno}:in `#{location.label}'"
|
249
176
|
end
|
250
|
-
|
251
|
-
def
|
252
|
-
@
|
253
|
-
backtrace_locations_shift
|
254
|
-
@script_lines = read_script(@path)
|
255
|
-
@output_linenos = default_output_linenos
|
177
|
+
|
178
|
+
def eturem_backtrace_locations
|
179
|
+
@eturem_backtrace_locations
|
256
180
|
end
|
257
|
-
|
258
|
-
def
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
181
|
+
|
182
|
+
def eturem_message
|
183
|
+
""
|
184
|
+
end
|
185
|
+
|
186
|
+
def eturem_script
|
187
|
+
Eturem::Base.script(@eturem_script_lines, @eturem_output_linenos, @eturem_lineno)
|
263
188
|
end
|
264
|
-
|
265
|
-
def
|
266
|
-
|
189
|
+
|
190
|
+
def eturem_full_message(highlight: true, order: :bottom)
|
191
|
+
unless $stderr == STDERR && $stderr.tty?
|
192
|
+
highlight = false
|
193
|
+
order = :top
|
194
|
+
end
|
195
|
+
|
196
|
+
str = @@eturem_output_backtrace ? eturem_backtrace_str(order) : ""
|
197
|
+
ext_message = eturem_message
|
198
|
+
if ext_message.empty?
|
199
|
+
str += eturem_original_error_message
|
200
|
+
else
|
201
|
+
str = "#{eturem_original_error_message}\n#{str}" if @@eturem_output_original
|
202
|
+
str += "#{ext_message}\n"
|
203
|
+
end
|
204
|
+
str += eturem_script if @@eturem_output_script
|
205
|
+
|
206
|
+
highlight ? str : Eturem::Base.unhighlight(str)
|
267
207
|
end
|
268
|
-
|
269
|
-
|
270
|
-
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
def eturem_backtrace_locations_shift
|
212
|
+
location = @eturem_backtrace_locations.shift
|
213
|
+
@eturem_label = location.label
|
214
|
+
@eturem_path = location.path
|
215
|
+
@eturem_lineno = location.lineno
|
271
216
|
end
|
272
|
-
|
273
|
-
def
|
274
|
-
from = [1, @
|
275
|
-
to = [@
|
217
|
+
|
218
|
+
def eturem_default_output_linenos
|
219
|
+
from = [1, @eturem_lineno - @@eturem_before_line_num].max
|
220
|
+
to = [@eturem_script_lines.size - 1, @eturem_lineno + @@eturem_after_line_num].min
|
276
221
|
(from..to).to_a
|
277
222
|
end
|
278
|
-
|
279
|
-
def
|
280
|
-
|
223
|
+
|
224
|
+
def eturem_traceback(order = :bottom)
|
225
|
+
order == :top ? "" : "\e[1mTraceback\e[0m (most recent call last):\n"
|
281
226
|
end
|
282
|
-
|
283
|
-
def
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
227
|
+
|
228
|
+
def eturem_backtrace_str_bottom
|
229
|
+
lines = []
|
230
|
+
backtrace = eturem_backtrace
|
231
|
+
size = backtrace.size
|
232
|
+
format = "%#{8 + size.to_s.length}d: %s\n"
|
233
|
+
backtrace.reverse.each_with_index do |bt, i|
|
234
|
+
lines.push(sprintf(format, size - i, bt))
|
290
235
|
end
|
236
|
+
|
237
|
+
if @eturem_message == "stack level too deep"
|
238
|
+
lines = lines[-4..-1] +
|
239
|
+
[" ... #{lines.size - 12} levels...\n"] +
|
240
|
+
lines[0..7]
|
241
|
+
end
|
242
|
+
lines.join
|
291
243
|
end
|
292
|
-
|
293
|
-
def
|
294
|
-
|
295
|
-
|
296
|
-
return nil unless script
|
297
|
-
script.encode!("utf-8")
|
298
|
-
if @@use_coderay
|
299
|
-
require "coderay"
|
300
|
-
script = CodeRay.scan(script, :ruby).terminal
|
301
|
-
end
|
302
|
-
@scripts[file] = [""] + script.lines(chomp: true)
|
244
|
+
|
245
|
+
def eturem_backtrace_str_top
|
246
|
+
lines = eturem_backtrace.map do |bt|
|
247
|
+
" from #{bt}\n"
|
303
248
|
end
|
304
|
-
|
249
|
+
if @eturem_message == "stack level too deep"
|
250
|
+
lines = lines[0..7] +
|
251
|
+
[" ... #{lines.size - 12} levels...\n"] +
|
252
|
+
lines[-4..-1]
|
253
|
+
end
|
254
|
+
lines.join
|
305
255
|
end
|
306
256
|
end
|
257
|
+
|
258
|
+
|
259
|
+
module ExceptionExt
|
260
|
+
include Base
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
module NameErrorExt
|
265
|
+
include ExceptionExt
|
266
|
+
|
267
|
+
def eturem_prepare()
|
268
|
+
@eturem_corrections = self.respond_to?(:corrections) ? self.corrections : []
|
269
|
+
@eturem_corrections += Object.constants.select do |const|
|
270
|
+
const.casecmp?(self.name)
|
271
|
+
end
|
272
|
+
@eturem_corrections.uniq!
|
273
|
+
def self.corrections; @eturem_corrections; end
|
274
|
+
super
|
275
|
+
uname = self.name.to_s.encode("utf-8")
|
276
|
+
if @eturem_script_lines[@eturem_lineno]
|
277
|
+
Eturem::Base.highlight(@eturem_script_lines[@eturem_lineno], uname, "\e[1;4;31m")
|
278
|
+
end
|
279
|
+
@eturem_corrections.each do |name|
|
280
|
+
index = @eturem_script_lines.index { |line| line.include?(name.to_s.encode("utf-8")) }
|
281
|
+
next unless index
|
282
|
+
Eturem::Base.highlight(@eturem_script_lines[index], name.to_s.encode("utf-8"), "\e[1;33m")
|
283
|
+
@eturem_output_linenos.push(index)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
module ArgumentErrorExt
|
290
|
+
include ExceptionExt
|
291
|
+
|
292
|
+
def eturem_prepare()
|
293
|
+
super
|
294
|
+
@eturem_method = @eturem_label
|
295
|
+
eturem_backtrace_locations_shift
|
296
|
+
@eturem_script_lines = Eturem::Base.read_script(@eturem_path)
|
297
|
+
@eturem_output_linenos = eturem_default_output_linenos
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
|
302
|
+
module SyntaxErrorExt
|
303
|
+
include ExceptionExt
|
307
304
|
|
308
|
-
|
305
|
+
def eturem_original_error_message()
|
306
|
+
ret = "#{@eturem_path}:#{@eturem_lineno}: #{@eturem_message}"
|
307
|
+
unless @eturem_path == Eturem.program_name
|
308
|
+
ret = "\e[1m#{ret} (\e[4m#{self.class}\e[0;1m)\e[0m"
|
309
|
+
end
|
310
|
+
ret + "\n"
|
311
|
+
end
|
312
|
+
end
|
309
313
|
end
|