preval 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -1
- data/Gemfile.lock +1 -1
- data/README.md +8 -1
- data/bin/console +1 -3
- data/bin/print +1 -3
- data/bin/start +3 -0
- data/docs/index.html +5 -3
- data/docs/public/favicon.png +0 -0
- data/docs/server.rb +1 -3
- data/lib/preval.rb +12 -2
- data/lib/preval/node.rb +2 -2
- data/lib/preval/version.rb +1 -1
- data/lib/preval/visitor.rb +0 -9
- data/lib/preval/visitors/arithmetic.rb +10 -10
- data/lib/preval/visitors/attr_accessor.rb +51 -0
- data/lib/preval/visitors/fasterer.rb +76 -0
- data/lib/preval/visitors/loops.rb +57 -19
- metadata +5 -2
- data/lib/preval/visitors/micro.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e8e8b1cc9579dafac71315c8138e9a07ece0a40e8c0e0ccdb3f9345574c4446
|
4
|
+
data.tar.gz: 5bc5ccf467619084b2243f082466881e1f491ecb844cd622ff612b9c7242ae42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aebce20a3d9332bf8e8eb20ea9f71789531b1462398713a22f9fb027c860aaee0d060bb94ddc6f400ceb1a6a94e0619638c54bedadcfa6eaea4a5cf3254cbb32
|
7
|
+
data.tar.gz: 515570a0d77a859529530b9113a8309b974c9bf09c7117afc2eee605406725155d3f35995bcac674cd0d3577e4da00891faa189925a573dde08fdd3b2fc9cda6
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
|
+
|
9
|
+
## [0.4.0] - 2019-04-19
|
10
|
+
### Added
|
11
|
+
- Replace `def foo=(value); @foo = value; end` with `attr_writer :foo`
|
12
|
+
- Replace `while false ... end` loops with nothing
|
13
|
+
- Replace `until false ... end` loops with `loop do ... end` loops
|
14
|
+
- Replace `until true ... end` loops with nothing
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
- Extracted out the `Preval::Visitors::AttrAccessor` visitor.
|
18
|
+
- Renamed the `Preval::Visitors::Micro` visitor to `Preval::Visitors::Fasterer`.
|
19
|
+
|
20
|
+
## [0.3.0] - 2019-04-19
|
8
21
|
### Added
|
9
22
|
- Fold constant for exponentiation if exponent is 0 and value is an integer.
|
10
23
|
- Replace `.reverse.each` usage with `.reverse_each`.
|
@@ -13,6 +26,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
13
26
|
- Replace `def foo; @foo; end` with `attr_reader :foo`.
|
14
27
|
- Replace `.shuffle.first` with `.sample`.
|
15
28
|
- Replace `.map { ... }.flatten(1)` with `.flat_map { ... }`.
|
29
|
+
- Replace `def foo=(value); @foo = value; end` with `attr_writer :foo`.
|
16
30
|
|
17
31
|
## [0.2.0] - 2019-04-18
|
18
32
|
### Added
|
@@ -22,6 +36,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
22
36
|
### Added
|
23
37
|
- Initial release. 🎉
|
24
38
|
|
25
|
-
[Unreleased]: https://github.com/kddeisz/preval/compare/v0.
|
39
|
+
[Unreleased]: https://github.com/kddeisz/preval/compare/v0.4.0...HEAD
|
40
|
+
[0.4.0]: https://github.com/kddeisz/preval/compare/v0.3.0...v0.4.0
|
41
|
+
[0.3.0]: https://github.com/kddeisz/preval/compare/v0.2.0...v0.3.0
|
26
42
|
[0.2.0]: https://github.com/kddeisz/preval/compare/v0.1.0...v0.2.0
|
27
43
|
[0.1.0]: https://github.com/kddeisz/preval/compare/49c899...v0.1.0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -31,8 +31,10 @@ Each optimization is generally named for the function it performs, and can be en
|
|
31
31
|
* `Preval::Visitors::Arithmetic` replaces:
|
32
32
|
* constant expressions with their evaluation (e.g., `5 + 2` becomes `7`)
|
33
33
|
* arithmetic identities with their evaluation (e.g., `a * 1` becomes `a`)
|
34
|
-
* `Preval::Visitors::
|
34
|
+
* `Preval::Visitors::AttrAccessor` replaces:
|
35
35
|
* `def foo; @foo; end` with `attr_reader :foo`
|
36
|
+
* `def foo=(value); @foo = value; end` with `attr_writer :foo`
|
37
|
+
* `Preval::Visitors::Fasterer` replaces:
|
36
38
|
* `.gsub('...', '...')` with `.tr('...', '...')` if the arguments are strings and are both of length 1
|
37
39
|
* `.map { ... }.flatten(1)` with `.flat_map { ... }`
|
38
40
|
* `.reverse.each` with `.reverse_each`
|
@@ -40,6 +42,11 @@ Each optimization is generally named for the function it performs, and can be en
|
|
40
42
|
* `Preval::Visitors::Loops` replaces:
|
41
43
|
* `for ... in ... end` loops with `... each do ... end` loops
|
42
44
|
* `while true ... end` loops with `loop do ... end` loops
|
45
|
+
* `while false ... end` loops with nothing
|
46
|
+
* `until false ... end` loops with `loop do ... end` loops
|
47
|
+
* `until true ... end` loops with nothing
|
48
|
+
|
49
|
+
You can also call `Preval.enable_all!` which will enable every built-in visitor. Be especially careful when doing this.
|
43
50
|
|
44
51
|
## Development
|
45
52
|
|
data/bin/console
CHANGED
data/bin/print
CHANGED
@@ -3,9 +3,7 @@
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'preval'
|
5
5
|
|
6
|
-
Preval
|
7
|
-
Preval::Visitors::Loops.enable!
|
8
|
-
Preval::Visitors::Micro.enable!
|
6
|
+
Preval.enable_all!
|
9
7
|
|
10
8
|
source = ARGV.first
|
11
9
|
puts Preval.process(File.exist?(source) ? File.read(source) : source)
|
data/bin/start
ADDED
data/docs/index.html
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html lang="en">
|
3
3
|
<head>
|
4
|
-
<meta charset="utf-8"
|
5
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge"
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1"
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
7
7
|
|
8
8
|
<title>preval</title>
|
9
|
+
<link href="/favicon.png" rel="icon" type="image/png" />
|
10
|
+
|
9
11
|
<style>
|
10
12
|
html, body, main {
|
11
13
|
font-family: "Courier New";
|
Binary file
|
data/docs/server.rb
CHANGED
@@ -4,9 +4,7 @@ require 'bundler/setup'
|
|
4
4
|
require 'preval'
|
5
5
|
require 'sinatra'
|
6
6
|
|
7
|
-
Preval
|
8
|
-
Preval::Visitors::Loops.enable!
|
9
|
-
Preval::Visitors::Micro.enable!
|
7
|
+
Preval.enable_all!
|
10
8
|
|
11
9
|
get '/' do
|
12
10
|
send_file(File.expand_path('index.html', __dir__))
|
data/lib/preval.rb
CHANGED
@@ -8,8 +8,17 @@ module Preval
|
|
8
8
|
class << self
|
9
9
|
attr_reader :visitors
|
10
10
|
|
11
|
+
def enable_all!
|
12
|
+
Visitors::Arithmetic.enable!
|
13
|
+
Visitors::AttrAccessor.enable!
|
14
|
+
Visitors::Fasterer.enable!
|
15
|
+
Visitors::Loops.enable!
|
16
|
+
end
|
17
|
+
|
11
18
|
def process(source)
|
12
|
-
visitors.inject(source)
|
19
|
+
visitors.inject(Parser.parse(source)) do |current, visitor|
|
20
|
+
current.tap { |ast| ast.visit(visitor) }
|
21
|
+
end.to_source
|
13
22
|
end
|
14
23
|
end
|
15
24
|
|
@@ -23,8 +32,9 @@ require 'preval/version'
|
|
23
32
|
require 'preval/visitor'
|
24
33
|
|
25
34
|
require 'preval/visitors/arithmetic'
|
35
|
+
require 'preval/visitors/attr_accessor'
|
36
|
+
require 'preval/visitors/fasterer'
|
26
37
|
require 'preval/visitors/loops'
|
27
|
-
require 'preval/visitors/micro'
|
28
38
|
|
29
39
|
if defined?(Bootsnap)
|
30
40
|
load_iseq = RubyVM::InstructionSequence.method(:load_iseq)
|
data/lib/preval/node.rb
CHANGED
@@ -31,11 +31,11 @@ module Preval
|
|
31
31
|
@literal = literal
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
34
|
+
def [](index, *args)
|
35
35
|
node = body[index]
|
36
36
|
return nil unless node
|
37
37
|
|
38
|
-
args.any? ? node
|
38
|
+
args.any? ? node[*args] : node
|
39
39
|
end
|
40
40
|
|
41
41
|
def join(delim = '')
|
data/lib/preval/version.rb
CHANGED
data/lib/preval/visitor.rb
CHANGED
@@ -2,15 +2,6 @@
|
|
2
2
|
|
3
3
|
module Preval
|
4
4
|
class Visitor
|
5
|
-
def process(source)
|
6
|
-
sexp = Parser.parse(source)
|
7
|
-
sexp.tap { |node| node.visit(self) }.to_source if sexp
|
8
|
-
end
|
9
|
-
|
10
|
-
def process!(source)
|
11
|
-
process(source).tap { |response| raise SyntaxError unless response }
|
12
|
-
end
|
13
|
-
|
14
5
|
def self.enable!
|
15
6
|
Preval.visitors << new
|
16
7
|
end
|
@@ -3,19 +3,19 @@
|
|
3
3
|
module Preval
|
4
4
|
class Visitors
|
5
5
|
class Arithmetic < Visitor
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
using(
|
7
|
+
Module.new do
|
8
|
+
refine Node do
|
9
|
+
def int?(value)
|
10
|
+
is?(:@int) && to_int == value
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
def to_int
|
14
|
+
body[0].to_i
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
|
-
|
17
|
-
|
18
|
-
using IntNode
|
18
|
+
)
|
19
19
|
|
20
20
|
OPERATORS = %i[+ - * / % **].freeze
|
21
21
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Preval
|
4
|
+
class Visitors
|
5
|
+
class AttrAccessor < Visitor
|
6
|
+
def on_def(node)
|
7
|
+
# auto create attr_readers
|
8
|
+
if node.type_match?(:@ident, :params, :bodystmt) &&
|
9
|
+
# def foo; @foo; end
|
10
|
+
node[1].body.none? &&
|
11
|
+
# there are no params to this method
|
12
|
+
node[2, 0].type_match?(:stmts_new, :var_ref) &&
|
13
|
+
# there is only one statement in the body and its a var reference
|
14
|
+
node[2, 0, 1, 0].is?(:@ivar) &&
|
15
|
+
# the var reference is referencing an instance variable
|
16
|
+
node[0].body == node[2, 0, 1, 0].body[1..-1]
|
17
|
+
# the name of the variable matches the name of the method
|
18
|
+
|
19
|
+
ast = Parser.parse("attr_reader :#{node[0].body}")
|
20
|
+
node.update(:stmts_add, ast.body[0].body)
|
21
|
+
end
|
22
|
+
|
23
|
+
# auto create attr_writers
|
24
|
+
if node.type_match?(:@ident, :paren, :bodystmt) &&
|
25
|
+
# def foo=(value); @foo = value; end
|
26
|
+
node[0].body.end_with?('=') &&
|
27
|
+
# this is a setter method
|
28
|
+
node[1, 0, 0].length == 1 &&
|
29
|
+
# there is exactly one required param
|
30
|
+
node[1, 0].body[1..-1].none? &&
|
31
|
+
# there are no other params
|
32
|
+
node[2, 0, 0, 0]&.is?(:stmts_new) &&
|
33
|
+
# there is only one statement in the body
|
34
|
+
node[2, 0, 1].is?(:assign) &&
|
35
|
+
# the only statement is an assignment
|
36
|
+
node[2, 0, 1].type_match?(:var_field, :var_ref) &&
|
37
|
+
# assigning a variable
|
38
|
+
node[2, 0, 1, 0, 0].is?(:@ivar) &&
|
39
|
+
# assigning to an instance variable
|
40
|
+
node[0].body[0..-2] == node[2, 0, 1, 0, 0].body[1..-1] &&
|
41
|
+
# variable name matches the method name
|
42
|
+
node[1, 0, 0][0].body == node[2, 0, 1, 1, 0].body
|
43
|
+
# assignment variable matches the argument name
|
44
|
+
|
45
|
+
ast = Parser.parse("attr_writer :#{node[0].body[0..-2]}")
|
46
|
+
node.update(:stmts_add, ast.body[0].body)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Preval
|
4
|
+
class Visitors
|
5
|
+
# All of these optimizations come from the `fasterer` gem.
|
6
|
+
class Fasterer < Visitor
|
7
|
+
def on_call(node)
|
8
|
+
left, _period, right = node.body
|
9
|
+
|
10
|
+
# replace `.reverse.each` with `.reverse_each`
|
11
|
+
# replace `.shuffle.first` with `.sample`
|
12
|
+
if node.type_match?(:call, :@period, :@ident) &&
|
13
|
+
# foo.each
|
14
|
+
left.type_match?(%i[array vcall], :@period, :@ident)
|
15
|
+
# foo.reverse
|
16
|
+
|
17
|
+
callleft, callperiod, callright = left.body
|
18
|
+
|
19
|
+
if callright.body == 'reverse' && right.body == 'each'
|
20
|
+
callright.update(:@ident, 'reverse_each')
|
21
|
+
node.update(:call, [callleft, callperiod, callright])
|
22
|
+
elsif callright.body == 'shuffle' && right.body == 'first'
|
23
|
+
callright.update(:@ident, 'sample')
|
24
|
+
node.update(:call, [callleft, callperiod, callright])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_method_add_arg(node)
|
30
|
+
# replace `.gsub('...', '...')` with `.tr('...', '...')`
|
31
|
+
if node.type_match?(:call, :arg_paren) &&
|
32
|
+
# foo.gsub()
|
33
|
+
node[0].type_match?(:vcall, :@period, :@ident) &&
|
34
|
+
# foo.gsub
|
35
|
+
node[0, 2].body == 'gsub'
|
36
|
+
# the method being called is gsub
|
37
|
+
|
38
|
+
left = node[1, 0, 0, 0, 1]
|
39
|
+
right = node[1, 0, 0, 1]
|
40
|
+
|
41
|
+
if left.is?(:string_literal) &&
|
42
|
+
right.is?(:string_literal) &&
|
43
|
+
[left, right].all? do |node|
|
44
|
+
node[0, 1].is?(:@tstring_content) &&
|
45
|
+
node[0, 1].body.length == 1
|
46
|
+
end
|
47
|
+
|
48
|
+
node[0, 2].update(:@ident, 'tr')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# replace `.map { ... }.flatten(1)` with `.flat_map { ... }`
|
53
|
+
if node.type_match?(:call, :arg_paren) &&
|
54
|
+
# foo.flatten()
|
55
|
+
node[0].type_match?(:method_add_block, :@period, :@ident) &&
|
56
|
+
# foo.map {}
|
57
|
+
node[0, 0, 0].type_match?(%i[array vcall], :@period, :@ident) &&
|
58
|
+
# foo.flatten
|
59
|
+
node[0, 0, 0, 2].body == 'map' &&
|
60
|
+
# the inner call is a call to map
|
61
|
+
node[0, 2].body == 'flatten' &&
|
62
|
+
# the outer call is a call to flatten
|
63
|
+
node[1].is?(:arg_paren) &&
|
64
|
+
# flatten has a param
|
65
|
+
node[1, 0, 0].type_match?(:args_new, :@int) &&
|
66
|
+
# there is only one argument to flatten and it is an integer
|
67
|
+
node[1, 0, 0, 1].body == '1'
|
68
|
+
# the value of the argument to flatten is 1
|
69
|
+
|
70
|
+
node[0, 0, 0, 2].update(:@ident, 'flat_map')
|
71
|
+
node.update(:method_add_block, node[0, 0].body)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -3,36 +3,74 @@
|
|
3
3
|
module Preval
|
4
4
|
class Visitors
|
5
5
|
class Loops < Visitor
|
6
|
-
module TrueNode
|
7
|
-
refine Node do
|
8
|
-
def true?
|
9
|
-
is?(:var_ref) && starts_with?(:@kw) && body[0].body == 'true'
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
using TrueNode
|
15
|
-
|
16
6
|
def on_for(node)
|
17
|
-
|
7
|
+
ast = Parser.parse(<<~CODE)
|
18
8
|
#{node.source(1)}.each do |#{node.source(0)}|
|
19
9
|
#{node.source(2)}
|
20
10
|
end
|
21
11
|
CODE
|
22
12
|
|
23
|
-
node.update(:stmts_add,
|
13
|
+
node.update(:stmts_add, ast[0].body)
|
24
14
|
end
|
25
15
|
|
26
16
|
def on_while(node)
|
27
|
-
|
17
|
+
# auto replace `while true` with `loop do`
|
18
|
+
if node[0].is?(:var_ref) &&
|
19
|
+
# the predicate to the while is a variable reference
|
20
|
+
node[0, 0].is?(:@kw) &&
|
21
|
+
# the variable reference is a keyword
|
22
|
+
node[0, 0].body == 'true'
|
23
|
+
# the keyword is "true"
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
ast = Parser.parse(<<~CODE)
|
26
|
+
loop do
|
27
|
+
#{node.source(1)}
|
28
|
+
end
|
29
|
+
CODE
|
30
|
+
|
31
|
+
node.update(:stmts_add, ast[0].body)
|
32
|
+
end
|
33
|
+
|
34
|
+
# ignore `while false`
|
35
|
+
if node[0].is?(:var_ref) &&
|
36
|
+
# the predicate to the while is a variable reference
|
37
|
+
node[0, 0].is?(:@kw) &&
|
38
|
+
# the variable reference is a keyword
|
39
|
+
node[0, 0].body == 'false'
|
40
|
+
# the kwyword is "false"
|
34
41
|
|
35
|
-
|
42
|
+
node.update(:void_stmt, [])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_until(node)
|
47
|
+
# auto replace `until false` with `loop do`
|
48
|
+
if node[0].is?(:var_ref) &&
|
49
|
+
# the predicate to the while is a variable reference
|
50
|
+
node[0, 0].is?(:@kw) &&
|
51
|
+
# the variable reference is a keyword
|
52
|
+
node[0, 0].body == 'false'
|
53
|
+
# the keyword is "false"
|
54
|
+
|
55
|
+
ast = Parser.parse(<<~CODE)
|
56
|
+
loop do
|
57
|
+
#{node.source(1)}
|
58
|
+
end
|
59
|
+
CODE
|
60
|
+
|
61
|
+
node.update(:stmts_add, ast[0].body)
|
62
|
+
end
|
63
|
+
|
64
|
+
# ignore `until true`
|
65
|
+
if node[0].is?(:var_ref) &&
|
66
|
+
# the predicate to the until is a variable reference
|
67
|
+
node[0, 0].is?(:@kw) &&
|
68
|
+
# the variable reference is a keyword
|
69
|
+
node[0, 0].body == 'true'
|
70
|
+
# the kwyword is "true"
|
71
|
+
|
72
|
+
node.update(:void_stmt, [])
|
73
|
+
end
|
36
74
|
end
|
37
75
|
end
|
38
76
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: preval
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Deisz
|
@@ -71,7 +71,9 @@ files:
|
|
71
71
|
- bin/parse
|
72
72
|
- bin/print
|
73
73
|
- bin/setup
|
74
|
+
- bin/start
|
74
75
|
- docs/index.html
|
76
|
+
- docs/public/favicon.png
|
75
77
|
- docs/server.rb
|
76
78
|
- lib/preval.rb
|
77
79
|
- lib/preval/format.rb
|
@@ -80,8 +82,9 @@ files:
|
|
80
82
|
- lib/preval/version.rb
|
81
83
|
- lib/preval/visitor.rb
|
82
84
|
- lib/preval/visitors/arithmetic.rb
|
85
|
+
- lib/preval/visitors/attr_accessor.rb
|
86
|
+
- lib/preval/visitors/fasterer.rb
|
83
87
|
- lib/preval/visitors/loops.rb
|
84
|
-
- lib/preval/visitors/micro.rb
|
85
88
|
- preval.gemspec
|
86
89
|
homepage: https://github.com/kddeisz/preval
|
87
90
|
licenses:
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Preval
|
4
|
-
class Visitors
|
5
|
-
class Micro < Visitor
|
6
|
-
def on_call(node)
|
7
|
-
left, _period, right = node.body
|
8
|
-
|
9
|
-
if node.type_match?(:call, :@period, :@ident) && left.type_match?(%i[array vcall], :@period, :@ident)
|
10
|
-
callleft, callperiod, callright = left.body
|
11
|
-
|
12
|
-
if callright.body == 'reverse' && right.body == 'each'
|
13
|
-
callright.update(:@ident, 'reverse_each')
|
14
|
-
node.update(:call, [callleft, callperiod, callright])
|
15
|
-
elsif callright.body == 'shuffle' && right.body == 'first'
|
16
|
-
callright.update(:@ident, 'sample')
|
17
|
-
node.update(:call, [callleft, callperiod, callright])
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def on_def(node)
|
23
|
-
if node.type_match?(:@ident, :params, :bodystmt) &&
|
24
|
-
node.body[1].body.none? &&
|
25
|
-
node.dig(2, 0, 0).is?(:stmts_new) &&
|
26
|
-
|
27
|
-
var_ref = node.dig(2, 0, 1)
|
28
|
-
|
29
|
-
if var_ref.is?(:var_ref) &&
|
30
|
-
var_ref.type_match?(:@ivar) &&
|
31
|
-
node.body[0].body == var_ref.body[0].body[1..-1]
|
32
|
-
|
33
|
-
sexp = Parser.parse("attr_reader :#{node.body[0].body}")
|
34
|
-
node.update(:stmts_add, sexp.body[0].body)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def on_method_add_arg(node)
|
40
|
-
if node.type_match?(:call, :arg_paren)
|
41
|
-
if node.body[0].type_match?(:vcall, :@period, :@ident) &&
|
42
|
-
node.dig(0, 2).body == 'gsub'
|
43
|
-
|
44
|
-
left = node.dig(1, 0, 0, 0, 1)
|
45
|
-
right = node.dig(1, 0, 0, 1)
|
46
|
-
|
47
|
-
if left.is?(:string_literal) &&
|
48
|
-
right.is?(:string_literal) &&
|
49
|
-
[left, right].all? do |node|
|
50
|
-
node.dig(0, 1).is?(:@tstring_content) &&
|
51
|
-
node.dig(0, 1).body.length == 1
|
52
|
-
end
|
53
|
-
|
54
|
-
node.dig(0, 2).update(:@ident, 'tr')
|
55
|
-
end
|
56
|
-
elsif node.dig(0).type_match?(:method_add_block, :@period, :@ident) &&
|
57
|
-
node.dig(0, 0, 0).type_match?(%i[array vcall], :@period, :@ident) &&
|
58
|
-
node.dig(0, 0, 0, 2).body == 'map' &&
|
59
|
-
node.dig(0, 2).body == 'flatten' &&
|
60
|
-
node.dig(1).is?(:arg_paren) &&
|
61
|
-
node.dig(1, 0, 0, 0).is?(:args_new) &&
|
62
|
-
node.dig(1, 0, 0, 1).is?(:@int) &&
|
63
|
-
node.dig(1, 0, 0, 1).body == '1'
|
64
|
-
|
65
|
-
node.dig(0, 0, 0, 2).update(:@ident, 'flat_map')
|
66
|
-
node.update(:method_add_block, node.dig(0, 0).body)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|