mentor 0.1.1 → 0.2.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
  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