unparser 0.3.0 → 0.4.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 +4 -4
- data/.circleci/config.yml +32 -8
- data/Changelog.md +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +26 -20
- data/README.md +21 -21
- data/config/flay.yml +1 -1
- data/config/reek.yml +9 -48
- data/lib/unparser.rb +62 -2
- data/lib/unparser/ast.rb +1 -1
- data/lib/unparser/cli/differ.rb +1 -1
- data/lib/unparser/cli/source.rb +2 -15
- data/lib/unparser/constants.rb +4 -2
- data/lib/unparser/emitter.rb +0 -14
- data/lib/unparser/emitter/argument.rb +62 -0
- data/lib/unparser/emitter/assignment.rb +4 -16
- data/lib/unparser/emitter/block.rb +29 -4
- data/lib/unparser/emitter/hookexe.rb +1 -1
- data/lib/unparser/emitter/index.rb +136 -0
- data/lib/unparser/emitter/lambda.rb +25 -0
- data/lib/unparser/emitter/literal/array.rb +1 -4
- data/lib/unparser/emitter/meta.rb +2 -2
- data/lib/unparser/emitter/rescue.rb +1 -1
- data/lib/unparser/emitter/send.rb +14 -28
- data/lib/unparser/emitter/send/attribute_assignment.rb +10 -24
- data/spec/spec_helper.rb +0 -11
- data/spec/unit/unparser/comments/consume_spec.rb +1 -1
- data/spec/unit/unparser/comments/take_all_spec.rb +1 -1
- data/spec/unit/unparser/comments/take_before_spec.rb +2 -2
- data/spec/unit/unparser/comments/take_eol_comments_spec.rb +6 -6
- data/spec/unit/unparser_spec.rb +365 -248
- data/unparser.gemspec +1 -1
- metadata +5 -6
- data/lib/unparser/emitter/send/index.rb +0 -127
- data/spec/support/parser_class_generator.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52e96163f8fc7a9a3da3464e326997c9dc5a094225806e0f2fc72e0474a97026
|
4
|
+
data.tar.gz: 719ac295c33e15c44cbe9bff91920536367b37409e71fb407f1fecef2cd69dbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 661ff992d06f1c3f1ff05e66ecd789c08fc91432af9e082a036309a6d74bec83e99b58026f1e85080c86f2b8ab8d01de08bb8e743225e5204690670c9d0f280e
|
7
|
+
data.tar.gz: 338124c08c6e241f70f587db3e149da9562dfd18550bae2e1f4d6afaa76f9e3b9d39dae37ca1d81e7ff97d50e246a2a56faa984edb4988c05e9e69d6880d12ba
|
data/.circleci/config.yml
CHANGED
@@ -1,17 +1,41 @@
|
|
1
1
|
defaults: &defaults
|
2
2
|
working_directory: ~/unparser
|
3
|
-
|
4
|
-
-
|
5
|
-
- run: bundle install
|
6
|
-
- run: bundle exec rake ci
|
3
|
+
docker:
|
4
|
+
- image: circleci/ruby:2.5.3
|
7
5
|
version: 2
|
8
6
|
jobs:
|
9
|
-
|
7
|
+
unit_specs:
|
10
8
|
<<: *defaults
|
11
|
-
|
12
|
-
-
|
9
|
+
steps:
|
10
|
+
- checkout
|
11
|
+
- run: bundle install
|
12
|
+
- run: bundle exec rspec spec/unit
|
13
|
+
integration_specs:
|
14
|
+
<<: *defaults
|
15
|
+
steps:
|
16
|
+
- checkout
|
17
|
+
- run: bundle install
|
18
|
+
- run: bundle exec rspec spec/integration
|
19
|
+
metrics:
|
20
|
+
<<: *defaults
|
21
|
+
steps:
|
22
|
+
- checkout
|
23
|
+
- run: bundle install
|
24
|
+
- run: bundle exec rake metrics:rubocop
|
25
|
+
- run: bundle exec rake metrics:reek
|
26
|
+
- run: bundle exec rake metrics:flay
|
27
|
+
- run: bundle exec rake metrics:flog
|
28
|
+
mutant:
|
29
|
+
<<: *defaults
|
30
|
+
steps:
|
31
|
+
- checkout
|
32
|
+
- run: bundle install
|
33
|
+
- run: bundle exec rake metrics:mutant
|
13
34
|
workflows:
|
14
35
|
version: 2
|
15
36
|
test:
|
16
37
|
jobs:
|
17
|
-
-
|
38
|
+
- unit_specs
|
39
|
+
- integration_specs
|
40
|
+
- metrics
|
41
|
+
- mutant
|
data/Changelog.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,31 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/mbj/mutant
|
3
|
+
revision: 6b36372385ec1bedc0d170470e65d7d33740769e
|
4
|
+
branch: change/to-modern-ast
|
5
|
+
specs:
|
6
|
+
mutant (0.8.20)
|
7
|
+
abstract_type (~> 0.0.7)
|
8
|
+
adamantium (~> 0.2.0)
|
9
|
+
anima (~> 0.3.0)
|
10
|
+
ast (~> 2.2)
|
11
|
+
concord (~> 0.1.5)
|
12
|
+
diff-lcs (~> 1.3)
|
13
|
+
equalizer (~> 0.0.9)
|
14
|
+
ice_nine (~> 0.11.1)
|
15
|
+
memoizable (~> 0.4.2)
|
16
|
+
morpher (~> 0.2.6)
|
17
|
+
parser (~> 2.5.1)
|
18
|
+
procto (~> 0.0.2)
|
19
|
+
regexp_parser (~> 1.2)
|
20
|
+
unparser (~> 0.3.0)
|
21
|
+
mutant-rspec (0.8.20)
|
22
|
+
mutant (~> 0.8.20)
|
23
|
+
rspec-core (>= 3.4.0, < 4.0.0)
|
24
|
+
|
1
25
|
PATH
|
2
26
|
remote: .
|
3
27
|
specs:
|
4
|
-
unparser (0.
|
28
|
+
unparser (0.4.0)
|
5
29
|
abstract_type (~> 0.0.7)
|
6
30
|
adamantium (~> 0.2.0)
|
7
31
|
concord (~> 0.1.5)
|
@@ -82,25 +106,6 @@ GEM
|
|
82
106
|
equalizer (~> 0.0.9)
|
83
107
|
ice_nine (~> 0.11.0)
|
84
108
|
procto (~> 0.0.2)
|
85
|
-
mutant (0.8.19)
|
86
|
-
abstract_type (~> 0.0.7)
|
87
|
-
adamantium (~> 0.2.0)
|
88
|
-
anima (~> 0.3.0)
|
89
|
-
ast (~> 2.2)
|
90
|
-
concord (~> 0.1.5)
|
91
|
-
diff-lcs (~> 1.3)
|
92
|
-
equalizer (~> 0.0.9)
|
93
|
-
ice_nine (~> 0.11.1)
|
94
|
-
memoizable (~> 0.4.2)
|
95
|
-
morpher (~> 0.2.6)
|
96
|
-
parallel (~> 1.3)
|
97
|
-
parser (~> 2.5.1)
|
98
|
-
procto (~> 0.0.2)
|
99
|
-
regexp_parser (~> 1.2)
|
100
|
-
unparser (~> 0.2.5)
|
101
|
-
mutant-rspec (0.8.19)
|
102
|
-
mutant (~> 0.8.19)
|
103
|
-
rspec-core (>= 3.4.0, < 4.0.0)
|
104
109
|
parallel (1.12.1)
|
105
110
|
parser (2.5.3.0)
|
106
111
|
ast (~> 2.4.0)
|
@@ -166,6 +171,7 @@ DEPENDENCIES
|
|
166
171
|
anima (~> 0.3.0)
|
167
172
|
devtools (~> 0.1.21)
|
168
173
|
morpher (~> 0.2.6)
|
174
|
+
mutant!
|
169
175
|
unparser!
|
170
176
|
|
171
177
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -7,12 +7,12 @@ unparser
|
|
7
7
|
[](https://rubygems.org/gems/unparser)
|
8
8
|
|
9
9
|
Generate equivalent source for ASTs from whitequarks [parser](https://github.com/whitequark/parser).
|
10
|
-
Excluding the macruby extensions the parser gem implemnents on top of ruby syntax.
|
11
10
|
|
12
|
-
|
13
|
-
syntax starting with parser release 2.3. If you feel the need to get them supported, contact me.
|
11
|
+
The following constraints apply:
|
14
12
|
|
15
|
-
|
13
|
+
* No support for macruby extensions
|
14
|
+
* Only support for the [modern AST](https://github.com/whitequark/parser/#usage) format
|
15
|
+
* Only support for Ruby >= 2.5
|
16
16
|
|
17
17
|
It serves well for [mutant](https://github.com/mbj/mutant) mutators and the in-memory vendoring for self hosting,
|
18
18
|
and other tooling.
|
@@ -20,15 +20,19 @@ and other tooling.
|
|
20
20
|
Public API:
|
21
21
|
-----------
|
22
22
|
|
23
|
-
While unparser is in the `0.x` versions its public API can change any moment.
|
24
|
-
version constraints that should give the best mileage.
|
23
|
+
While unparser is in the `0.x` versions its public API can change any moment.
|
24
|
+
I recommend to use `~> 0.x.y` style version constraints that should give the best mileage.
|
25
25
|
|
26
26
|
Usage
|
27
27
|
-----
|
28
28
|
|
29
29
|
```ruby
|
30
|
+
require 'parser/current'
|
30
31
|
require 'unparser'
|
31
|
-
|
32
|
+
|
33
|
+
ast = Unpaser.parse('your(ruby(code))')
|
34
|
+
|
35
|
+
Unparser.unparse(ast) # => 'your(ruby(code))'
|
32
36
|
```
|
33
37
|
|
34
38
|
To preserve the comments from the source:
|
@@ -36,8 +40,10 @@ To preserve the comments from the source:
|
|
36
40
|
```ruby
|
37
41
|
require 'parser/current'
|
38
42
|
require 'unparser'
|
39
|
-
|
40
|
-
|
43
|
+
|
44
|
+
ast, comments = Unpaser.parse_with_comments('your(ruby(code)) # with comments')
|
45
|
+
|
46
|
+
Unparser.unparse(ast, comments) # => 'your(ruby(code)) # with comments'
|
41
47
|
```
|
42
48
|
|
43
49
|
Passing in manually constructed AST:
|
@@ -71,22 +77,19 @@ Unparser.unparse(node) # => "def foo(x)\n x + 3\nend"
|
|
71
77
|
Note: DO NOT attempt to pass in nodes generated via `AST::Sexp#s`, these ones return
|
72
78
|
API incompatible `AST::Node` instances, unparser needs `Parser::AST::Node` instances.
|
73
79
|
|
74
|
-
|
75
80
|
Equivalent vs identical:
|
76
81
|
|
77
82
|
```ruby
|
78
83
|
require 'unparser'
|
79
84
|
|
80
|
-
|
81
|
-
%w
|
85
|
+
node = Unparser.parse(<<~'RUBY')
|
86
|
+
%w[foo bar]
|
82
87
|
RUBY
|
83
88
|
|
84
|
-
|
85
|
-
|
86
|
-
generated = Unparser.unparse(node) # ["foo", "bar"], NOT %w(foo bar) !
|
89
|
+
generated = Unparser.unparse(node) # ["foo", "bar"], NOT %w[foo bar] !
|
87
90
|
|
88
91
|
code == generated # false, not identical code
|
89
|
-
|
92
|
+
Unparser.parse(generated) == node # true, but identical AST
|
90
93
|
```
|
91
94
|
|
92
95
|
Summary: unparser does not reproduce your source! It produces equivalent source.
|
@@ -94,7 +97,7 @@ Summary: unparser does not reproduce your source! It produces equivalent source.
|
|
94
97
|
Testing:
|
95
98
|
--------
|
96
99
|
|
97
|
-
Unparser currently successfully round trips almost all ruby code around. Using MRI-2.
|
100
|
+
Unparser currently successfully round trips almost all ruby code around. Using MRI-2.5.x.
|
98
101
|
If there is a non round trippable example that is NOT subjected to known [Limitations](#limitations).
|
99
102
|
please report a bug.
|
100
103
|
|
@@ -106,10 +109,7 @@ Limitations:
|
|
106
109
|
Source parsed with magic encoding headers other than UTF-8 and that have literal strings.
|
107
110
|
where parts can be represented in UTF-8 will fail to get reproduced.
|
108
111
|
|
109
|
-
|
110
|
-
Unparser does not reproduce these.
|
111
|
-
|
112
|
-
A fix might be possible and requires some guessing or parser metadata the raw AST does not carry.
|
112
|
+
A fix is possible as with latest updates the parser gem carries the information.
|
113
113
|
|
114
114
|
Example:
|
115
115
|
|
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -11,8 +11,7 @@ detectors:
|
|
11
11
|
exclude: []
|
12
12
|
ControlParameter:
|
13
13
|
enabled: true
|
14
|
-
exclude:
|
15
|
-
- Mutant::Expression#match_length
|
14
|
+
exclude: []
|
16
15
|
DataClump:
|
17
16
|
enabled: true
|
18
17
|
exclude: []
|
@@ -31,9 +30,7 @@ detectors:
|
|
31
30
|
exclude: []
|
32
31
|
LongParameterList:
|
33
32
|
enabled: true
|
34
|
-
exclude:
|
35
|
-
- Mutant::Matcher::Method::Instance#self.build
|
36
|
-
- Mutant::Meta::Example::DSL # 3 vars
|
33
|
+
exclude: []
|
37
34
|
max_params: 2
|
38
35
|
LongYieldList:
|
39
36
|
enabled: true
|
@@ -41,55 +38,30 @@ detectors:
|
|
41
38
|
max_params: 2
|
42
39
|
NestedIterators:
|
43
40
|
enabled: true
|
44
|
-
exclude:
|
45
|
-
- Mutant#self.singleton_subclass_instance
|
46
|
-
- Mutant::CLI#parse
|
47
|
-
- Mutant::Mutator::Node::Arguments#emit_argument_mutations
|
48
|
-
- Mutant::Mutator::Node::Resbody#mutate_captures
|
49
|
-
- Mutant::Mutator::Util::Array::Element#dispatch
|
50
|
-
- Mutant::Parallel::Master#run
|
51
|
-
- Mutant::RequireHighjack#self.call
|
52
|
-
- Mutant::Selector::Expression#call
|
53
|
-
- Parser::Lexer#self.new
|
41
|
+
exclude: []
|
54
42
|
max_allowed_nesting: 1
|
55
43
|
ignore_iterators: []
|
56
44
|
NilCheck:
|
57
45
|
enabled: false
|
58
46
|
RepeatedConditional:
|
59
47
|
enabled: true
|
60
|
-
exclude:
|
61
|
-
- Mutant::Mutator
|
62
|
-
- Mutant::Meta::Example::DSL
|
48
|
+
exclude: []
|
63
49
|
max_ifs: 1
|
64
50
|
TooManyInstanceVariables:
|
65
51
|
enabled: true
|
66
|
-
exclude:
|
67
|
-
- Mutant::Mutator # 4 vars
|
68
|
-
- Mutant::Parallel::Master # 4 vars
|
69
|
-
- Mutant::Meta::Example::DSL # 4 vars
|
52
|
+
exclude: []
|
70
53
|
max_instance_variables: 3
|
71
54
|
TooManyMethods:
|
72
55
|
enabled: true
|
73
|
-
exclude:
|
74
|
-
- Mutant::CLI
|
75
|
-
- Mutant::Mutator::Node
|
76
|
-
- Mutant::Parallel::Master
|
56
|
+
exclude: []
|
77
57
|
max_methods: 10
|
78
58
|
TooManyStatements:
|
79
59
|
enabled: true
|
80
|
-
exclude:
|
81
|
-
- Mutant::CLI#add_debug_options
|
82
|
-
- Mutant::CLI#add_environment_options
|
83
|
-
- Mutant::Reporter::CLI::Printer::Config#run
|
84
|
-
- Mutant::Reporter::CLI::Printer::EnvProgress#run
|
85
|
-
- Mutant::Runner#run_driver
|
86
|
-
- Mutant::Zombifier::File#self.find
|
60
|
+
exclude: []
|
87
61
|
max_statements: 7
|
88
62
|
UncommunicativeMethodName:
|
89
63
|
enabled: true
|
90
|
-
exclude:
|
91
|
-
- Mutant::AST::Sexp#s
|
92
|
-
- Mutant::Mutation#sha1
|
64
|
+
exclude: []
|
93
65
|
reject:
|
94
66
|
- '/^[a-z]$/'
|
95
67
|
- '/[0-9]$/'
|
@@ -123,15 +95,4 @@ detectors:
|
|
123
95
|
exclude: []
|
124
96
|
UtilityFunction:
|
125
97
|
enabled: true
|
126
|
-
exclude:
|
127
|
-
- Mutant::AST::Sexp#s
|
128
|
-
- Mutant::Actor::Env#new_mailbox
|
129
|
-
- Mutant::CLI#reporter
|
130
|
-
- Mutant::Integration::Null#call
|
131
|
-
- Mutant::Integration::Rspec#parse_example
|
132
|
-
- Mutant::Integration::Rspec#parse_expression # intentional, private
|
133
|
-
- Mutant::Meta::Example::Verification#format_mutations # intentional, private
|
134
|
-
- Mutant::Reporter::CLI::Format::Progressive#new_buffer
|
135
|
-
- Mutant::Reporter::CLI::Printer::StatusProgressive#object # False positive calls super
|
136
|
-
- Mutant::Repository::Diff#tracks? # intentional, private
|
137
|
-
- Mutant::Repository::Diff#within_working_directory? # intentional, private
|
98
|
+
exclude: []
|
data/lib/unparser.rb
CHANGED
@@ -8,10 +8,15 @@ require 'parser/current'
|
|
8
8
|
|
9
9
|
# Library namespace
|
10
10
|
module Unparser
|
11
|
+
# Unparser specific AST builder defaulting to modern AST format
|
12
|
+
class Builder < Parser::Builders::Default
|
13
|
+
modernize
|
14
|
+
end
|
11
15
|
|
12
16
|
EMPTY_STRING = ''.freeze
|
17
|
+
EMPTY_ARRAY = [].freeze
|
13
18
|
|
14
|
-
|
19
|
+
private_constant(*constants(false))
|
15
20
|
|
16
21
|
# Unparse an AST (and, optionally, comments) into a string
|
17
22
|
#
|
@@ -31,6 +36,60 @@ module Unparser
|
|
31
36
|
buffer.content
|
32
37
|
end
|
33
38
|
|
39
|
+
# Parse string into AST
|
40
|
+
#
|
41
|
+
# @param [String] source
|
42
|
+
#
|
43
|
+
# @return [Parser::AST::Node]
|
44
|
+
def self.parse(source)
|
45
|
+
parser.parse(buffer(source))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Parse string into AST, with comments
|
49
|
+
#
|
50
|
+
# @param [String] source
|
51
|
+
#
|
52
|
+
# @return [Parser::AST::Node]
|
53
|
+
def self.parse_with_comments(source)
|
54
|
+
parser.parse_with_comments(buffer(source))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Parser instance that produces AST unparser understands
|
58
|
+
#
|
59
|
+
# @return [Parser::Base]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
#
|
63
|
+
# ignore :reek:NestedIterators
|
64
|
+
def self.parser
|
65
|
+
Parser::CurrentRuby.new(Builder.new).tap do |parser|
|
66
|
+
parser.diagnostics.tap do |diagnostics|
|
67
|
+
diagnostics.all_errors_are_fatal = true
|
68
|
+
diagnostics.consumer = method(:consume_diagnostic)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Consume diagnostic
|
74
|
+
#
|
75
|
+
# @param [Parser::Diagnostic] diagnostic
|
76
|
+
#
|
77
|
+
# @return [undefined]
|
78
|
+
def self.consume_diagnostic(diagnostic)
|
79
|
+
Kernel.warn(diagnostic.render)
|
80
|
+
end
|
81
|
+
private_class_method :consume_diagnostic
|
82
|
+
|
83
|
+
# Construct a parser buffer from string
|
84
|
+
#
|
85
|
+
# @param [String] source
|
86
|
+
#
|
87
|
+
# @return [Parser::Source::Buffer]
|
88
|
+
def self.buffer(source)
|
89
|
+
Parser::Source::Buffer.new('(string)').tap do |buffer|
|
90
|
+
buffer.source = source
|
91
|
+
end
|
92
|
+
end
|
34
93
|
end # Unparser
|
35
94
|
|
36
95
|
require 'unparser/buffer'
|
@@ -56,7 +115,6 @@ require 'unparser/emitter/meta'
|
|
56
115
|
require 'unparser/emitter/send'
|
57
116
|
require 'unparser/emitter/send/unary'
|
58
117
|
require 'unparser/emitter/send/binary'
|
59
|
-
require 'unparser/emitter/send/index'
|
60
118
|
require 'unparser/emitter/send/regular'
|
61
119
|
require 'unparser/emitter/send/conditional'
|
62
120
|
require 'unparser/emitter/send/arguments'
|
@@ -93,5 +151,7 @@ require 'unparser/emitter/flipflop'
|
|
93
151
|
require 'unparser/emitter/rescue'
|
94
152
|
require 'unparser/emitter/resbody'
|
95
153
|
require 'unparser/emitter/ensure'
|
154
|
+
require 'unparser/emitter/index'
|
155
|
+
require 'unparser/emitter/lambda'
|
96
156
|
# make it easy for zombie
|
97
157
|
require 'unparser/finalize'
|
data/lib/unparser/ast.rb
CHANGED