better_errors 2.8.3 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 616022aff59a6fbf38d22ce25749211fc988ef60650f0b2d1fb01244cf558d82
4
- data.tar.gz: 108c7f49871d078cd84ad46da808efd29c75898ba592a3ca2911cd9a47b868e7
3
+ metadata.gz: f8ee0f98712b916f23c694b2221baec07d555acaac8ded033faf70bcd15a2f17
4
+ data.tar.gz: 60190607c78fc8a278d8f4b3f0a76ad49f958cf844d145d57d64a9afb986e635
5
5
  SHA512:
6
- metadata.gz: 183597138988fa4048097461f8c805b97478b314a6e0f7b76819a4ffa0b99fe905262f5343457a3fb64a3494b222eae73cf2bc659956146e111b5646427c2ed4
7
- data.tar.gz: b9e683652c3121d376f883ed0f773986cc8b8b8f089920a829b5e9a35ff1b4e4c86d2e4a4a9bbbf3c88a3648ce3fe80db77793942be93a548d902f3ec69e6dcf
6
+ metadata.gz: 456e4d9788580cdb530a3f3b26a3bb4dfa67d3e49b83043118e2bfbdb298d945964b9ddb71138a20599a3fcdd6106e9b484e81ae38e42cb2e9b401fdf7ee0f24
7
+ data.tar.gz: cca1e3e1858f34b56221d0b8720c9ae310e667117d458a474fb9787ab8d31cd5a4419667e74fde4b7b64682e3c038666e05b72d8c0429da8bac5c11a94adb1f5
@@ -0,0 +1,130 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ schedule:
7
+ - cron: '0 0 12,26 * *' # roughly every two weeks to run on new Ruby versions
8
+ pull_request:
9
+ branches: [ master ]
10
+ workflow_dispatch:
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ ruby:
19
+ - 2.2
20
+ - 2.3
21
+ - 2.4
22
+ - 2.5
23
+ - 2.6
24
+ - 2.7
25
+ # - ruby-head
26
+ # - truffleruby-head
27
+ gemfile:
28
+ # These are located in the gemfiles/ folder
29
+ - rails42
30
+ - rails50
31
+ - rails51
32
+ - rails52
33
+ - rails60
34
+ - rails42_haml
35
+ - rails50_haml
36
+ - rails51_haml
37
+ - rails52_haml
38
+ - rails60_haml
39
+ - rails42_boc
40
+ - rails50_boc
41
+ - rails51_boc
42
+ - rails52_boc
43
+ - rails60_boc
44
+ - rack
45
+ - rack_boc
46
+ # - pry09
47
+ # - pry10
48
+ # - pry11
49
+ exclude:
50
+ - { ruby: 2.2, gemfile: rails60 }
51
+ - { ruby: 2.2, gemfile: rails60_boc }
52
+ - { ruby: 2.2, gemfile: rails60_haml }
53
+ - { ruby: 2.3, gemfile: rails42 }
54
+ - { ruby: 2.3, gemfile: rails42_boc }
55
+ - { ruby: 2.3, gemfile: rails42_haml }
56
+ - { ruby: 2.3, gemfile: rails60 }
57
+ - { ruby: 2.3, gemfile: rails60_boc }
58
+ - { ruby: 2.3, gemfile: rails60_haml }
59
+ - { ruby: 2.4, gemfile: rails42 }
60
+ - { ruby: 2.4, gemfile: rails42_boc }
61
+ - { ruby: 2.4, gemfile: rails42_haml }
62
+ - { ruby: 2.4, gemfile: rails60 }
63
+ - { ruby: 2.4, gemfile: rails60_boc }
64
+ - { ruby: 2.4, gemfile: rails60_haml }
65
+ - { ruby: 2.5, gemfile: rails42 }
66
+ - { ruby: 2.5, gemfile: rails42_boc }
67
+ - { ruby: 2.5, gemfile: rails42_haml }
68
+ - { ruby: 2.6, gemfile: rails42 }
69
+ - { ruby: 2.6, gemfile: rails42_boc }
70
+ - { ruby: 2.6, gemfile: rails42_haml }
71
+ - { ruby: 2.7, gemfile: rails42 }
72
+ - { ruby: 2.7, gemfile: rails42_boc }
73
+ - { ruby: 2.7, gemfile: rails42_haml }
74
+ # - { ruby: ruby-head, gemfile: rails42 }
75
+ # - { ruby: ruby-head, gemfile: rails42_boc }
76
+ # - { ruby: ruby-head, gemfile: rails42_haml }
77
+ - { ruby: truffleruby-head, gemfile: rails42_boc }
78
+ - { ruby: truffleruby-head, gemfile: rails50_boc }
79
+ - { ruby: truffleruby-head, gemfile: rails51_boc }
80
+ - { ruby: truffleruby-head, gemfile: rails52_boc }
81
+ - { ruby: truffleruby-head, gemfile: rails60_boc }
82
+ - { ruby: truffleruby-head, gemfile: rack_boc }
83
+
84
+ steps:
85
+
86
+ - uses: actions/checkout@v2
87
+
88
+ - name: Set up Ruby
89
+ uses: ruby/setup-ruby@v1
90
+ with:
91
+ ruby-version: ${{ matrix.ruby }}
92
+
93
+ - uses: actions/cache@v2
94
+ with:
95
+ path: gemfiles/vendor/bundle
96
+ key: v3-${{ runner.os }}-branch-${{ github.ref }}-ruby-${{ matrix.ruby }}-gemfile-${{ matrix.gemfile }}-${{ hashFiles(format('gemfiles/{0}.gemfile', matrix.gemfile)) }}
97
+ restore-keys: |
98
+ v3-${{ runner.os }}-branch-${{ github.ref }}-ruby-${{ matrix.ruby }}-gemfile-${{ matrix.gemfile }}
99
+ v3-${{ runner.os }}-branch-master-ruby-${{ matrix.ruby }}-gemfile-${{ matrix.gemfile }}
100
+
101
+ - name: Bundle install
102
+ run: |
103
+ bundle config path vendor/bundle
104
+ bundle install --jobs 4 --retry 3
105
+ env:
106
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
107
+
108
+ - name: RSpec
109
+ run: bundle exec rspec -f doc --color
110
+ env:
111
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
112
+
113
+ - name: Report to Coveralls
114
+ uses: coverallsapp/github-action@v1.1.2
115
+ with:
116
+ github-token: ${{ secrets.github_token }}
117
+ flag-name: test-${{ matrix.ruby }}-${{ matrix.gemfile }}
118
+ parallel: true
119
+
120
+
121
+ finish:
122
+ needs: test
123
+ runs-on: ubuntu-latest
124
+ steps:
125
+
126
+ - name: Report completion to Coveralls
127
+ uses: coverallsapp/github-action@v1.1.2
128
+ with:
129
+ github-token: ${{ secrets.github_token }}
130
+ parallel-finished: true
@@ -0,0 +1,64 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+
13
+ - uses: actions/checkout@v2
14
+
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: 2.7
19
+
20
+ - uses: actions/cache@v2
21
+ with:
22
+ path: vendor/bundle
23
+ key: v1-${{ runner.os }}-${{ hashFiles('Gemfile', 'better_errors.gemspec') }}
24
+ restore-keys: |
25
+ v1-${{ runner.os }}
26
+
27
+ - name: Bundle install
28
+ run: |
29
+ bundle config path vendor/bundle
30
+ bundle install --jobs 4 --retry 3
31
+
32
+ - name: Get release version
33
+ id: get_version
34
+ run: |
35
+ version="${github_ref//refs\/tags\/v/}"
36
+ echo "${version}"
37
+ echo "::set-output name=version::${version}"
38
+ env:
39
+ github_ref: ${{ github.ref }}
40
+
41
+ - name: Get Release
42
+ id: get_release
43
+ uses: bruceadams/get-release@v1.2.2
44
+ env:
45
+ GITHUB_TOKEN: ${{ github.token }}
46
+
47
+ - name: Set gem version
48
+ run: |
49
+ bundle exec gem bump better_errors --version ${{ steps.get_version.outputs.version }} --no-commit
50
+
51
+ - name: Build gem
52
+ run: gem build better_errors.gemspec
53
+
54
+ - name: Upload gem to Release
55
+ uses: actions/upload-release-asset@v1
56
+ env:
57
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58
+ with:
59
+ upload_url: ${{ steps.get_release.outputs.upload_url }}
60
+ asset_path: ./better_errors-${{ steps.get_version.outputs.version }}.gem
61
+ asset_name: better_errors-${{ steps.get_version.outputs.version }}.gem
62
+ asset_content_type: application/octet-stream
63
+
64
+ # TODO: if this release is on master, add a commit updating the version in master.
@@ -0,0 +1 @@
1
+ 2.7.2
data/Gemfile CHANGED
@@ -2,5 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- # gem "pry-byebug"
6
5
  gem 'simplecov', require: false
6
+ gem 'simplecov-lcov', require: false
7
+
8
+ # For managing release version in CI
9
+ gem 'gem-release'
10
+
11
+ # gem "pry-byebug"
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- [![Build Status](https://travis-ci.org/BetterErrors/better_errors.svg)](https://travis-ci.org/BetterErrors/better_errors)
1
+ [![Build Status](https://github.com/BetterErrors/better_errors/workflows/CI/badge.svg?event=push&branch=master)](https://github.com/BetterErrors/better_errors/actions?query=branch%3Amaster)
2
2
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6bc3e7d6118d47e6959b16690b815909)](https://www.codacy.com/app/BetterErrors/better_errors?utm_source=github.com&utm_medium=referral&utm_content=BetterErrors/better_errors&utm_campaign=Badge_Grade)
3
- [![Coverage](https://coveralls.io/repos/github/BetterErrors/better_errors/badge.svg?branch=master)](https://coveralls.io/github/BetterErrors/better_errors?branch=master)
3
+ [![Test Coverage](https://coveralls.io/repos/github/BetterErrors/better_errors/badge.svg?branch=master)](https://coveralls.io/github/BetterErrors/better_errors?branch=master)
4
4
  [![Gem Version](https://img.shields.io/gem/v/better_errors.svg)](https://rubygems.org/gems/better_errors)
5
5
 
6
6
  # Better Errors
@@ -4,6 +4,7 @@ gem 'rack', RUBY_VERSION < '2.2.2' ? '~> 1.6' : '~> 2.0'
4
4
  gem "binding_of_caller"
5
5
  gem "pry", "~> 0.10.0"
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem 'rack', RUBY_VERSION < '2.2.2' ? '~> 1.6' : '~> 2.0'
4
4
  gem "pry", "~> 0.11.0pre"
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem 'rack', RUBY_VERSION < '2.2.2' ? '~> 1.6' : '~> 2.0'
4
4
  gem "pry", "~> 0.9.12"
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem 'rack', RUBY_VERSION < '2.2.2' ? '~> 1.6' : '~> 2.0'
4
4
 
5
- gem 'coveralls', require: false
5
+ gem 'simplecov', require: false
6
+ gem 'simplecov-lcov', require: false
6
7
 
7
8
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem 'rack', RUBY_VERSION < '2.2.2' ? '~> 1.6' : '~> 2.0'
4
4
  gem "binding_of_caller"
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -4,6 +4,7 @@ gem "rails", "~> 4.2.0"
4
4
  gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
5
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -5,6 +5,7 @@ gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
5
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
6
6
  gem "binding_of_caller"
7
7
 
8
- gem 'coveralls', require: false
8
+ gem 'simplecov', require: false
9
+ gem 'simplecov-lcov', require: false
9
10
 
10
11
  gemspec path: "../"
@@ -5,6 +5,7 @@ gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
5
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
6
6
  gem "haml"
7
7
 
8
- gem 'coveralls', require: false
8
+ gem 'simplecov', require: false
9
+ gem 'simplecov-lcov', require: false
9
10
 
10
11
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem "rails", "~> 5.0.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -4,6 +4,7 @@ gem "rails", "~> 5.0.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
  gem "binding_of_caller"
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -4,6 +4,7 @@ gem "rails", "~> 5.0.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
  gem "haml"
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem "rails", "~> 5.1.0"
4
4
  gem 'i18n', '< 1.5.2', require: false if RUBY_VERSION < '2.3'
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -4,6 +4,7 @@ gem "rails", "~> 5.1.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
  gem "binding_of_caller"
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -4,6 +4,7 @@ gem "rails", "~> 5.1.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
  gem "haml"
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem "rails", "~> 5.2.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -4,6 +4,7 @@ gem "rails", "~> 5.2.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
  gem "binding_of_caller"
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -4,6 +4,7 @@ gem "rails", "~> 5.2.0"
4
4
  gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
5
  gem "haml"
6
6
 
7
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov-lcov', require: false
8
9
 
9
10
  gemspec path: "../"
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 6.0.0"
4
4
 
5
- gem 'coveralls', require: false
5
+ gem 'simplecov', require: false
6
+ gem 'simplecov-lcov', require: false
6
7
 
7
8
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem "rails", "~> 6.0.0"
4
4
  gem "binding_of_caller"
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  gem "rails", "~> 6.0.0"
4
4
  gem "haml"
5
5
 
6
- gem 'coveralls', require: false
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
7
8
 
8
9
  gemspec path: "../"
@@ -11,20 +11,9 @@ require "better_errors/middleware"
11
11
  require "better_errors/raised_exception"
12
12
  require "better_errors/repl"
13
13
  require "better_errors/stack_frame"
14
+ require "better_errors/editor"
14
15
 
15
16
  module BetterErrors
16
- POSSIBLE_EDITOR_PRESETS = [
17
- { symbols: [:emacs, :emacsclient], sniff: /emacs/i, url: "emacs://open?url=file://%{file}&line=%{line}" },
18
- { symbols: [:macvim, :mvim], sniff: /vim/i, url: proc { |file, line| "mvim://open?url=file://#{file}&line=#{line}" } },
19
- { symbols: [:sublime, :subl, :st], sniff: /subl/i, url: "subl://open?url=file://%{file}&line=%{line}" },
20
- { symbols: [:textmate, :txmt, :tm], sniff: /mate/i, url: "txmt://open?url=file://%{file}&line=%{line}" },
21
- { symbols: [:idea], sniff: /idea/i, url: "idea://open?file=%{file}&line=%{line}" },
22
- { symbols: [:rubymine], sniff: /mine/i, url: "x-mine://open?file=%{file}&line=%{line}" },
23
- { symbols: [:vscode, :code], sniff: /code/i, url: "vscode://file/%{file}:%{line}" },
24
- { symbols: [:vscodium, :codium], sniff: /codium/i, url: "vscodium://file/%{file}:%{line}" },
25
- { symbols: [:atom], sniff: /atom/i, url: "atom://core/open/file?filename=%{file}&line=%{line}" },
26
- ]
27
-
28
17
  class << self
29
18
  # The path to the root of the application. Better Errors uses this property
30
19
  # to determine if a file in a backtrace should be considered an application
@@ -64,17 +53,18 @@ module BetterErrors
64
53
  @maximum_variable_inspect_size = 100_000
65
54
  @ignored_classes = ['ActionDispatch::Request', 'ActionDispatch::Response']
66
55
 
67
- # Returns a proc, which when called with a filename and line number argument,
56
+ # Returns an object which responds to #url, which when called with
57
+ # a filename and line number argument,
68
58
  # returns a URL to open the filename and line in the selected editor.
69
59
  #
70
60
  # Generates TextMate URLs by default.
71
61
  #
72
- # BetterErrors.editor["/some/file", 123]
62
+ # BetterErrors.editor.url("/some/file", 123)
73
63
  # # => txmt://open?url=file:///some/file&line=123
74
64
  #
75
65
  # @return [Proc]
76
66
  def self.editor
77
- @editor
67
+ @editor ||= default_editor
78
68
  end
79
69
 
80
70
  # Configures how Better Errors generates open-in-editor URLs.
@@ -115,20 +105,15 @@ module BetterErrors
115
105
  # @param [Proc] proc
116
106
  #
117
107
  def self.editor=(editor)
118
- POSSIBLE_EDITOR_PRESETS.each do |config|
119
- if config[:symbols].include?(editor)
120
- return self.editor = config[:url]
121
- end
122
- end
123
-
124
- if editor.is_a? String
125
- self.editor = proc { |file, line| editor % { file: URI.encode_www_form_component(file), line: line } }
108
+ if editor.is_a? Symbol
109
+ @editor = Editor.for_symbol(editor)
110
+ raise(ArgumentError, "Symbol #{editor} is not a symbol in the list of supported errors.") unless editor
111
+ elsif editor.is_a? String
112
+ @editor = Editor.for_formatting_string(editor)
113
+ elsif editor.respond_to? :call
114
+ @editor = Editor.for_proc(editor)
126
115
  else
127
- if editor.respond_to? :call
128
- @editor = editor
129
- else
130
- raise TypeError, "Expected editor to be a valid editor key, a format string or a callable."
131
- end
116
+ raise ArgumentError, "Expected editor to be a valid editor key, a format string or a callable."
132
117
  end
133
118
  end
134
119
 
@@ -145,12 +130,8 @@ module BetterErrors
145
130
  #
146
131
  # @return [Symbol]
147
132
  def self.default_editor
148
- POSSIBLE_EDITOR_PRESETS.detect(-> { {} }) { |config|
149
- ENV["EDITOR"] =~ config[:sniff]
150
- }[:url] || :textmate
133
+ Editor.default_editor
151
134
  end
152
-
153
- BetterErrors.editor = default_editor
154
135
  end
155
136
 
156
137
  begin
@@ -0,0 +1,99 @@
1
+ require "uri"
2
+
3
+ module BetterErrors
4
+ class Editor
5
+ KNOWN_EDITORS = [
6
+ { symbols: [:atom], sniff: /atom/i, url: "atom://core/open/file?filename=%{file}&line=%{line}" },
7
+ { symbols: [:emacs, :emacsclient], sniff: /emacs/i, url: "emacs://open?url=file://%{file}&line=%{line}" },
8
+ { symbols: [:idea], sniff: /idea/i, url: "idea://open?file=%{file}&line=%{line}" },
9
+ { symbols: [:macvim, :mvim], sniff: /vim/i, url: "mvim://open?url=file://%{file_unencoded}&line=%{line}" },
10
+ { symbols: [:rubymine], sniff: /mine/i, url: "x-mine://open?file=%{file}&line=%{line}" },
11
+ { symbols: [:sublime, :subl, :st], sniff: /subl/i, url: "subl://open?url=file://%{file}&line=%{line}" },
12
+ { symbols: [:textmate, :txmt, :tm], sniff: /mate/i, url: "txmt://open?url=file://%{file}&line=%{line}" },
13
+ { symbols: [:vscode, :code], sniff: /code/i, url: "vscode://file/%{file}:%{line}" },
14
+ { symbols: [:vscodium, :codium], sniff: /codium/i, url: "vscodium://file/%{file}:%{line}" },
15
+ ]
16
+
17
+ def self.for_formatting_string(formatting_string)
18
+ new proc { |file, line|
19
+ formatting_string % { file: URI.encode_www_form_component(file), file_unencoded: file, line: line }
20
+ }
21
+ end
22
+
23
+ def self.for_proc(url_proc)
24
+ new url_proc
25
+ end
26
+
27
+ # Automatically sniffs a default editor preset based on
28
+ # environment variables.
29
+ #
30
+ # @return [Symbol]
31
+ def self.default_editor
32
+ editor_from_environment_formatting_string ||
33
+ editor_from_environment_editor ||
34
+ editor_from_symbol(:textmate)
35
+ end
36
+
37
+ def self.editor_from_environment_editor
38
+ if ENV["BETTER_ERRORS_EDITOR"]
39
+ editor = editor_from_command(ENV["BETTER_ERRORS_EDITOR"])
40
+ return editor if editor
41
+ puts "BETTER_ERRORS_EDITOR environment variable is not recognized as a supported Better Errors editor."
42
+ end
43
+ if ENV["EDITOR"]
44
+ editor = editor_from_command(ENV["EDITOR"])
45
+ return editor if editor
46
+ puts "EDITOR environment variable is not recognized as a supported Better Errors editor. Using TextMate by default."
47
+ else
48
+ puts "Since there is no EDITOR or BETTER_ERRORS_EDITOR environment variable, using Textmate by default."
49
+ end
50
+ end
51
+
52
+ def self.editor_from_command(editor_command)
53
+ env_preset = KNOWN_EDITORS.find { |preset| editor_command =~ preset[:sniff] }
54
+ for_formatting_string(env_preset[:url]) if env_preset
55
+ end
56
+
57
+ def self.editor_from_environment_formatting_string
58
+ return unless ENV['BETTER_ERRORS_EDITOR_URL']
59
+
60
+ for_formatting_string(ENV['BETTER_ERRORS_EDITOR_URL'])
61
+ end
62
+
63
+ def self.editor_from_symbol(symbol)
64
+ KNOWN_EDITORS.each do |preset|
65
+ return for_formatting_string(preset[:url]) if preset[:symbols].include?(symbol)
66
+ end
67
+ end
68
+
69
+ def initialize(url_proc)
70
+ @url_proc = url_proc
71
+ end
72
+
73
+ def url(raw_path, line)
74
+ if virtual_path && raw_path.start_with?(virtual_path)
75
+ if host_path
76
+ file = raw_path.sub(%r{\A#{virtual_path}}, host_path)
77
+ else
78
+ file = raw_path.sub(%r{\A#{virtual_path}/}, '')
79
+ end
80
+ else
81
+ file = raw_path
82
+ end
83
+
84
+ url_proc.call(file, line)
85
+ end
86
+
87
+ private
88
+
89
+ attr_reader :url_proc
90
+
91
+ def virtual_path
92
+ @virtual_path ||= ENV['BETTER_ERRORS_VIRTUAL_PATH']
93
+ end
94
+
95
+ def host_path
96
+ @host_path ||= ENV['BETTER_ERRORS_HOST_PATH']
97
+ end
98
+ end
99
+ end
@@ -67,6 +67,10 @@ module BetterErrors
67
67
  exception.message.strip.gsub(/(\r?\n\s*\r?\n)+/, "\n")
68
68
  end
69
69
 
70
+ def exception_hint
71
+ exception.hint
72
+ end
73
+
70
74
  def active_support_actions
71
75
  return [] unless defined?(ActiveSupport::ActionableError)
72
76
 
@@ -90,7 +94,7 @@ module BetterErrors
90
94
  private
91
95
 
92
96
  def editor_url(frame)
93
- BetterErrors.editor[frame.filename, frame.line]
97
+ BetterErrors.editor.url(frame.filename, frame.line)
94
98
  end
95
99
 
96
100
  def rack_session
@@ -0,0 +1,29 @@
1
+ module BetterErrors
2
+ class ExceptionHint
3
+ def initialize(exception)
4
+ @exception = exception
5
+ end
6
+
7
+ def hint
8
+ case exception
9
+ when NoMethodError
10
+ /\Aundefined method `(?<method>[^']+)' for (?<val>[^:]+):(?<klass>\w+)/.match(exception.message) do |match|
11
+ if match[:val] == "nil"
12
+ return "Something is `nil` when it probably shouldn't be."
13
+ elsif !match[:klass].start_with? '0x'
14
+ return "`#{match[:method]}` is being called on a `#{match[:klass]}` object, "\
15
+ "which might not be the type of object you were expecting."
16
+ end
17
+ end
18
+ when NameError
19
+ /\Aundefined local variable or method `(?<method>[^']+)' for/.match(exception.message) do |match|
20
+ return "`#{match[:method]}` is probably misspelled."
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :exception
28
+ end
29
+ end
@@ -1,7 +1,9 @@
1
+ require 'better_errors/exception_hint'
2
+
1
3
  # @private
2
4
  module BetterErrors
3
5
  class RaisedException
4
- attr_reader :exception, :message, :backtrace
6
+ attr_reader :exception, :message, :backtrace, :hint
5
7
 
6
8
  def initialize(exception)
7
9
  if exception.class.name == "ActionView::Template::Error" && exception.respond_to?(:cause)
@@ -23,6 +25,7 @@ module BetterErrors
23
25
  @message = exception.message
24
26
 
25
27
  setup_backtrace
28
+ setup_hint
26
29
  massage_syntax_error
27
30
  end
28
31
 
@@ -78,5 +81,9 @@ module BetterErrors
78
81
  end
79
82
  end
80
83
  end
84
+
85
+ def setup_hint
86
+ @hint = ExceptionHint.new(exception).hint
87
+ end
81
88
  end
82
89
  end
@@ -90,7 +90,7 @@
90
90
  nav.sidebar,
91
91
  .frame_info {
92
92
  position: fixed;
93
- top: 95px;
93
+ top: 102px;
94
94
  bottom: 0;
95
95
 
96
96
  box-sizing: border-box;
@@ -102,7 +102,7 @@
102
102
  nav.sidebar {
103
103
  width: 40%;
104
104
  left: 20px;
105
- top: 115px;
105
+ top: 122px;
106
106
  bottom: 20px;
107
107
  }
108
108
 
@@ -131,7 +131,7 @@
131
131
  header.exception {
132
132
  padding: 18px 20px;
133
133
 
134
- height: 59px;
134
+ height: 66px;
135
135
  min-height: 59px;
136
136
 
137
137
  overflow: hidden;
@@ -595,6 +595,9 @@
595
595
  color: #8080a0;
596
596
  padding-left: 20px;
597
597
  }
598
+ .console-has-been-used .live-console-hint {
599
+ display: none;
600
+ }
598
601
 
599
602
  .hint:before {
600
603
  content: '\25b2';
@@ -611,17 +614,6 @@
611
614
  margin: 10px 0;
612
615
  }
613
616
 
614
- .sub:before {
615
- content: '';
616
- display: block;
617
- width: 100%;
618
- height: 4px;
619
-
620
- border-radius: 2px;
621
- background: rgba(0, 150, 200, 0.05);
622
- box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.7), inset 0 0 0 1px rgba(0, 0, 0, 0.04), inset 2px 2px 2px rgba(0, 0, 0, 0.07);
623
- }
624
-
625
617
  .sub h3 {
626
618
  color: #39a;
627
619
  font-size: 1.1em;
@@ -764,6 +756,9 @@
764
756
  <% end %>
765
757
  </div>
766
758
  <% end %>
759
+ <% if exception_hint %>
760
+ <h2>Hint: <%= exception_hint %></h2>
761
+ <% end %>
767
762
  </header>
768
763
  </div>
769
764
 
@@ -825,6 +820,28 @@
825
820
  return html.replace(/&/, "&amp;").replace(/</g, "&lt;");
826
821
  }
827
822
 
823
+ function hasConsoleBeenUsedPreviously() {
824
+ return !!document.cookie.split('; ').find(function(cookie) {
825
+ return cookie.startsWith('BetterErrors-has-used-console=');
826
+ });
827
+ }
828
+
829
+ var consoleHasBeenUsed = hasConsoleBeenUsedPreviously();
830
+
831
+ function consoleWasJustUsed() {
832
+ if (consoleHasBeenUsed) {
833
+ return;
834
+ }
835
+
836
+ hideConsoleHint();
837
+ consoleHasBeenUsed = true;
838
+ document.cookie = "BetterErrors-has-used-console=true;path=/;max-age=31536000;samesite"
839
+ }
840
+
841
+ function hideConsoleHint() {
842
+ document.querySelector('body').className += " console-has-been-used";
843
+ }
844
+
828
845
  function REPL(index) {
829
846
  this.index = index;
830
847
 
@@ -846,15 +863,20 @@
846
863
  this.inputElement = this.container.querySelector("input");
847
864
  this.outputElement = this.container.querySelector("pre");
848
865
 
866
+ if (consoleHasBeenUsed) {
867
+ hideConsoleHint();
868
+ }
869
+
849
870
  var self = this;
850
871
  this.inputElement.onkeydown = function(ev) {
851
872
  self.onKeyDown(ev);
873
+ consoleWasJustUsed();
852
874
  };
853
875
 
854
876
  this.setPrompt(">>");
855
877
 
856
878
  REPL.all[this.index] = this;
857
- }
879
+ };
858
880
 
859
881
  REPL.prototype.focus = function() {
860
882
  this.inputElement.focus();
@@ -1,7 +1,10 @@
1
1
  <%== text_heading("=", "%s at %s" % [exception_type, request_path]) %>
2
2
 
3
- > <%== exception_message %>
4
- <% if backtrace_frames.any? %>
3
+ <%== exception_message %>
4
+
5
+ > To access an interactive console with this error, point your browser to: /__better_errors
6
+
7
+ <% if backtrace_frames.any? -%>
5
8
 
6
9
  <%== text_heading("-", "%s, line %i" % [first_frame.pretty_path, first_frame.line]) %>
7
10
 
@@ -25,7 +25,7 @@
25
25
  </header>
26
26
 
27
27
  <% if BetterErrors.binding_of_caller_available? && @frame.frame_binding %>
28
- <div class="hint">
28
+ <div class="hint live-console-hint">
29
29
  This is a live shell. Type in here.
30
30
  </div>
31
31
 
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "2.8.3"
2
+ VERSION = "2.9.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.3
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Somerville
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-03 00:00:00.000000000 Z
11
+ date: 2020-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -146,8 +146,10 @@ extensions: []
146
146
  extra_rdoc_files: []
147
147
  files:
148
148
  - ".coveralls.yml"
149
+ - ".github/workflows/ci.yml"
150
+ - ".github/workflows/release.yml"
149
151
  - ".gitignore"
150
- - ".travis.yml"
152
+ - ".ruby-version"
151
153
  - ".yardopts"
152
154
  - CHANGELOG.md
153
155
  - Gemfile
@@ -178,8 +180,10 @@ files:
178
180
  - lib/better_errors/code_formatter.rb
179
181
  - lib/better_errors/code_formatter/html.rb
180
182
  - lib/better_errors/code_formatter/text.rb
183
+ - lib/better_errors/editor.rb
181
184
  - lib/better_errors/error_page.rb
182
185
  - lib/better_errors/exception_extension.rb
186
+ - lib/better_errors/exception_hint.rb
183
187
  - lib/better_errors/inspectable_value.rb
184
188
  - lib/better_errors/middleware.rb
185
189
  - lib/better_errors/rails.rb
@@ -214,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
218
  - !ruby/object:Gem::Version
215
219
  version: '0'
216
220
  requirements: []
217
- rubygems_version: 3.1.2
221
+ rubygems_version: 3.1.4
218
222
  signing_key:
219
223
  specification_version: 4
220
224
  summary: Better error page for Rails and other Rack apps
@@ -1,111 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
- notifications:
4
- webhooks:
5
- # With COVERALLS_PARALLEL, coverage information sent to coveralls will not be processed until
6
- # this webhook is sent.
7
- # https://coveralls.zendesk.com/hc/en-us/articles/203484329-Parallel-Build-Webhook
8
- - secure: "YnHYbTq51ySistjvOxsuNhyg4GLuUffEJstTYeGYXiBF7HG5h43IVYo8KNuLzwkgsOYBcNo+YMdQX7qCqJffSbhsr1FZRSzBmjFFxcyD4hu+ukM2theZ4mePVAZiePscYvQPRNY4hIb4d3egStJEytkalDhB3sOebF57tIaCssg="
9
- rvm:
10
- - 2.2.10
11
- - 2.3.8
12
- - 2.4.9
13
- - 2.5.7
14
- - 2.6.5
15
- - 2.7.0
16
- - ruby-head
17
- - truffleruby-head
18
- gemfile:
19
- - gemfiles/rails42.gemfile
20
- - gemfiles/rails50.gemfile
21
- - gemfiles/rails51.gemfile
22
- - gemfiles/rails52.gemfile
23
- - gemfiles/rails60.gemfile
24
- - gemfiles/rails42_haml.gemfile
25
- - gemfiles/rails50_haml.gemfile
26
- - gemfiles/rails51_haml.gemfile
27
- - gemfiles/rails52_haml.gemfile
28
- - gemfiles/rails60_haml.gemfile
29
- - gemfiles/rails42_boc.gemfile
30
- - gemfiles/rails50_boc.gemfile
31
- - gemfiles/rails51_boc.gemfile
32
- - gemfiles/rails52_boc.gemfile
33
- - gemfiles/rails60_boc.gemfile
34
- - gemfiles/rack.gemfile
35
- - gemfiles/rack_boc.gemfile
36
- - gemfiles/pry09.gemfile
37
- - gemfiles/pry010.gemfile
38
- - gemfiles/pry011.gemfile
39
- matrix:
40
- fast_finish: true
41
- allow_failures:
42
- - rvm: ruby-head
43
- - gemfile: gemfiles/pry010.gemfile
44
- - gemfile: gemfiles/pry011.gemfile
45
- exclude:
46
- - rvm: 2.2.10
47
- gemfile: gemfiles/rails60.gemfile
48
- - rvm: 2.2.10
49
- gemfile: gemfiles/rails60_boc.gemfile
50
- - rvm: 2.2.10
51
- gemfile: gemfiles/rails60_haml.gemfile
52
- - rvm: 2.3.8
53
- gemfile: gemfiles/rails42.gemfile
54
- - rvm: 2.3.8
55
- gemfile: gemfiles/rails42_boc.gemfile
56
- - rvm: 2.3.8
57
- gemfile: gemfiles/rails42_haml.gemfile
58
- - rvm: 2.3.8
59
- gemfile: gemfiles/rails60.gemfile
60
- - rvm: 2.3.8
61
- gemfile: gemfiles/rails60_boc.gemfile
62
- - rvm: 2.3.8
63
- gemfile: gemfiles/rails60_haml.gemfile
64
- - rvm: 2.4.9
65
- gemfile: gemfiles/rails42.gemfile
66
- - rvm: 2.4.9
67
- gemfile: gemfiles/rails42_boc.gemfile
68
- - rvm: 2.4.9
69
- gemfile: gemfiles/rails42_haml.gemfile
70
- - rvm: 2.4.9
71
- gemfile: gemfiles/rails60.gemfile
72
- - rvm: 2.4.9
73
- gemfile: gemfiles/rails60_boc.gemfile
74
- - rvm: 2.4.9
75
- gemfile: gemfiles/rails60_haml.gemfile
76
- - rvm: 2.5.7
77
- gemfile: gemfiles/rails42.gemfile
78
- - rvm: 2.5.7
79
- gemfile: gemfiles/rails42_boc.gemfile
80
- - rvm: 2.5.7
81
- gemfile: gemfiles/rails42_haml.gemfile
82
- - rvm: 2.6.5
83
- gemfile: gemfiles/rails42.gemfile
84
- - rvm: 2.6.5
85
- gemfile: gemfiles/rails42_boc.gemfile
86
- - rvm: 2.6.5
87
- gemfile: gemfiles/rails42_haml.gemfile
88
- - rvm: 2.7.0
89
- gemfile: gemfiles/rails42.gemfile
90
- - rvm: 2.7.0
91
- gemfile: gemfiles/rails42_boc.gemfile
92
- - rvm: 2.7.0
93
- gemfile: gemfiles/rails42_haml.gemfile
94
- - rvm: ruby-head
95
- gemfile: gemfiles/rails42.gemfile
96
- - rvm: ruby-head
97
- gemfile: gemfiles/rails42_boc.gemfile
98
- - rvm: ruby-head
99
- gemfile: gemfiles/rails42_haml.gemfile
100
- - rvm: truffleruby-head
101
- gemfile: gemfiles/rails42_boc.gemfile
102
- - rvm: truffleruby-head
103
- gemfile: gemfiles/rails50_boc.gemfile
104
- - rvm: truffleruby-head
105
- gemfile: gemfiles/rails51_boc.gemfile
106
- - rvm: truffleruby-head
107
- gemfile: gemfiles/rails52_boc.gemfile
108
- - rvm: truffleruby-head
109
- gemfile: gemfiles/rails60_boc.gemfile
110
- - rvm: truffleruby-head
111
- gemfile: gemfiles/rack_boc.gemfile