fasterer 0.1.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.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.fasterer.yml +17 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +8 -0
  6. data/.travis.yml +6 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +93 -0
  10. data/Rakefile +7 -0
  11. data/bin/fasterer +5 -0
  12. data/fasterer.gemspec +28 -0
  13. data/lib/fasterer.rb +7 -0
  14. data/lib/fasterer/analyzer.rb +99 -0
  15. data/lib/fasterer/binary_call.rb +4 -0
  16. data/lib/fasterer/cli.rb +10 -0
  17. data/lib/fasterer/file_traverser.rb +81 -0
  18. data/lib/fasterer/method_call.rb +138 -0
  19. data/lib/fasterer/method_definition.rb +51 -0
  20. data/lib/fasterer/offense.rb +69 -0
  21. data/lib/fasterer/offense_collector.rb +17 -0
  22. data/lib/fasterer/parse_error.rb +10 -0
  23. data/lib/fasterer/parser.rb +11 -0
  24. data/lib/fasterer/rescue_call.rb +36 -0
  25. data/lib/fasterer/scanners/method_call_scanner.rb +134 -0
  26. data/lib/fasterer/scanners/method_definition_scanner.rb +52 -0
  27. data/lib/fasterer/scanners/offensive.rb +25 -0
  28. data/lib/fasterer/scanners/rescue_call_scanner.rb +28 -0
  29. data/lib/fasterer/token.rb +27 -0
  30. data/lib/fasterer/version.rb +3 -0
  31. data/spec/lib/fasterer/analyzer/01_parallel_assignment_spec.rb +12 -0
  32. data/spec/lib/fasterer/analyzer/02_rescue_vs_respond_to_spec.rb +12 -0
  33. data/spec/lib/fasterer/analyzer/03_module_eval_spec.rb +12 -0
  34. data/spec/lib/fasterer/analyzer/04_find_vs_bsearch_spec.rb +12 -0
  35. data/spec/lib/fasterer/analyzer/06_shuffle_first_vs_sample_spec.rb +12 -0
  36. data/spec/lib/fasterer/analyzer/08_for_loop_vs_each_spec.rb +12 -0
  37. data/spec/lib/fasterer/analyzer/09_each_with_index_vs_while_spec.rb +12 -0
  38. data/spec/lib/fasterer/analyzer/10_map_flatten_vs_flat_map_spec.rb +12 -0
  39. data/spec/lib/fasterer/analyzer/11_reverse_each_vs_reverse_each_spec.rb +12 -0
  40. data/spec/lib/fasterer/analyzer/12_select_first_vs_detect_spec.rb +12 -0
  41. data/spec/lib/fasterer/analyzer/13_sort_vs_sort_by_spec.rb +12 -0
  42. data/spec/lib/fasterer/analyzer/14_fetch_with_argument_vs_block_spec.rb +12 -0
  43. data/spec/lib/fasterer/analyzer/15_keys_each_vs_each_key_spec.rb +12 -0
  44. data/spec/lib/fasterer/analyzer/16_hash_merge_bang_vs_hash_brackets_spec.rb +12 -0
  45. data/spec/lib/fasterer/analyzer/18_block_vs_symbol_to_proc_spec.rb +12 -0
  46. data/spec/lib/fasterer/analyzer/19_proc_call_vs_yield_spec.rb +12 -0
  47. data/spec/lib/fasterer/analyzer/24_gsub_vs_tr_spec.rb +12 -0
  48. data/spec/lib/fasterer/analyzer/98_misc_spec.rb +11 -0
  49. data/spec/lib/fasterer/analyzer/99_exceptional_files_spec.rb +11 -0
  50. data/spec/lib/fasterer/method_call_spec.rb +483 -0
  51. data/spec/lib/fasterer/method_definition_spec.rb +93 -0
  52. data/spec/lib/fasterer/rescue_call_spec.rb +76 -0
  53. data/spec/spec_helper.rb +99 -0
  54. data/spec/support/analyzer/01_parallel_assignment.rb +10 -0
  55. data/spec/support/analyzer/02_rescue_vs_respond_to.rb +36 -0
  56. data/spec/support/analyzer/03_module_eval.rb +11 -0
  57. data/spec/support/analyzer/04_find_vs_bsearch.rb +5 -0
  58. data/spec/support/analyzer/06_shuffle_first_vs_sample.rb +5 -0
  59. data/spec/support/analyzer/08_for_loop_vs_each.rb +8 -0
  60. data/spec/support/analyzer/09_each_with_index_vs_while.rb +3 -0
  61. data/spec/support/analyzer/10_map_flatten_vs_flat_map.rb +15 -0
  62. data/spec/support/analyzer/11_reverse_each_vs_reverse_each.rb +9 -0
  63. data/spec/support/analyzer/12_select_first_vs_detect.rb +7 -0
  64. data/spec/support/analyzer/13_sort_vs_sort_by.rb +9 -0
  65. data/spec/support/analyzer/14_fetch_with_argument_vs_block.rb +11 -0
  66. data/spec/support/analyzer/15_keys_each_vs_each_key.rb +15 -0
  67. data/spec/support/analyzer/16_hash_merge_bang_vs_hash_brackets.rb +21 -0
  68. data/spec/support/analyzer/18_block_vs_symbol_to_proc.rb +30 -0
  69. data/spec/support/analyzer/19_proc_call_vs_yield.rb +24 -0
  70. data/spec/support/analyzer/24_gsub_vs_tr.rb +14 -0
  71. data/spec/support/analyzer/98_misc.rb +15 -0
  72. data/spec/support/analyzer/99_exceptional_files.rb +7 -0
  73. data/spec/support/binary_call/simple_comparison.rb +0 -0
  74. data/spec/support/method_call/method_call_on_constant.rb +1 -0
  75. data/spec/support/method_call/method_call_on_integer.rb +1 -0
  76. data/spec/support/method_call/method_call_on_method_call.rb +1 -0
  77. data/spec/support/method_call/method_call_on_string.rb +1 -0
  78. data/spec/support/method_call/method_call_on_variable.rb +2 -0
  79. data/spec/support/method_call/method_call_with_a_block.rb +5 -0
  80. data/spec/support/method_call/method_call_with_a_integer_argument.rb +1 -0
  81. data/spec/support/method_call/method_call_with_a_regex_argument.rb +1 -0
  82. data/spec/support/method_call/method_call_with_an_argument_and_a_block.rb +2 -0
  83. data/spec/support/method_call/method_call_with_an_implicit_receiver.rb +1 -0
  84. data/spec/support/method_call/method_call_with_an_implicit_receiver_and_no_brackets.rb +1 -0
  85. data/spec/support/method_call/method_call_with_an_implicit_receiver_and_no_brackets_and_do_end.rb +3 -0
  86. data/spec/support/method_call/method_call_with_equals.rb +1 -0
  87. data/spec/support/method_call/method_call_with_one_argument.rb +1 -0
  88. data/spec/support/method_call/method_call_with_two_arguments.rb +2 -0
  89. data/spec/support/method_call/method_call_without_brackets.rb +1 -0
  90. data/spec/support/method_definition/method_with_argument_and_block.rb +3 -0
  91. data/spec/support/method_definition/method_with_block.rb +3 -0
  92. data/spec/support/method_definition/method_with_default_argument.rb +3 -0
  93. data/spec/support/method_definition/method_with_splat_and_block.rb +3 -0
  94. data/spec/support/method_definition/simple_method.rb +2 -0
  95. data/spec/support/method_definition/simple_method_omitted_parenthesis.rb +2 -0
  96. data/spec/support/method_definition/simple_method_with_argument.rb +3 -0
  97. data/spec/support/rescue_call/plain_rescue.rb +7 -0
  98. data/spec/support/rescue_call/rescue_with_class.rb +5 -0
  99. data/spec/support/rescue_call/rescue_with_class_and_variable.rb +5 -0
  100. data/spec/support/rescue_call/rescue_with_multiple_classes.rb +4 -0
  101. data/spec/support/rescue_call/rescue_with_multiple_classes_and_variable.rb +5 -0
  102. data/spec/support/rescue_call/rescue_with_variable.rb +6 -0
  103. metadata +303 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 700f1de5e4957667423d3e045970c1046e86579f
4
+ data.tar.gz: 7c60c88efa59abe5857436f1a229a96b54f77e6d
5
+ SHA512:
6
+ metadata.gz: 70b4baaf83af7c16e926245b5685b9a2b52568f4f81c279da6d0f70a68cd1af49b82dda342c43d0a4f5c4e6bb65ab027cb9fee19afdd0601be6815db660d2865
7
+ data.tar.gz: 26543c720eefaf8f678e4353d4a5837d336912def1359d300a3d3f45903ca1bf4e2185446e916ef9fdf4b74c4548e829989f1d2f9131f1438cd6180141435565
data/.fasterer.yml ADDED
@@ -0,0 +1,17 @@
1
+ speedups:
2
+ parallel_assignment: false
3
+ rescue_vs_respond_to: true
4
+ module_eval: true
5
+ shuffle_first_vs_sample: true
6
+ for_loop_vs_each: true
7
+ each_with_index_vs_while: false
8
+ map_flatten_vs_flat_map: true
9
+ reverse_each_vs_reverse_each: true
10
+ select_first_vs_detect: true
11
+ sort_vs_sort_by: true
12
+ fetch_with_argument_vs_block: true
13
+ keys_each_vs_each_key: true
14
+ hash_merge_bang_vs_hash_brackets: true
15
+ block_vs_symbol_to_proc: true
16
+ proc_call_vs_yield: true
17
+ gsub_vs_tr: true
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ Include:
3
+ - '**/Rakefile'
4
+ Exclude:
5
+ - 'spec/support/**/*'
6
+ - 'spec/spec_helper.rb'
7
+ Documentation:
8
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.2
6
+ - 2.2.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fasterer.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Damir Svrtan
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ [![Build Status](https://travis-ci.org/DamirSvrtan/fasterer.svg?branch=master)](https://travis-ci.org/DamirSvrtan/fasterer)
2
+ [![Code Climate](https://codeclimate.com/github/DamirSvrtan/fasterer/badges/gpa.svg)](https://codeclimate.com/github/DamirSvrtan/fasterer)
3
+ # Fasterer
4
+
5
+ Make your Rubies go faster with this command line tool highly inspired by [fast-ruby](https://github.com/JuanitoFatas/fast-ruby) and [Sferik's talk at Baruco Conf](https://speakerdeck.com/sferik/writing-fast-ruby).
6
+
7
+ Fasterer will suggest some speed improvements which you can check in detail at the [fast-ruby repo](https://github.com/JuanitoFatas/fast-ruby).
8
+
9
+ **Please note** that you shouldn't follow the suggestions blindly. Using a while loop instead of a each_with_index probably shouldn't be considered if you're doing a regular Rails project, but maybe if you're doing something very speed dependent such as Rack or if you're building your own framework, you might consider this speed increase.
10
+
11
+
12
+
13
+ ## Installation
14
+
15
+ ```shell
16
+ gem install fasterer
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ Run it from the root of your project:
22
+
23
+ ```shell
24
+ fasterer
25
+ ```
26
+
27
+ ## Example output
28
+
29
+ ```shell
30
+
31
+ app/models/post.rb
32
+ Array#select.first is slower than Array#detect. Occured at lines: 57, 61.
33
+
34
+ db/seeds/cities.rb
35
+ Hash#keys.each is slower than Hash#each_key. Occured at lines: 15, 33.
36
+
37
+ test/options_test.rb
38
+ Hash#merge! with one argument is slower than Hash#[]. Occured at lines: 84.
39
+
40
+ test/module_test.rb
41
+ Don't rescue NoMethodError, rather check with respond_to?. Occured at lines: 272.
42
+
43
+ spec/cache/mem_cache_store_spec.rb
44
+ Use tr instead of gsub when grepping plain strings. Occured at lines: 161.
45
+ ```
46
+ ## Configuration
47
+
48
+ You can turn of speed suggestions with a simple yaml file called **.fasterer.yml** in the root of your project. Example:
49
+
50
+
51
+ ```yaml
52
+ speedups:
53
+ parallel_assignment: false
54
+ rescue_vs_respond_to: true
55
+ module_eval: true
56
+ shuffle_first_vs_sample: true
57
+ for_loop_vs_each: true
58
+ each_with_index_vs_while: false
59
+ map_flatten_vs_flat_map: true
60
+ reverse_each_vs_reverse_each: true
61
+ select_first_vs_detect: true
62
+ sort_vs_sort_by: true
63
+ fetch_with_argument_vs_block: true
64
+ keys_each_vs_each_key: true
65
+ hash_merge_bang_vs_hash_brackets: true
66
+ block_vs_symbol_to_proc: true
67
+ proc_call_vs_yield: true
68
+ gsub_vs_tr: true
69
+ ```
70
+
71
+ ## TODOs:
72
+
73
+ 4. find vs bsearch
74
+ 5. Array#count vs Array#size
75
+ 7. Enumerable#each + push vs Enumerable#map
76
+ 17. Hash#merge vs Hash#merge!
77
+ 20. String#casecmp vs String#downcase + ==
78
+ 21. String concatenation
79
+ 22. String#match vs String#start_with?/String#end_with?
80
+ 23. String#gsub vs String#sub
81
+
82
+ # New
83
+
84
+ values each -> each_value
85
+ class_eval
86
+
87
+ ## Contributing
88
+
89
+ 1. Fork it ( https://github.com/DamirSvrtan/fasterer/fork )
90
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
91
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
92
+ 4. Push to the branch (`git push origin my-new-feature`)
93
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc 'Run all RSpec tests'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
data/bin/fasterer ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
3
+ require 'fasterer/cli'
4
+
5
+ Fasterer::CLI.execute
data/fasterer.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fasterer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'fasterer'
8
+ spec.version = Fasterer::VERSION
9
+ spec.authors = ['Damir Svrtan']
10
+ spec.email = ['damir.svrtan@gmail.com']
11
+ spec.summary = 'Run Ruby more than fast. Fasterer'
12
+ spec.description = 'Use Fasterer to check various places in your code that could be faster.'
13
+ spec.homepage = 'https://github.com/DamirSvrtan/fasterer'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'colorize', '~> 0.7'
22
+ spec.add_dependency 'ruby_parser', '~> 3.6'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.6'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.1'
27
+ spec.add_development_dependency 'pry', '~> 0.10'
28
+ end
data/lib/fasterer.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'fasterer/version'
2
+ require 'fasterer/analyzer'
3
+ require 'fasterer/method_definition'
4
+
5
+ module Fasterer
6
+ # Your code goes here...
7
+ end
@@ -0,0 +1,99 @@
1
+ require 'fasterer/method_definition'
2
+ require 'fasterer/method_call'
3
+ require 'fasterer/rescue_call'
4
+ require 'fasterer/offense_collector'
5
+ require 'fasterer/parser'
6
+ require 'fasterer/parse_error'
7
+ require 'fasterer/scanners/method_call_scanner'
8
+ require 'fasterer/scanners/rescue_call_scanner'
9
+ require 'fasterer/scanners/method_definition_scanner'
10
+
11
+ module Fasterer
12
+ class Analyzer
13
+ attr_reader :file_path
14
+ alias_method :path, :file_path
15
+
16
+ def initialize(file_path)
17
+ @file_path = file_path
18
+ @file_content = File.read(file_path)
19
+ end
20
+
21
+ def scan
22
+ sexp_tree = Fasterer::Parser.parse(@file_content)
23
+ fail ParseError.new(file_path) if sexp_tree.nil?
24
+ traverse_sexp_tree(sexp_tree)
25
+ end
26
+
27
+ def errors
28
+ @errors ||= Fasterer::OffenseCollector.new
29
+ end
30
+
31
+ private
32
+
33
+ def traverse_sexp_tree(sexp_tree)
34
+ return unless sexp_tree.is_a?(Sexp)
35
+
36
+ token = sexp_tree.first
37
+
38
+ scan_by_token(token, sexp_tree)
39
+
40
+ case token
41
+ when :call, :iter
42
+ method_call = MethodCall.new(sexp_tree)
43
+ traverse_sexp_tree(method_call.receiver_element) if method_call.receiver_element
44
+ traverse_sexp_tree(method_call.arguments_element)
45
+ traverse_sexp_tree(method_call.block_body) if method_call.has_block?
46
+ else
47
+ sexp_tree.each { |element| traverse_sexp_tree(element) }
48
+ end
49
+ end
50
+
51
+ def scan_by_token(token, element)
52
+ case token
53
+ when :defn
54
+ scan_method_definitions(element)
55
+ when :call, :iter
56
+ scan_method_calls(element)
57
+ when :masgn
58
+ scan_parallel_assignment(element)
59
+ when :for
60
+ scan_for_loop(element)
61
+ when :resbody
62
+ scan_rescue(element)
63
+ end
64
+ end
65
+
66
+ def scan_method_definitions(element)
67
+ method_definition_scanner = MethodDefinitionScanner.new(element)
68
+
69
+ if method_definition_scanner.offense_detected?
70
+ errors.push(method_definition_scanner.offense)
71
+ end
72
+ end
73
+
74
+ def scan_method_calls(element)
75
+ method_call_scanner = MethodCallScanner.new(element)
76
+
77
+ if method_call_scanner.offense_detected?
78
+ errors.push(method_call_scanner.offense)
79
+ end
80
+ end
81
+
82
+ def scan_parallel_assignment(element)
83
+ errors.push(Fasterer::Offense.new(:parallel_assignment, element.line))
84
+ end
85
+
86
+ def scan_for_loop(element)
87
+ errors.push(Fasterer::Offense.new(:for_loop_vs_each, element.line))
88
+ end
89
+
90
+ def scan_rescue(element)
91
+ rescue_call_scanner = RescueCallScanner.new(element)
92
+
93
+ if rescue_call_scanner.offense_detected?
94
+ errors.push(rescue_call_scanner.offense)
95
+ end
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,4 @@
1
+ module Fasterer
2
+ class BinaryCall
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'file_traverser'
2
+
3
+ module Fasterer
4
+ class CLI
5
+ def self.execute
6
+ file_traverser = Fasterer::FileTraverser.new('.')
7
+ file_traverser.traverse
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,81 @@
1
+ require 'pathname'
2
+ require 'colorize'
3
+ require 'yaml'
4
+
5
+ require_relative 'analyzer'
6
+
7
+ module Fasterer
8
+ class FileTraverser
9
+
10
+ CONFIG_FILE_NAME = '.fasterer.yml'
11
+
12
+ attr_reader :ignored_speedups
13
+
14
+ def initialize(path)
15
+ @path = Pathname(path)
16
+ @parse_error_paths = []
17
+ set_ignored_speedups
18
+ end
19
+
20
+ def traverse
21
+ if @path.directory?
22
+ traverse_directory(@path)
23
+ else
24
+ scan_file(@path)
25
+ end
26
+ output_parse_errors if parse_error_paths.any?
27
+ end
28
+
29
+ def set_ignored_speedups
30
+ @ignored_speedups = if config_file
31
+ config_file['speedups'].select {|_, value| value == false }.keys.map(&:to_sym)
32
+ end || []
33
+ end
34
+
35
+ def config_file
36
+ File.exists?(CONFIG_FILE_NAME) && YAML.load_file(CONFIG_FILE_NAME)
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :parse_error_paths
42
+
43
+ def scan_file(path)
44
+ analyzer = Analyzer.new(path)
45
+ analyzer.scan
46
+ rescue Fasterer::ParseError, RubyParser::SyntaxError, Racc::ParseError
47
+ parse_error_paths.push(path)
48
+ else
49
+ output(analyzer) if offenses_grouped_by_type(analyzer).any?
50
+ end
51
+
52
+ def traverse_directory(path)
53
+ Dir["#{path}/**/*.rb"].each do |ruby_file|
54
+ scan_file(ruby_file.split('/').drop(1).join('/'))
55
+ end
56
+ end
57
+
58
+ def output(analyzer)
59
+ puts analyzer.file_path.colorize(:red)
60
+
61
+ offenses_grouped_by_type(analyzer).each do |error_group_name, error_occurences|
62
+ puts "#{Fasterer::Offense::EXPLANATIONS[error_group_name]}. Occured at lines: #{error_occurences.map(&:line_number).join(', ')}."
63
+ end
64
+
65
+ puts
66
+ end
67
+
68
+ def offenses_grouped_by_type(analyzer)
69
+ analyzer.errors.group_by(&:name).delete_if {|offense_name, _| ignored_speedups.include?(offense_name) }
70
+ end
71
+
72
+ def output_parse_errors
73
+ puts 'Fasterer was unable to process some files because the'
74
+ puts 'internal parser is not able to read some characters.'
75
+ puts 'Unprocessable files were:'
76
+ puts '-----------------------------------------------------'
77
+ puts parse_error_paths
78
+ puts
79
+ end
80
+ end
81
+ end