fuckitruby 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8d78029b63a1d750b6906e0a0e31d24d03cef621
4
+ data.tar.gz: 77cca7b886117f0c16b22125b22cd2c80a5ec340
5
+ SHA512:
6
+ metadata.gz: c323a83a4ee7dc3fac0520ea56296f7b0e120dfaa632a09f070bb24eed4463ddc8df1f3c8566379fd80a392959ebdcaec31ed61f8ba6ff85647ed1fec3c9ff9f
7
+ data.tar.gz: 2ef4ab8ed0415042e734943d36909a6131d6d087497d8fb47c1148c0c19b62fa930c968508cfc1d16b3fb42fb3aabcad351c3b61eb0f38443e6f2d4fe475b493
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'parser'
4
+ gem 'binding_of_caller'
5
+ gem 'hotwater'
6
+ gem 'colorize'
7
+
8
+ gem 'rspec', group: [:development, :test]
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Alexander Ivanov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ #fuckitruby
2
+
3
+ Tired of `NameError` ? Tired of the lack of AI? Tired of ruby-not-being-a-grammar-nazi?
4
+
5
+ Fuck it, ruby, that's not what I meant!
6
+
7
+ ```ruby
8
+ def lala(explicit)
9
+ if exlicit
10
+ do_something_stupid
11
+ else
12
+ explicit
13
+ end
14
+ end
15
+ ```
16
+
17
+ ```bash
18
+ /home/penka-was-abducted/lala.rb:2:in `lala': undefined local variable or method `exlicit' for main:Object (NameError)
19
+ from /home/penka-was-abducted/lala.rb:9:in `<main>'
20
+ ```
21
+
22
+ ohh
23
+
24
+ ```ruby
25
+ require 'fuckitruby'
26
+
27
+ def lala...
28
+ ```
29
+
30
+ ```bash
31
+ fix in 'lala': 'exlicit' to
32
+ 'explicit' [ENTER]
33
+ other name [type it]
34
+ fix explicit to exlicit [!] [ENTER]
35
+ > # entering
36
+ # program rewrites itself and reexecutes properly
37
+ ```
38
+
39
+ ##faq
40
+
41
+ * why
42
+
43
+ it's fun.
44
+
45
+ it's "a program can self-heal itself on error conditions" little experiment
46
+
47
+
48
+ * srsly?
49
+
50
+ well it's not for production use , but it combines several really cool hacks
51
+
52
+ it looks for the local variables in the offending scope using [binding_of_caller](https://github.com/banister/binding_of_caller),
53
+
54
+ it uses lewenstein distance to find the most probable fix, thanks [hotwater](https://github.com/colinsurprenant/hotwater)
55
+
56
+ it uses [parser](https://github.com/whitequark/parser/) to
57
+ find the exact locations of name uses in the method
58
+
59
+ it uses [colorize](https://github.com/fazibear/colorize) to color the output
60
+
61
+ * uh
62
+ it's inspired by magnificient [thefuck command](https://github.com/nvbn/thefuck)
63
+
64
+ ## that name sucks
65
+
66
+ it's an obvious nod to `thefuck` command.
67
+
68
+ ##kk
69
+
70
+ Copyright (c) 2015 Alexander Ivanov under the MIT License. See LICENSE for further details.
71
+
72
+
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+ require 'rspec/core'
14
+ require 'rspec/core/rake_task'
15
+
16
+ NAME = ""
17
+
18
+ RSpec::Core::RakeTask.new(:spec) do |spec|
19
+ spec.pattern = FileList['spec/**/*_spec.rb']
20
+ end
21
+ task :default => :spec
@@ -0,0 +1,36 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "fuckitruby"
3
+ s.version = "0.1.0"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.require_paths = ["lib"]
7
+ s.authors = ["Alexander Ivanov"]
8
+ s.date = "2015-11-04"
9
+ s.description = "a gem that can automatically fix your NameErrors"
10
+ s.email = "alehander42@gmail.com"
11
+ s.executables = []
12
+ s.extra_rdoc_files = [
13
+ "LICENSE",
14
+ "README.md"
15
+ ]
16
+ s.files = [
17
+ "Gemfile",
18
+ "LICENSE",
19
+ "README.md",
20
+ "Rakefile",
21
+ "lib/fuckitruby.rb",
22
+ "lib/fuckitruby/name_error.rb",
23
+ "lib/fuckitruby/fuck_processor.rb",
24
+ "fuckitruby.gemspec"
25
+ ]
26
+ s.homepage = "http://github.com/alehander42/fuckitruby"
27
+ s.licenses = ["MIT"]
28
+ s.rubygems_version = "2.4.8"
29
+ s.summary = "a gem that can automatically fix your NameErrors"
30
+
31
+ s.add_development_dependency 'rspec', '~> 0'
32
+ s.add_runtime_dependency 'parser', '~> 2.2.3'
33
+ s.add_runtime_dependency 'binding_of_caller', '~> 0.7.2'
34
+ s.add_runtime_dependency 'hotwater', '~> 0.1.2'
35
+ s.add_runtime_dependency 'colorize', '~> 0.7.7'
36
+ end
data/lib/fuckitruby.rb ADDED
@@ -0,0 +1,2 @@
1
+ require_relative 'fuckitruby/fuck_processor'
2
+ require_relative 'fuckitruby/name_error'
@@ -0,0 +1,56 @@
1
+ require 'ast'
2
+
3
+ module FuckItRuby
4
+ class FuckProcessor < AST::Processor
5
+ attr_reader :locations
6
+
7
+ def initialize(method_label, from, whole_file, *args)
8
+ @method_label = method_label
9
+ @from = from
10
+ @whole_file = whole_file
11
+ @locations = []
12
+ super *args
13
+ end
14
+
15
+ def on_begin(node)
16
+ process_all node
17
+ end
18
+
19
+ def handler_missing(node)
20
+ process_all(node.children.select { |c| c.is_a?(AST::Node) })
21
+ end
22
+
23
+ def on_def(node)
24
+ if !@whole_file && node.children[0] == @method_label
25
+ @itshappening = true
26
+ node.children[1..-1].each &method(:process)
27
+ @itshappening = false
28
+ elsif @whole_file && node.children[0] == @from
29
+ @locations << [node.location.name.begin_pos, node.location.name.end_pos]
30
+ node.children[1..-1].each &method(:process)
31
+ end
32
+ end
33
+
34
+ def on_lvasgn(node)
35
+ if (@whole_file || @itshappening) && node.children[0] == @from
36
+ @locations << [node.location.name.begin_pos, node.location.name.end_pos]
37
+ end
38
+ end
39
+
40
+ def mark_local(node)
41
+ if (@whole_file || @itshappening) && node.children[0] == @from
42
+ @locations << [node.location.expression.begin_pos, node.location.expression.end_pos]
43
+ end
44
+ node
45
+ end
46
+
47
+ alias_method :on_lvar, :mark_local
48
+ alias_method :on_arg, :mark_local
49
+
50
+ def on_send(node)
51
+ if (@whole_file || @itshappening) && node.children[1] == @from #&& node.children[0].nil?
52
+ @locations << [node.location.selector.begin_pos, node.location.selector.end_pos]
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,69 @@
1
+ require 'binding_of_caller'
2
+ require 'parser/current'
3
+ require 'hotwater'
4
+ require 'colorize'
5
+
6
+ class NameError
7
+ alias_method :e, :exception
8
+
9
+ def exception
10
+ @bindings = binding.callers
11
+ e
12
+ end
13
+
14
+ def message
15
+ error_dialog *fix_for_name
16
+ exec("ruby #{backtrace_locations[0].absolute_path}")
17
+ end
18
+
19
+ private
20
+
21
+ def method_label
22
+ backtrace_locations[0].base_label.to_sym
23
+ end
24
+
25
+ def fix_for_name
26
+ b = @bindings.find { |c| c.eval('self.class') != self.class }
27
+ methods = (b.eval('self.class.private_methods') + b.eval('methods')).uniq
28
+ fix = !b.local_variables.empty? ? closest_name(name, b.local_variables + methods) : closest_name(name, methods)
29
+ [fix, methods]
30
+ end
31
+
32
+ def error_dialog(fix, methods)
33
+ puts
34
+ puts "fix in '#{method_label}': '#{name}' to"
35
+ puts " #{fix}".ljust(42) + "[ENTER]".colorize(:green)
36
+ puts " other name".ljust(42) + "[type it]".colorize(:yellow) + "[ENTER]".colorize(:green)
37
+ puts " fix #{fix} to #{name}".ljust(42) + "R [ENTER]".colorize(:green)
38
+
39
+ l = gets.chomp
40
+
41
+ if l.empty?
42
+ rewrite_with_name(backtrace_locations[0].path, method_label, name, fix, methods.include?(name))
43
+ elsif l == 'R'
44
+ rewrite_with_name(backtrace_locations[0].path, method_label, fix, name, methods.include?(fix))
45
+ else
46
+ rewrite_with_name(backtrace_locations[0].path, method_label, name, l, methods.include?(name))
47
+ end
48
+ end
49
+
50
+ def closest_name(label, locals)
51
+ locals.map { |l| [Hotwater.levenshtein_distance(l.to_s, label.to_s), l] }.min[1]
52
+ end
53
+
54
+ def rewrite_with_name(path, method, from, to, whole_file)
55
+ source = File.read(path)
56
+ ast = Parser::CurrentRuby.parse source
57
+ fuck = FuckItRuby::FuckProcessor.new(method, from, whole_file)
58
+ fuck.process ast
59
+ lines = source.split("\n")
60
+ tokens, lc = [], 0
61
+ fuck.locations.each do |b, e|
62
+ tokens << source[lc..b - 1]
63
+ tokens << to.to_s
64
+ lc = e
65
+ end
66
+ tokens << source[lc..-1]
67
+ File.write path, tokens.join
68
+ end
69
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fuckitruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Ivanov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: parser
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.2.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: binding_of_caller
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.7.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.7.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: hotwater
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: colorize
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.7.7
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.7.7
83
+ description: a gem that can automatically fix your NameErrors
84
+ email: alehander42@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files:
88
+ - LICENSE
89
+ - README.md
90
+ files:
91
+ - Gemfile
92
+ - LICENSE
93
+ - README.md
94
+ - Rakefile
95
+ - fuckitruby.gemspec
96
+ - lib/fuckitruby.rb
97
+ - lib/fuckitruby/fuck_processor.rb
98
+ - lib/fuckitruby/name_error.rb
99
+ homepage: http://github.com/alehander42/fuckitruby
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.4.8
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: a gem that can automatically fix your NameErrors
123
+ test_files: []