eturem 0.4.0 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,27 +1,31 @@
1
- # Eturem
2
-
3
- Easy To Understand Ruby Error Message.
4
-
5
- [日本語説明(こちらの方が詳細)](https://github.com/nodai2hITC/eturem/blob/master/README.ja.md)
6
-
7
- ## Installation
8
-
9
- install it yourself as:
10
-
11
- $ gem install eturem
12
-
13
- ## Usage
14
-
15
- $ ruby -returem <your_script.rb>
16
-
17
- ## Contributing
18
-
19
- 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.
20
-
21
- ## License
22
-
23
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
24
-
25
- ## Code of Conduct
26
-
27
- Everyone interacting in the Eturem project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/nodai2hITC/eturem/blob/master/CODE_OF_CONDUCT.md).
1
+ # Eturem
2
+
3
+ Easy To Understand Ruby Error Message.
4
+
5
+ [日本語説明(こちらの方が詳細)](https://github.com/nodai2hITC/eturem/blob/master/README.ja.md)
6
+
7
+ ## Installation
8
+
9
+ install it yourself as:
10
+
11
+ $ gem install eturem
12
+
13
+ ## Usage
14
+
15
+ $ ruby -returem <your_script.rb>
16
+
17
+ or
18
+
19
+ $ eturem <your_script.rb>
20
+
21
+ ## Contributing
22
+
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.
24
+
25
+ ## License
26
+
27
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
28
+
29
+ ## Code of Conduct
30
+
31
+ Everyone interacting in the Eturem project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/nodai2hITC/eturem/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
8
- t.warning = false
9
- end
10
-
11
- task :default => :test
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ t.warning = false
9
+ end
10
+
11
+ task :default => :test
data/bin/console CHANGED
@@ -1,14 +1,14 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "eturem"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "eturem"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup CHANGED
@@ -1,8 +1,8 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/eturem.gemspec CHANGED
@@ -1,36 +1,30 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "eturem/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "eturem"
8
- spec.version = Eturem::VERSION
9
- spec.authors = ["nodai2hITC"]
10
- spec.email = ["nodai2h.itc@gmail.com"]
11
-
12
- spec.summary = %q{Easy To Understand Ruby Error Message.}
13
- spec.description = %q{Easy To Understand Ruby Error Message.}
14
- spec.homepage = "https://github.com/nodai2hITC/eturem"
15
- spec.license = "MIT"
16
-
17
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
- # to allow pushing to a single host or delete this section to allow pushing to any host.
19
- if spec.respond_to?(:metadata)
20
- # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
- else
22
- raise "RubyGems 2.0 or newer is required to protect against " \
23
- "public gem pushes."
24
- end
25
-
26
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
- f.match(%r{^(test|spec|features)/})
28
- end
29
- spec.bindir = "exe"
30
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
- 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
- end
1
+
2
+ require_relative 'lib/eturem/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "eturem"
6
+ spec.version = Eturem::VERSION
7
+ spec.authors = ["nodai2hITC"]
8
+ spec.email = ["nodai2h.itc@gmail.com"]
9
+
10
+ spec.summary = %q{Easy To Understand Ruby Error Message.}
11
+ spec.description = %q{Easy To Understand Ruby Error Message.}
12
+ spec.homepage = "https://github.com/nodai2hITC/eturem"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
15
+
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
21
+
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)/}) }
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
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
@@ -1,42 +1,79 @@
1
- enable = true
2
- debug = false
3
- lang = "en"
4
- output_backtrace = true
5
- output_original = true
6
- output_script = true
7
- use_coderay = false
8
- before_line_num = 2
9
- after_line_num = 2
10
- repl = nil
11
-
12
- if File.exist?($PROGRAM_NAME)
13
- config_file = File.join(Dir.home, ".eturem")
14
- if File.exist?(config_file)
15
- config = File.read(config_file)
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
- use_coderay = true if config.match( /^use_coderay\s*\:\s*(?:true|on|1)/i)
23
- before_line_num = Regexp.last_match(:num).to_i if config.match(/^before_line_num\s*\:\s*(?<num>\d+)/i)
24
- after_line_num = Regexp.last_match(:num).to_i if config.match( /^after_line_num\s*\:\s*(?<num>\d+)/i)
25
- repl = Regexp.last_match(:repl).downcase if config.match(/^repl\s*\:\s*(?<repl>irb|pry)/i)
26
- end
27
-
28
- if enable
29
- require "eturem/#{lang}" unless defined?(Eturem)
30
- Eturem.set_config(
31
- output_backtrace: output_backtrace,
32
- output_original: output_original,
33
- output_script: output_script,
34
- use_coderay: use_coderay,
35
- before_line_num: before_line_num,
36
- after_line_num: after_line_num
37
- )
38
-
39
- Eturem.load_and_output($PROGRAM_NAME, repl, debug)
40
- exit
41
- end
42
- end
1
+ enable = true
2
+ debug = false
3
+ lang = "en"
4
+ output_backtrace = true
5
+ output_original = true
6
+ output_script = true
7
+ override_warning = true
8
+ use_coderay = false
9
+ before_line_num = 2
10
+ after_line_num = 2
11
+ repl = nil
12
+
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
+ if File.exist?($PROGRAM_NAME)
40
+ program_file = File.open($PROGRAM_NAME, "rb")
41
+ script = program_file.read
42
+ if script.match(/^__END__\R/)
43
+ program_file.pos = Regexp.last_match.end(0)
44
+ encoding = "utf-8"
45
+ if script.match(/\A(?:#!.*\R)?#.*coding *[:=] *(?<encoding>[^\s:]+)/)
46
+ encoding = Regexp.last_match(:encoding)
47
+ end
48
+ program_file.set_encoding(encoding)
49
+ Object.const_set(:DATA, program_file)
50
+ program_file
51
+ else
52
+ program_file.close
53
+ end
54
+ end
55
+
56
+ eturem_path = File.expand_path("..", __FILE__)
57
+ last_binding = nil
58
+ tracepoint = TracePoint.trace(:raise) do |tp|
59
+ last_binding = tp.binding unless File.expand_path(tp.path).start_with?(eturem_path)
60
+ end
61
+ exception = Eturem.load(File.expand_path(Eturem.program_name))
62
+ tracepoint.disable
63
+
64
+ if exception.is_a?(Exception)
65
+ begin
66
+ Eturem.extend_exception(exception)
67
+ $stderr.write exception.eturem_full_message
68
+ rescue Exception => e
69
+ raise debug ? e : exception
70
+ end
71
+
72
+ repl ||= $eturem_repl if defined?($eturem_repl)
73
+ if repl && last_binding && exception.is_a?(StandardError)
74
+ require repl
75
+ last_binding.public_send(repl)
76
+ end
77
+ end
78
+ exit
79
+ end
data/lib/eturem/base.rb CHANGED
@@ -1,309 +1,312 @@
1
1
  require "eturem/version"
2
2
 
3
3
  module Eturem
4
- # load script and return eturem_exception if exception raised
5
- # @param [String] file script file
6
- # @return [Eturem::Base] if exception raised
7
- # @return [nil] if exception did not raise
8
- def self.load(file)
9
- eturem = @eturem_class.new(file)
10
- begin
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
- def self.load_and_output(file, repl = nil, debug = false)
20
- eturem = @eturem_class.new(file, true)
21
- last_binding = nil
22
- tp = TracePoint.trace(:raise) do |t|
23
- last_binding = t.binding unless File.expand_path(t.path) == File.expand_path(__FILE__)
24
- end
25
- script = read_script(file)
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
- eturem = @eturem_class.new(fname)
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.set_config(config)
60
- @eturem_class.set_config(config)
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.read_script(file)
64
- script = nil
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
- class Base
77
- attr_reader :exception, :backtrace_locations, :path, :lineno, :label
78
-
79
- @@output_backtrace = true
80
- @@output_original = true
81
- @@output_script = true
82
- @@use_coderay = false
83
- @@before_line_num = 2
84
- @@after_line_num = 2
85
-
86
- @inspect_methods = {}
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.set_config(config)
93
- @@output_backtrace = config[:output_backtrace] if config.has_key?(:output_backtrace)
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 initialize(load_file, replace_stderr = false)
102
- @load_file = load_file.encode("utf-8")
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 exception=(exception)
112
- @exception = exception
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 inspect
134
- str = @@output_backtrace ? backtrace_inspect : ""
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 backtrace_inspect
147
- return "" if @backtrace_locations.empty?
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 exception_inspect
168
- inspect_methods = self.class.inspect_methods
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 original_exception_inspect
180
- if @exception.is_a? SyntaxError
181
- return "#{@exception_s.chomp}\n"
182
- else
183
- location_str = "#{@path}:#{@lineno}:in `#{@label}'"
184
- @exception_s.match(/\A(?<first_line>.*)/)
185
- return "#{location_str}: #{Regexp.last_match(:first_line)} (\e[4m#{@exception.class}\e[0m)" +
186
- "#{Regexp.last_match.post_match.chomp}\n"
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 script_inspect(path = @path, linenos = @output_linenos, lineno = @lineno, decoration = @decoration)
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 = script_lines[i]
199
- line = highlight(line, decoration[i][0], decoration[i][1]) if decoration[i]
200
- str << "\e[0m #{' ' * max_lineno_length} :\n" if last_i + 1 != i
201
- str << (lineno == i ? "\e[0m => \e[1;34m" : "\e[0m \e[1;34m")
202
- str << sprintf("%#{max_lineno_length}d\e[0m: %s\n", i, line)
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
- return str
113
+ str
206
114
  end
207
-
208
- def write(*str)
209
- message = nil
210
- if str.join.force_encoding("utf-8").match(/^(.+?):(\d+):\s*warning:\s*/)
211
- path, lineno, warning = $1, $2.to_i, $'.strip
212
- message = warning_message(path, lineno, warning)
115
+
116
+
117
+ def eturem_prepare
118
+ this_dirpath = File.dirname(File.expand_path(__FILE__))
119
+ @eturem_backtrace_locations = (self.backtrace_locations || []).reject do |location|
120
+ File.expand_path(location.path).start_with?(this_dirpath) ||
121
+ location.path.end_with?(
122
+ "/rubygems/core_ext/kernel_require.rb",
123
+ "/rubygems/core_ext/kernel_require.rb>"
124
+ )
125
+ end
126
+
127
+ program_filepath = File.expand_path(Eturem.program_name)
128
+ @eturem_backtrace_locations.each do |location|
129
+ if File.expand_path(location.path) == program_filepath
130
+ def location.path; Eturem.program_name; end
131
+ if location.label == "<top (required)>"
132
+ def location.label; "<main>"; end
133
+ end
134
+ end
213
135
  end
214
- if message
215
- @stderr.write(message)
136
+
137
+ @eturem_message = self.message
138
+ unless @eturem_message.encoding == Encoding::UTF_8
139
+ @eturem_message.force_encoding("utf-8")
140
+ unless @eturem_message.valid_encoding?
141
+ @eturem_message.force_encoding(Encoding.locale_charmap).encode!("utf-8")
142
+ end
143
+ end
144
+
145
+ if self.is_a?(SyntaxError) && @eturem_message.match(/\A(?<path>.+?)\:(?<lineno>\d+):\s*/)
146
+ @eturem_path = Regexp.last_match(:path)
147
+ @eturem_lineno = Regexp.last_match(:lineno).to_i
148
+ @eturem_message = Regexp.last_match.post_match
149
+ @eturem_path = Eturem.program_name if @eturem_path == program_filepath
216
150
  else
217
- @stderr.write(*str)
151
+ eturem_backtrace_locations_shift
218
152
  end
153
+
154
+ @eturem_script_lines = Eturem::Base.read_script(@eturem_path)
155
+ @eturem_output_linenos = eturem_default_output_linenos
219
156
  end
220
-
221
- def comeback_stderr
222
- $stderr = @stderr || STDERR
157
+
158
+ def eturem_original_error_message()
159
+ @eturem_message.match(/\A(?<first_line>.*)/)
160
+ "#{@eturem_path}:#{@eturem_lineno}:in `#{@eturem_label}': " +
161
+ "\e[1m#{Regexp.last_match(:first_line)} (\e[4m#{self.class}\e[0;1m)" +
162
+ "#{Regexp.last_match.post_match.chomp}\e[0m\n"
223
163
  end
224
-
225
- def to_s
226
- @exception_s
164
+
165
+ def eturem_backtrace_str(order = :top)
166
+ str = @eturem_backtrace_locations.empty? ? "" : eturem_traceback(order)
167
+ str + (order == :top ? eturem_backtrace_str_top : eturem_backtrace_str_bottom)
227
168
  end
228
-
229
- private
230
-
231
- def prepare
232
- case @exception
233
- when NameError then prepare_name_error
234
- when ArgumentError then prepare_argument_error
169
+
170
+ def eturem_backtrace
171
+ eturem_backtrace_locations.map do |location|
172
+ eturem_location_to_s(location)
235
173
  end
236
174
  end
237
-
238
- def prepare_name_error
239
- return unless @exception_s.match(/Did you mean\?/)
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
175
+
176
+ def eturem_location_to_s(location)
177
+ "#{location.path}:#{location.lineno}:in `#{location.label}'"
249
178
  end
250
-
251
- def prepare_argument_error
252
- @method = @label
253
- backtrace_locations_shift
254
- @script_lines = read_script(@path)
255
- @output_linenos = default_output_linenos
179
+
180
+ def eturem_backtrace_locations
181
+ @eturem_backtrace_locations
256
182
  end
257
-
258
- def backtrace_locations_shift
259
- @label = @backtrace_locations.first.label
260
- @path = @backtrace_locations.first.path
261
- @lineno = @backtrace_locations.first.lineno
262
- @backtrace_locations.shift
183
+
184
+ def eturem_message
185
+ ""
263
186
  end
264
-
265
- def traceback_most_recent_call_last
266
- "Traceback (most recent call last):"
187
+
188
+ def eturem_script
189
+ Eturem::Base.script(@eturem_script_lines, @eturem_output_linenos, @eturem_lineno)
267
190
  end
268
-
269
- def location_inspect(location)
270
- "from #{location.path}:#{location.lineno}:in `#{location.label}'"
191
+
192
+ def eturem_full_message(highlight: true, order: :top)
193
+ highlight = false unless $stderr == STDERR && $stderr.tty?
194
+
195
+ str = @@eturem_output_backtrace ? eturem_backtrace_str(order) : ""
196
+ ext_message = eturem_message
197
+ if ext_message.empty?
198
+ str += eturem_original_error_message
199
+ else
200
+ str = "#{eturem_original_error_message}\n#{str}" if @@eturem_output_original
201
+ str += "#{ext_message}\n"
202
+ end
203
+ str += eturem_script if @@eturem_output_script
204
+
205
+ highlight ? str : Eturem::Base.unhighlight(str)
271
206
  end
272
-
273
- def default_output_linenos
274
- from = [1, @lineno - @@before_line_num].max
275
- to = [@script_lines.size - 1, @lineno + @@after_line_num].min
207
+
208
+ private
209
+
210
+ def eturem_backtrace_locations_shift
211
+ location = @eturem_backtrace_locations.shift
212
+ @eturem_label = location.label
213
+ @eturem_path = location.path
214
+ @eturem_lineno = location.lineno
215
+ end
216
+
217
+ def eturem_default_output_linenos
218
+ from = [1, @eturem_lineno - @@eturem_before_line_num].max
219
+ to = [@eturem_script_lines.size - 1, @eturem_lineno + @@eturem_after_line_num].min
276
220
  (from..to).to_a
277
221
  end
278
-
279
- def highlight(str, keyword, color)
280
- str.to_s.gsub(keyword){ "#{color}#{$&}\e[0m" }
222
+
223
+ def eturem_traceback(order = :bottom)
224
+ order == :top ? "" : "\e[1mTraceback\e[0m (most recent call last):\n"
281
225
  end
282
-
283
- def warning_message(file, line, warning)
284
- case warning
285
- when "found `= literal' in conditional, should be =="
286
- "#{file}:#{line}: warning: #{warning}\n" +
287
- script_inspect(file, [line], line, { line => [/(?<![><!=])=(?!=)/, "\e[1;31m\e[4m"] })
288
- else
289
- nil
226
+
227
+ def eturem_backtrace_str_bottom
228
+ lines = []
229
+ backtrace = eturem_backtrace
230
+ size = backtrace.size
231
+ format = "%#{8 + size.to_s.length}d: %s\n"
232
+ backtrace.reverse.each_with_index do |bt, i|
233
+ lines.push(sprintf(format, size - i, bt))
290
234
  end
235
+
236
+ if @eturem_message == "stack level too deep"
237
+ lines = lines[-4..-1] +
238
+ [" ... #{lines.size - 12} levels...\n"] +
239
+ lines[0..7]
240
+ end
241
+ lines.join
291
242
  end
292
-
293
- def read_script(file)
294
- unless @scripts[file]
295
- script = Eturem.read_script(file)
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)
243
+
244
+ def eturem_backtrace_str_top
245
+ lines = eturem_backtrace.map do |bt|
246
+ " from #{bt}\n"
303
247
  end
304
- return @scripts[file]
248
+ if @eturem_message == "stack level too deep"
249
+ lines = lines[0..7] +
250
+ [" ... #{lines.size - 12} levels...\n"] +
251
+ lines[-4..-1]
252
+ end
253
+ lines.join
305
254
  end
306
255
  end
256
+
257
+
258
+ module ExceptionExt
259
+ include Base
260
+ end
261
+
262
+
263
+ module NameErrorExt
264
+ include ExceptionExt
265
+
266
+ def eturem_prepare()
267
+ @eturem_corrections = self.respond_to?(:corrections) ? self.corrections : []
268
+ @eturem_corrections += Object.constants.map(&:to_s).select do |const|
269
+ const.casecmp?(self.name)
270
+ end
271
+ @eturem_corrections.uniq!
272
+ def self.corrections; @eturem_corrections; end
273
+ super
274
+ uname = self.name.to_s.encode("utf-8")
275
+ if @eturem_script_lines[@eturem_lineno]
276
+ Eturem::Base.highlight(@eturem_script_lines[@eturem_lineno], uname, "\e[1;4;31m")
277
+ end
278
+ @eturem_corrections.each do |name|
279
+ index = @eturem_script_lines.index { |line| line.include?(name.to_s.encode("utf-8")) }
280
+ next unless index
281
+ Eturem::Base.highlight(@eturem_script_lines[index], name.to_s.encode("utf-8"), "\e[1;33m")
282
+ @eturem_output_linenos.push(index)
283
+ end
284
+ end
285
+ end
286
+
287
+
288
+ module ArgumentErrorExt
289
+ include ExceptionExt
290
+
291
+ def eturem_prepare()
292
+ super
293
+ @eturem_method = @eturem_label
294
+ eturem_backtrace_locations_shift
295
+ @eturem_script_lines = Eturem::Base.read_script(@eturem_path)
296
+ @eturem_output_linenos = eturem_default_output_linenos
297
+ end
298
+ end
299
+
300
+
301
+ module SyntaxErrorExt
302
+ include ExceptionExt
307
303
 
308
- @eturem_class = Base
304
+ def eturem_original_error_message()
305
+ ret = "#{@eturem_path}:#{@eturem_lineno}: #{@eturem_message}"
306
+ unless @eturem_path == Eturem.program_name
307
+ ret = "\e[1m#{ret} (\e[4m#{self.class}\e[0;1m)\e[0m"
308
+ end
309
+ ret + "\n"
310
+ end
311
+ end
309
312
  end