mentor 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 154403f120fb0038895fd393ed5ee5ade659a97c
4
- data.tar.gz: d6463cbbb85424479d49a43c83151f8fa425315d
3
+ metadata.gz: 9d61b738e627b884222d11ae5e7e01b717a4b473
4
+ data.tar.gz: 30b3b83534080ed8a0da9eb9d32ba11dde4c6b01
5
5
  SHA512:
6
- metadata.gz: abcf92fe3f316713f95d3a7d19ed7f1cf6cb997dc60369145bd73829a1c502f4dd79ee848ef8627a38f1a8b776d841d2de44be1b5ecf012561df5a9a69b65c3f
7
- data.tar.gz: 0a4cb06f1f27148e5a8f80ade2b0b7c3e29631e59b68defdead01c58d00f964f02f1bbce237f32bbcbf51374b793370cfc17a365748566863602e08653d91891
6
+ metadata.gz: 974dea0e3cf08d028480c1e4925df058fee38583c7a115d7a83d39bc8b09e6467f8371d47110913f5ed9c5c8655ba8666b84561b86ecabd86625b7756f9fa2a0
7
+ data.tar.gz: 8b8e7aa5f94c8c3b186c05d5bcc7f5013623b16dd2d6754e059d340197e4134861501729e9b0c5a197aacbffd5342bc6e0d6afc812209488c2252ed685c5ba88
data/.gitignore CHANGED
@@ -1 +1,3 @@
1
1
  /Gemfile.lock
2
+ /.todo.reek
3
+ /.rubocop.yml
data/bin/mentor CHANGED
@@ -9,6 +9,6 @@ end
9
9
  ruby_program = ARGV.first
10
10
  ruby_program = Dir.pwd + '/' + ruby_program unless ruby_program[0] == '/'
11
11
 
12
- require 'mentor'
13
- Mentor.enable
12
+ require_relative '../lib/mentor'
13
+ Mentor::Init.setup
14
14
  require_relative ruby_program
@@ -20,16 +20,20 @@ module Mentor
20
20
  end
21
21
  end
22
22
 
23
- private
23
+ private_class_method
24
24
 
25
25
  def self.error_classes
26
26
  [
27
27
  NoMethodDidYouMeanSuggestionError,
28
+ NoMethodForNilClassForCommonClassError,
29
+ NoMethodForNilClassError,
28
30
  MentorNoMethodError,
29
31
  MentorError
30
32
  ]
31
33
  end
32
34
 
35
+ private
36
+
33
37
  def sections
34
38
  [
35
39
  Header.new,
@@ -3,7 +3,9 @@ module Mentor
3
3
  class NoMethodDidYouMeanSuggestionError < MentorNoMethodError
4
4
 
5
5
  def self.can_handle?
6
- super && Mentor.tp.raised_exception&.corrections.any?
6
+ super &&
7
+ Mentor.tp.raised_exception.respond_to?(:corrections) &&
8
+ Mentor.tp.raised_exception.corrections.any?
7
9
  end
8
10
 
9
11
  def sections
@@ -0,0 +1,35 @@
1
+ module Mentor
2
+
3
+ class NoMethodForNilClassError < MentorNoMethodError
4
+
5
+ def self.can_handle?
6
+ super && Mentor.tp.raised_exception.to_s['NilClass']
7
+ end
8
+
9
+ def sections
10
+ [
11
+ Header.new,
12
+ RubyErrorComplete.new,
13
+ RelativePath.new,
14
+ LinesOfCode.new,
15
+ ErrorClassSpecificHelp.new([error_class_specific_help]),
16
+ Suggestion.new("Try setting #{var_for_method} to a value first and then call the method #{method_name} on it.")
17
+ ]
18
+ end
19
+
20
+ private
21
+
22
+ def error_class_specific_help
23
+ [
24
+ "It looks like you're trying to call the method #{method_name} on #{var_for_method}.",
25
+ '',
26
+ "It's likely #{var_for_method} was never defined, and therefore is equal to nil, which is how Ruby represents 'nothing'."
27
+ ]
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+
35
+
@@ -0,0 +1,74 @@
1
+ module Mentor
2
+
3
+ class NoMethodForNilClassForCommonClassError < MentorNoMethodError
4
+
5
+ def self.can_handle?
6
+ super &&
7
+ Mentor.tp.raised_exception.to_s['NilClass'] &&
8
+ common_methods.include?(method_name.to_sym)
9
+ end
10
+
11
+ def sections
12
+ [
13
+ Header.new,
14
+ RubyErrorComplete.new,
15
+ RelativePath.new,
16
+ LinesOfCode.new,
17
+ ErrorClassSpecificHelp.new(error_class_specific_help),
18
+ Examples.new(examples),
19
+ Docs.new(docs),
20
+ Suggestion.new("Try setting #{var_for_method} to #{a_an(common_classes_for_error.keys.first)} #{or_sentence(common_classes_for_error.keys)} first and then call the method #{method_name} on it.")
21
+ ]
22
+ end
23
+
24
+ private
25
+
26
+ def error_class_specific_help
27
+ [
28
+ "It looks like you're trying to call the method #{method_name} on #{var_for_method}.",
29
+ '',
30
+ "It's likely #{var_for_method} was never defined, and therefore is equal to nil, which is how Ruby represents 'nothing'.",
31
+ '',
32
+ "#{and_sentence(pluralize_words(common_classes_for_error.keys))} have the #{method_name} method, so you may want to set #{var_for_method} to #{a_an(common_classes_for_error.keys.first)} #{or_sentence(common_classes_for_error.keys)} first.",
33
+ ]
34
+ end
35
+
36
+ def examples
37
+ common_classes_for_error.map { |klass, attrs| " #{var_for_method} = #{attrs[:example]} # sets it to #{a_an(klass)} #{klass}" }
38
+ end
39
+
40
+ def docs
41
+ common_classes_for_error.keys.map { |klass| "ri #{klass}##{method_name}" }
42
+ end
43
+
44
+ def common_classes_for_error
45
+ self.class.common_classes.select do |klass, attrs|
46
+ attrs[:methods].include? raised_exception.spell_checker.method_name
47
+ end
48
+ end
49
+
50
+ private_class_method
51
+
52
+ @@string_methods = String.new.methods
53
+ @@integer_methods = 1.methods
54
+ @@float_methods = 1.0.methods
55
+ @@array_methods = Array.new.methods
56
+ @@hash_methods = Hash.new.methods
57
+
58
+ def self.common_classes
59
+ {
60
+ String: { methods: @@string_methods, example: "Hello, world!" },
61
+ Integer: { methods: @@integer_methods, example: 42 },
62
+ Float: { methods: @@float_methods, example: 3.14 },
63
+ Array: { methods: @@array_methods, example: '[]' },
64
+ Hash: { methods: @@hash_methods, example: '{}' }
65
+ }
66
+ end
67
+
68
+ def self.common_methods
69
+ common_classes.map { |klass, attrs| attrs[:methods] }.flatten - Object.methods
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -2,10 +2,12 @@ module Mentor
2
2
 
3
3
  module Colorize
4
4
 
5
+ include OutputHelper
6
+
5
7
  def colorize(line)
6
8
 
7
- if line_of_code?(line)
8
- line = syntax_highlight(line)
9
+ if line_of_padded_code?(line)
10
+ line = color_padded_code(line)
9
11
  elsif backtrace?(line)
10
12
  return rainbow(line, :backtrace_line)
11
13
  end
@@ -14,10 +16,7 @@ module Mentor
14
16
  end
15
17
 
16
18
  def colorize_section
17
- @lines.map! do |line|
18
- line = rainbow(line, :suggestion)
19
- colorize(line)
20
- end
19
+ @lines.map! { |line| colorize(line) }
21
20
  end
22
21
 
23
22
  private
@@ -26,84 +25,66 @@ module Mentor
26
25
  line['from ']
27
26
  end
28
27
 
29
- def line_of_code?(line)
28
+ def line_of_padded_code?(line)
30
29
  line[padded_lineno_with_colon_regex]
31
30
  end
32
31
 
33
- def apply_colors(line)
34
-
35
- line = color_pattern(line, error_lineno, "#{file_name}:#{error_lineno}", :error_lineno)
36
- line = color_pattern(line, ruby_error_class, "(#{ruby_error_class})", :ruby_error_class)
37
- line = color_pattern(line, ruby_error_class, " #{ruby_error_class} ", :ruby_error_class)
38
-
39
- output_types = %i(
32
+ def output_types
33
+ %i[
40
34
  did_you_mean_text did_you_mean_word
41
35
  message horizontal_line ruby_error_text
42
- calling_method method_class method_name var_for_method
43
- absolute_base_dir relative_base_dir app_dir file_name
44
- )
45
-
46
- output_types.reduce(line) do |line, output_type|
47
- color_text(line, send(output_type), output_type)
48
- end
49
-
36
+ calling_method method_name var_for_method
37
+ absolute_base_dir relative_base_dir app_dir file_name
38
+ ]
50
39
  end
51
40
 
52
- def syntax_highlight(line)
53
- padded_lineno = line[padded_lineno_with_colon_regex]
54
- code = line[padded_lineno.size..-1]
55
- color_padded_lineno(padded_lineno) + color_code(code)
41
+ def apply_colors(line)
42
+ line = apply_pattern_colors(line)
43
+ line = apply_output_colors(line)
44
+ line = apply_nil_colors(line)
45
+ line = apply_common_classes_colors(line)
56
46
  end
57
47
 
58
- def color_code(code)
59
- formatter = Rouge::Formatters::Terminal256.new
60
- lexer = Rouge::Lexers::Ruby.new
61
- formatter.format(lexer.lex(code))
48
+ def apply_pattern_colors(line)
49
+ line = TextToColor.new(line, error_lineno, :error_lineno, "#{file_name}:#{error_lineno}").color_pattern
50
+ line = TextToColor.new(line, ruby_error_class, :ruby_error_class, "(#{ruby_error_class})").color_pattern
51
+ line = TextToColor.new(line, ruby_error_class, :ruby_error_class, " #{ruby_error_class} ").color_pattern
62
52
  end
63
53
 
64
- def color_padded_lineno(padded_lineno)
65
- text_to_color = padded_lineno[padded_lineno_regex]
66
- color = text_to_color['=>'] ? :error_lineno : :subtle
67
- color_text(padded_lineno, text_to_color, color)
54
+ def apply_output_colors(line)
55
+ output_types.reduce(line) do |new_line, output_type|
56
+ TextToColor.new(new_line, send(output_type), output_type).colored
57
+ end
68
58
  end
69
59
 
70
- def color_pattern(full_text, text_to_color, match_pattern, output_type)
71
- full_text.gsub(match_pattern, color_text(match_pattern, text_to_color, output_type))
60
+ def apply_nil_colors(line)
61
+ line = TextToColor.new(line, ' nil', :nil_text).colored
62
+ line = TextToColor.new(line, 'NilClass', :nil_text).colored
72
63
  end
73
64
 
74
- def color_text(full_text, text_to_color, output_type)
75
-
76
- return full_text unless text_to_color && text_to_color.size > 0
77
-
78
- colorized_text = rainbow(text_to_color, output_type)
79
- remaining_text = full_text
80
- text_processed = ''
81
-
82
- while remaining_text[text_to_color]
83
- before_text = before_text_to_color(remaining_text, text_to_color)
84
- reset_color = get_reset_color(before_text).to_s
85
- text_processed += before_text + colorized_text
86
- index_after_text_processed = (before_text + text_to_color).size
87
- remaining_text = reset_color + remaining_text[index_after_text_processed..-1].to_s
65
+ def apply_common_classes_colors(line)
66
+ %w(String Integer Float Array Hash [] {}).reduce(line) do |new_line, klass|
67
+ new_line = TextToColor.new(new_line, pluralize(klass), :common_class).colored
68
+ new_line = TextToColor.new(new_line, klass.to_s, :common_class).colored
88
69
  end
89
-
90
- text_processed + remaining_text
91
-
92
70
  end
93
71
 
94
- def before_text_to_color(remaining_text, text_to_color)
95
- index = remaining_text.index(text_to_color)
96
- return '' if !index || index == 0
97
- remaining_text[0..index - 1]
72
+ def color_padded_code(line)
73
+ padded_lineno = line[padded_lineno_with_colon_regex]
74
+ code = line[padded_lineno.size..-1]
75
+ color_padded_lineno(padded_lineno) + color_code(code)
98
76
  end
99
77
 
100
- def get_reset_color(before_text)
101
- index_of_color_to_reset_to = before_text.rindex(color_regex)
102
- before_text[index_of_color_to_reset_to..-1][color_regex] if index_of_color_to_reset_to
78
+ def color_code(code)
79
+ formatter = Rouge::Formatters::Terminal256.new
80
+ lexer = Rouge::Lexers::Ruby.new
81
+ formatter.format(lexer.lex(code))
103
82
  end
104
83
 
105
- def color_regex
106
- /\e\[(\d|;)+m/
84
+ def color_padded_lineno(padded_lineno)
85
+ text_to_color_text = padded_lineno[padded_lineno_regex]
86
+ color = text_to_color_text['=>'] ? :error_lineno : :subtle
87
+ TextToColor.new(padded_lineno, text_to_color_text, color).colored
107
88
  end
108
89
 
109
90
  def padded_lineno_regex
@@ -124,6 +105,7 @@ module Mentor
124
105
  method_name = :deepskyblue
125
106
  subtle = :olive
126
107
  very_subtle = :dimgray
108
+ nil_text = :orange
127
109
 
128
110
  {
129
111
  app_dir: subtle,
@@ -131,6 +113,7 @@ module Mentor
131
113
  absolute_base_dir: subtle,
132
114
  relative_base_dir: subtle,
133
115
  calling_method: :green,
116
+ common_class: :wheat,
134
117
  did_you_mean_text: :royalblue,
135
118
  did_you_mean_word: method_name,
136
119
  error_lineno: error_lineno,
@@ -141,6 +124,7 @@ module Mentor
141
124
  message: error,
142
125
  method_class: :mediumpurple,
143
126
  method_name: method_name,
127
+ nil_text: nil_text,
144
128
  other_class_or_module: :darksalmon,
145
129
  prominent: :ivory,
146
130
  ruby_error_class: :orangered,
@@ -2,13 +2,7 @@ module Mentor
2
2
 
3
3
  module Globals
4
4
 
5
- DIR = __dir__ + '/../..'
6
-
7
- attr_accessor :cancel_exit_after_error, :tp
8
-
9
- def cancel_exit_after_error?
10
- @cancel_exit_after_error
11
- end
5
+ attr_accessor :tp
12
6
 
13
7
  def enable
14
8
  @enabled = true
@@ -2,6 +2,26 @@ module Mentor
2
2
 
3
3
  module OutputHelper
4
4
 
5
+ def a_an(word)
6
+ %w(A E I O U).include?(word[0]) ? 'an' : 'a'
7
+ end
8
+
9
+ def pluralize(word)
10
+ word.to_s + (word.to_s == 'Hash' ? 'es' :'s')
11
+ end
12
+
13
+ def pluralize_words(words)
14
+ words.map { |word| pluralize word }
15
+ end
16
+
17
+ def or_sentence(words)
18
+ words.join(' or ')
19
+ end
20
+
21
+ def and_sentence(words)
22
+ words.join(' and ')
23
+ end
24
+
5
25
  def home_to_tilde(path)
6
26
  path.sub(ENV['HOME'], '~')
7
27
  end
@@ -4,31 +4,41 @@ module Mentor
4
4
 
5
5
  include OutputHelper
6
6
 
7
+ private
8
+
9
+ def tp
10
+ Mentor.tp
11
+ end
12
+
13
+ def raised_exception
14
+ tp.raised_exception
15
+ end
16
+
7
17
  def absolute_base_dir
8
18
  Dir.pwd + '/'
9
19
  end
10
20
 
11
21
  def app_dir
12
- Mentor.tp.path. # Full path
13
- sub(absolute_base_dir, ''). # Remove path up until this file
14
- split('/')[0..-2]. # Split path into parts and exclude filename
15
- join('/') + # Join with '/'
22
+ tp.path # Full path
23
+ .sub(absolute_base_dir, '') # Remove path up until this file
24
+ .split('/')[0..-2] # Split path into parts and exclude filename
25
+ .join('/') + # Join with '/'
16
26
  '/' # Add one more '/' to end of it
17
27
  end
18
28
 
19
29
  def backtrace_lines
20
30
 
21
- # Mentor.tp.raised_exception.backtrace disappears after accessing it once
31
+ # raised_exception.backtrace disappears after accessing it once
22
32
  # So we just do it once and then save the result to @@backtrace_lines
23
33
  if self.class.class_variable_defined?(:@@backtrace_lines)
24
34
  return @@backtrace_lines
25
35
  end
26
36
 
27
- bt_lines = Mentor.tp.raised_exception.
28
- backtrace[1..-1]. # Remove first
29
- grep_v(/bin\/mentor/). # Remove mentor involvement
30
- map { |line| line.sub(Dir.pwd + '/', '') }. # Remove path before current dir
31
- map { |line| 'from ' + line } # Add 'from'
37
+ bt_lines = raised_exception
38
+ .backtrace[1..-1] # Remove first
39
+ .grep_v(%r{bin/mentor}) # Remove mentor involvement
40
+ .map { |line| line.sub(Dir.pwd + '/', '') } # Remove path before current dir
41
+ .map { |line| 'from ' + line } # Add 'from'
32
42
 
33
43
  return bt_lines if bt_lines.empty?
34
44
 
@@ -40,13 +50,13 @@ module Mentor
40
50
  end
41
51
 
42
52
  def calling_method
43
- (Mentor.tp.method_id || '<main>').to_s
53
+ (tp.method_id || '<main>').to_s
44
54
  end
45
55
 
46
56
  def did_you_mean_word
47
- if Mentor.tp.raised_exception.respond_to? :corrections
48
- Mentor.tp.raised_exception.corrections.first&.to_s
49
- end
57
+ return unless raised_exception.respond_to? :corrections
58
+
59
+ raised_exception.corrections.first.to_s
50
60
  end
51
61
 
52
62
  def did_you_mean_text
@@ -58,60 +68,35 @@ module Mentor
58
68
  end
59
69
 
60
70
  def error_lineno
61
- Mentor.tp.lineno.to_s
71
+ tp.lineno.to_s
62
72
  end
63
73
 
64
74
  def file_name
65
- Mentor.tp.path.split('/').last
75
+ tp.path.split('/').last
66
76
  end
67
77
 
68
78
  def horizontal_line
69
79
  '─' * terminal_width
70
80
  end
71
81
 
72
- def instance_methods
73
- Mentor.tp.raised_exception.receiver.class.instance_methods -
74
- Mentor.tp.raised_exception.receiver.class.superclass.instance_methods
75
- end
76
-
77
82
  def lineno_subtle_padded(width)
78
83
  @lineno.to_s.rjust(width)
79
84
  end
80
85
 
81
86
  def message
82
- if Mentor.tp.raised_exception.respond_to? :original_message
83
- Mentor.tp.raised_exception.original_message
87
+ if raised_exception.respond_to? :original_message
88
+ raised_exception.original_message
84
89
  else
85
- Mentor.tp.raised_exception.message
90
+ raised_exception.message
86
91
  end
87
92
  end
88
93
 
89
94
  def method_name
90
- if Mentor.tp.raised_exception.respond_to? :spell_checker
91
- if Mentor.tp.raised_exception.spell_checker.respond_to?(:method_name)
92
- Mentor.tp.raised_exception.spell_checker.method_name.to_s
93
- else
94
- raise "cannot determine method name"
95
- end
96
- end
97
- end
98
-
99
- def method_class
100
- if Mentor.tp.raised_exception.respond_to? :receiver
101
- Mentor.tp.raised_exception.receiver.class.to_s
102
- end
103
- end
104
-
105
- def method_class_plural
106
- pluralize method_class
107
- end
108
-
109
- def method_class_superclass
110
- Mentor.tp.raised_exception.receiver.class.superclass
111
- end
95
+ return unless
96
+ raised_exception.respond_to?(:spell_checker) &&
97
+ raised_exception.spell_checker.respond_to?(:method_name)
112
98
 
113
- def method_class_superclasses
114
- to_sentence(Mentor.tp.raised_exception.receiver.class.ancestors - typical_classes)
99
+ raised_exception.spell_checker.method_name.to_s
115
100
  end
116
101
 
117
102
  def relative_base_dir
@@ -119,7 +104,7 @@ module Mentor
119
104
  end
120
105
 
121
106
  def ruby_error_class
122
- Mentor.tp.raised_exception.class.to_s
107
+ raised_exception.class.to_s
123
108
  end
124
109
 
125
110
  def ruby_error_text
@@ -127,7 +112,7 @@ module Mentor
127
112
  end
128
113
 
129
114
  def var_for_method
130
- culprit_line = lines_from_file[Mentor.tp.lineno]
115
+ culprit_line = lines_from_file[tp.lineno]
131
116
  var = culprit_line[/#{valid_var_name}\.#{method_name}/].to_s.chomp(".#{method_name}")
132
117
  if var.empty?
133
118
  culprit_line[/#{valid_var_name} method_name/].to_s.chomp(".#{method_name}")
@@ -1,18 +1,18 @@
1
1
  module Mentor
2
- gems = [
3
- 'pry',
4
- 'rainbow',
5
- 'rouge',
6
- ]
7
2
 
8
- helpers = [
9
- 'output_helper',
10
- 'outputs',
11
- 'colorize'
12
- ].map { |file| Globals::DIR + '/lib/helpers/' + file }
3
+ dir = __dir__ + '/../..'
13
4
 
14
- sections = Dir.glob(Globals::DIR + '/lib/sections/*.rb')
15
- errors = Dir.glob(Globals::DIR + '/lib/errors/*.rb')
5
+ gems = %w[pry rainbow rouge]
6
+
7
+ helpers = %w[
8
+ output_helper
9
+ outputs
10
+ colorize
11
+ text_to_color
12
+ ].map { |file| dir + '/lib/helpers/' + file }
13
+
14
+ sections = Dir.glob(dir + '/lib/sections/*.rb')
15
+ errors = Dir.glob(dir + '/lib/errors/*.rb')
16
16
 
17
17
  (gems + helpers + sections + errors).each { |file| require file }
18
18
 
@@ -0,0 +1,65 @@
1
+ module Mentor
2
+
3
+ class TextToColor
4
+
5
+ include Colorize
6
+
7
+ def initialize(full_text, text_to_color, output_type, match_pattern = nil)
8
+ @full_text = full_text
9
+ @text_to_color = text_to_color
10
+ @output_type = output_type
11
+ @match_pattern = match_pattern
12
+ end
13
+
14
+ def color_pattern
15
+ @full_text.gsub(@match_pattern, colored)
16
+ end
17
+
18
+ def colored
19
+ return @full_text unless text_to_color_exists?
20
+ color_text
21
+ end
22
+
23
+ private
24
+
25
+ def colorized_text
26
+ rainbow(@text_to_color, @output_type)
27
+ end
28
+
29
+ def text_to_color_exists?
30
+ @text_to_color && !@text_to_color.empty?
31
+ end
32
+
33
+ def color_text
34
+ remaining_text = @match_pattern || @full_text
35
+ text_processed = ''
36
+
37
+ while remaining_text[@text_to_color]
38
+ before_text = before_text_to_color(remaining_text)
39
+ reset_color = get_reset_color(before_text).to_s
40
+ text_processed += before_text + colorized_text
41
+ index_after_text_processed = (before_text + @text_to_color).size
42
+ remaining_text = reset_color + remaining_text[index_after_text_processed..-1]
43
+ end
44
+
45
+ text_processed + remaining_text
46
+ end
47
+
48
+ def before_text_to_color(remaining_text)
49
+ index = remaining_text.index(@text_to_color)
50
+ return '' if !index || index.zero?
51
+ remaining_text[0..index - 1]
52
+ end
53
+
54
+ def get_reset_color(before_text)
55
+ index_of_color_to_reset_to = before_text.rindex(color_regex)
56
+ before_text[index_of_color_to_reset_to..-1][color_regex] if index_of_color_to_reset_to
57
+ end
58
+
59
+ def color_regex
60
+ /\e\[(\d|;)+m/
61
+ end
62
+
63
+ end
64
+
65
+ end
data/lib/main.rb CHANGED
@@ -13,7 +13,7 @@ module Mentor
13
13
  raise error
14
14
  rescue *MentorError.error_classes
15
15
  error.output
16
- exit 1 unless Mentor.cancel_exit_after_error?
16
+ exit 1
17
17
  end
18
18
 
19
19
  end
@@ -1,3 +1,3 @@
1
1
  module Mentor
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'.freeze
3
3
  end
data/lib/mentor.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'mentor/version'
2
-
3
1
  module Mentor
4
2
 
5
3
  class Init
@@ -11,19 +9,19 @@ module Mentor
11
9
  Mentor.enable
12
10
  end
13
11
 
14
- private
12
+ private_class_method
15
13
 
16
14
  def self.setup_trace_point
17
15
 
18
16
  TracePoint.trace(:raise) do |tp|
19
17
  tp.disable
20
18
 
21
- if Mentor.enabled?
22
- Mentor.disable
23
- require_relative 'helpers/requires'
24
- Mentor.tp = tp
25
- Main.new
26
- end
19
+ if Mentor.enabled?
20
+ Mentor.disable
21
+ require_relative 'helpers/requires'
22
+ Mentor.tp = tp
23
+ Main.new
24
+ end
27
25
 
28
26
  tp.enable
29
27
  end
@@ -33,5 +31,3 @@ module Mentor
33
31
  end
34
32
 
35
33
  end
36
-
37
- Mentor::Init.setup
@@ -4,10 +4,8 @@ module Mentor
4
4
 
5
5
  include Outputs
6
6
 
7
- attr_reader :lines
8
-
9
- def initialize
10
- @lines = indent_lines(backtrace_lines, indent: 10)
7
+ def lines
8
+ indent_lines(backtrace_lines, indent: 10)
11
9
  end
12
10
 
13
11
  end
@@ -12,7 +12,7 @@ module Mentor
12
12
 
13
13
  def self.can_handle?
14
14
  Mentor.tp.raised_exception.respond_to?(:corrections) &&
15
- Mentor.tp.raised_exception.corrections.any?
15
+ Mentor.tp.raised_exception.corrections.any?
16
16
  end
17
17
 
18
18
  end
@@ -0,0 +1,18 @@
1
+ module Mentor
2
+
3
+ class Docs
4
+
5
+ include Outputs, Colorize
6
+
7
+ attr_reader :lines
8
+
9
+ def initialize(lines)
10
+ @lines = ['For docs, type:', '']
11
+ @lines << indent_lines(lines)
12
+ @lines = indent_lines(@lines)
13
+ colorize_section
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,28 @@
1
+ module Mentor
2
+
3
+ class Examples
4
+
5
+ include Outputs, Colorize
6
+
7
+ attr_reader :lines
8
+
9
+ def initialize(examples)
10
+ @lines =
11
+ indent_lines([
12
+ 'For example:',
13
+ '',
14
+ examples
15
+ ]).flatten
16
+
17
+ examples.each do |example|
18
+ @lines.map! do |line|
19
+ line.sub(example, color_code(example))
20
+ end
21
+ end
22
+
23
+ colorize_section
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -4,13 +4,11 @@ module Mentor
4
4
 
5
5
  include Outputs, Colorize
6
6
 
7
- attr_reader :lines
8
-
9
- def initialize
7
+ def lines
10
8
  @lines = [
11
9
  horizontal_line,
12
10
  title_indented,
13
- horizontal_line,
11
+ horizontal_line
14
12
  ]
15
13
 
16
14
  colorize_section
@@ -4,10 +4,8 @@ module Mentor
4
4
 
5
5
  include Outputs
6
6
 
7
- attr_accessor :lines
8
-
9
- def initialize
10
- @lines = indent_lines(lines_of_code_from_method_or_file, indent: 4)
7
+ def lines
8
+ indent_lines(lines_of_code_from_method_or_file, indent: 4)
11
9
  end
12
10
 
13
11
  private
@@ -32,16 +30,19 @@ module Mentor
32
30
 
33
31
  def set_first_and_last_from_method
34
32
  method_text = Pry::Method.from_str("#{Mentor.tp.defined_class}##{calling_method}").source.split("\n")
35
- @first_lineno = lines_from_file.select { |lineno, line| line["def #{calling_method}"] }.sort.last.first
33
+ @first_lineno = lines_from_file.select { |_lineno, line| line["def #{calling_method}"] }.sort.last.first
36
34
  @last_lineno = @first_lineno + method_text.size - 1
37
35
  end
38
36
 
39
37
  def set_first_and_last_from_file
40
38
  @first_lineno = Mentor.tp.lineno
41
- @first_lineno -= 1 until first_line_at_start_of_file? || first_line_empty? ||
39
+ @first_lineno -= 1 until first_line_at_start_of_file? ||
40
+ first_line_empty? ||
42
41
  line_prior_to_first_line_ends?
42
+
43
43
  @last_lineno = Mentor.tp.lineno
44
- @last_lineno += 1 until last_line_at_end_of_file? || last_line_empty?
44
+ @last_lineno += 1 until last_line_at_end_of_file? ||
45
+ last_line_empty?
45
46
  end
46
47
 
47
48
  def first_line_at_start_of_file?
@@ -67,4 +68,3 @@ module Mentor
67
68
  end
68
69
 
69
70
  end
70
-
@@ -4,10 +4,8 @@ module Mentor
4
4
 
5
5
  include Outputs
6
6
 
7
- attr_accessor :lines
8
-
9
- def initialize
10
- @lines = indent_lines(relative_base_dir + app_dir + file_name + ':' + error_lineno)
7
+ def lines
8
+ indent_lines(relative_base_dir + app_dir + file_name + ':' + error_lineno)
11
9
  end
12
10
 
13
11
  end
@@ -2,18 +2,16 @@ module Mentor
2
2
 
3
3
  class RubyErrorComplete
4
4
 
5
- include Outputs, Colorize
5
+ include Outputs
6
6
 
7
- attr_reader :lines
8
-
9
- def initialize
10
- @lines = []
11
- @lines << RubyErrorMain.new.lines
12
- @lines << DidYouMeanCorrection.new.line if DidYouMeanCorrection.can_handle?
13
- @lines << Backtrace.new.lines
14
- @lines = indent_lines(@lines)
15
- @lines << ''
16
- @lines << horizontal_line
7
+ def lines
8
+ lines_array = []
9
+ lines_array << RubyErrorMain.new.lines
10
+ lines_array << DidYouMeanCorrection.new.line if DidYouMeanCorrection.can_handle?
11
+ lines_array << Backtrace.new.lines
12
+ lines_array = indent_lines(lines_array)
13
+ lines_array << ''
14
+ lines_array << horizontal_line
17
15
  end
18
16
 
19
17
  end
@@ -4,20 +4,14 @@ module Mentor
4
4
 
5
5
  include Outputs
6
6
 
7
- attr_reader :lines
8
-
9
- def initialize
10
- @lines = ruby_error_main
7
+ def lines
8
+ ruby_error_main
11
9
  end
12
10
 
13
11
  private
14
12
 
15
13
  def single_line
16
- parts = []
17
- parts << path_and_lineno
18
- parts << message
19
- parts << bracketed_class
20
- parts.flatten.join(' ')
14
+ [path_and_lineno, message, bracketed_class].flatten.join(' ')
21
15
  end
22
16
 
23
17
  def path_and_lineno
@@ -57,7 +51,7 @@ module Mentor
57
51
 
58
52
  def fit_on_one_or_two_lines?(part_a, part_b)
59
53
  fit_on_one_line?(part_a, part_b) ||
60
- does_not_fit_on_one_line?(part_a) && fit_on_two_lines?(part_a, part_b)
54
+ does_not_fit_on_one_line?(part_a) && fit_on_two_lines?(part_a, part_b)
61
55
  end
62
56
 
63
57
  def fit_on_one_line?(part_a, part_b)
@@ -15,7 +15,7 @@ module Mentor
15
15
 
16
16
  def format_lines
17
17
  @lines = indent_lines(@lines)
18
- colorize_section
18
+ @lines.map! { |line| rainbow(line, :suggestion) }
19
19
  end
20
20
 
21
21
  end
data/mentor.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  lib = File.expand_path('../lib', __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'mentor/version'
@@ -12,11 +11,11 @@ Gem::Specification.new do |spec|
12
11
  spec.homepage = 'https://gitlab.com/seanlerner/mentor'
13
12
  spec.license = 'MIT'
14
13
 
15
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
14
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
15
  f.match(%r{^(test|spec|features)/})
17
16
  end
18
17
 
19
- spec.executables << 'mentor'
18
+ spec.executables << 'mentor'
20
19
  spec.require_paths = ['lib']
21
20
 
22
21
  spec.add_dependency 'pry', '~> 0.10'
@@ -24,6 +23,7 @@ Gem::Specification.new do |spec|
24
23
  spec.add_dependency 'rouge', '~> 2.0'
25
24
 
26
25
  spec.add_development_dependency 'bundler', '~> 1.13'
26
+ spec.add_development_dependency 'did_you_mean', '~> 1.1'
27
27
  spec.add_development_dependency 'guard', '~> 2.14'
28
28
  spec.add_development_dependency 'guard-minitest', '~> 2.4'
29
29
  spec.add_development_dependency 'minitest', '~> 5.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mentor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Lerner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-24 00:00:00.000000000 Z
11
+ date: 2017-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.13'
69
+ - !ruby/object:Gem::Dependency
70
+ name: did_you_mean
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: guard
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -140,17 +154,22 @@ files:
140
154
  - lib/errors/mentor_error.rb
141
155
  - lib/errors/mentor_no_method_error.rb
142
156
  - lib/errors/no_method_did_you_mean_suggestion_error.rb
157
+ - lib/errors/no_method_for_nil_class_error.rb
158
+ - lib/errors/no_method_for_nil_class_for_common_class_error.rb
143
159
  - lib/helpers/colorize.rb
144
160
  - lib/helpers/globals.rb
145
161
  - lib/helpers/output_helper.rb
146
162
  - lib/helpers/outputs.rb
147
163
  - lib/helpers/requires.rb
164
+ - lib/helpers/text_to_color.rb
148
165
  - lib/main.rb
149
166
  - lib/mentor.rb
150
167
  - lib/mentor/version.rb
151
168
  - lib/sections/backtrace.rb
152
169
  - lib/sections/did_you_mean_correction.rb
170
+ - lib/sections/docs.rb
153
171
  - lib/sections/error_class_specific_help.rb
172
+ - lib/sections/examples.rb
154
173
  - lib/sections/header.rb
155
174
  - lib/sections/line_of_code.rb
156
175
  - lib/sections/lines_of_codes.rb