unparser 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.travis.yml +2 -1
- data/Changelog.md +5 -0
- data/Gemfile +2 -0
- data/Gemfile.devtools +28 -17
- data/README.md +55 -1
- data/circle.yml +3 -3
- data/config/flay.yml +1 -1
- data/config/reek.yml +8 -3
- data/config/rubocop.yml +1 -1
- data/lib/unparser.rb +0 -1
- data/lib/unparser/ast.rb +2 -2
- data/lib/unparser/buffer.rb +12 -4
- data/lib/unparser/cli.rb +8 -3
- data/lib/unparser/cli/source.rb +78 -16
- data/lib/unparser/constants.rb +1 -1
- data/lib/unparser/emitter/begin.rb +0 -10
- data/lib/unparser/emitter/ensure.rb +5 -1
- data/lib/unparser/emitter/flipflop.rb +1 -1
- data/lib/unparser/emitter/flow_modifier.rb +1 -1
- data/lib/unparser/emitter/if.rb +3 -3
- data/lib/unparser/emitter/repetition.rb +1 -1
- data/lib/unparser/emitter/resbody.rb +1 -1
- data/lib/unparser/emitter/rescue.rb +1 -1
- data/lib/unparser/emitter/send/attribute_assignment.rb +34 -1
- data/spec/integration/unparser/corpus_spec.rb +116 -0
- data/spec/integrations.yml +23 -0
- data/spec/spec_helper.rb +5 -3
- data/spec/unit/unparser_spec.rb +42 -7
- data/unparser.gemspec +4 -4
- metadata +56 -54
- data/lib/unparser/strip_helper.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 034e53fe83f3cb6b5d1c99e64f35b73d505812bf
|
4
|
+
data.tar.gz: 261ece646cfa726f17d70c2d82a44f837d6155b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff483fa78c83e951ff869033f025238d75dbbba20a747952a32ce034c3a88ee346a0aeab555053fb27b94a440a38b4a9a18b036d672b7e64545fec4d0bec788b
|
7
|
+
data.tar.gz: db9c2c31f83b67d7bf70893c774a53b764a4e02ff7f096555fe42c88ba1ee504e962ff6e0e4e20be3febfa08ad09884a0b0e363bab05034127aef404af552064
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.devtools
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
group :development do
|
4
|
-
gem 'rake',
|
5
|
-
gem 'rspec',
|
6
|
-
gem '
|
4
|
+
gem 'rake', '~> 10.2.1'
|
5
|
+
gem 'rspec', '~> 2.14.1'
|
6
|
+
gem 'rspec-core', '~> 2.14.8'
|
7
|
+
gem 'yard', '~> 0.8.7.4'
|
7
8
|
|
8
9
|
platform :rbx do
|
9
10
|
gem 'rubysl-singleton', '~> 2.0.0'
|
@@ -11,23 +12,23 @@ group :development do
|
|
11
12
|
end
|
12
13
|
|
13
14
|
group :yard do
|
14
|
-
gem 'kramdown', '~> 1.3.
|
15
|
+
gem 'kramdown', '~> 1.3.3'
|
15
16
|
end
|
16
17
|
|
17
18
|
group :guard do
|
18
|
-
gem 'guard', '~> 2.
|
19
|
+
gem 'guard', '~> 2.6.0'
|
19
20
|
gem 'guard-bundler', '~> 2.0.0'
|
20
|
-
gem 'guard-rspec', '~> 4.2.
|
21
|
-
gem 'guard-rubocop', '~> 1.0.
|
21
|
+
gem 'guard-rspec', '~> 4.2.8'
|
22
|
+
gem 'guard-rubocop', '~> 1.0.2'
|
22
23
|
|
23
24
|
# file system change event handling
|
24
|
-
gem 'listen', '~> 2.
|
25
|
+
gem 'listen', '~> 2.7.1'
|
25
26
|
gem 'rb-fchange', '~> 0.0.6', require: false
|
26
|
-
gem 'rb-fsevent', '~> 0.9.
|
27
|
-
gem 'rb-inotify', '~> 0.9.
|
27
|
+
gem 'rb-fsevent', '~> 0.9.4', require: false
|
28
|
+
gem 'rb-inotify', '~> 0.9.3', require: false
|
28
29
|
|
29
30
|
# notification handling
|
30
|
-
gem 'libnotify', '~> 0.8.
|
31
|
+
gem 'libnotify', '~> 0.8.2', require: false
|
31
32
|
gem 'rb-notifu', '~> 0.0.4', require: false
|
32
33
|
gem 'terminal-notifier-guard', '~> 1.5.3', require: false
|
33
34
|
end
|
@@ -36,25 +37,35 @@ group :metrics do
|
|
36
37
|
gem 'coveralls', '~> 0.7.0'
|
37
38
|
gem 'flay', '~> 2.4.0'
|
38
39
|
gem 'flog', '~> 4.2.0'
|
39
|
-
gem 'reek', '~> 1.3.
|
40
|
-
gem 'rubocop', '~> 0.
|
40
|
+
gem 'reek', '~> 1.3.7'
|
41
|
+
gem 'rubocop', '~> 0.19.1'
|
41
42
|
gem 'simplecov', '~> 0.8.2'
|
42
|
-
gem 'yardstick', '~> 0.9.
|
43
|
+
gem 'yardstick', '~> 0.9.9'
|
44
|
+
|
45
|
+
platforms :mri do
|
46
|
+
gem 'mutant', '~> 0.5.9'
|
47
|
+
gem 'mutant-rspec', '~> 0.5.3'
|
48
|
+
end
|
43
49
|
|
44
50
|
platforms :ruby_19, :ruby_20 do
|
45
|
-
gem 'mutant', '~> 0.3.0', git: 'https://github.com/mbj/mutant.git'
|
46
51
|
gem 'yard-spellcheck', '~> 0.1.5'
|
47
52
|
end
|
48
53
|
|
49
54
|
platform :rbx do
|
50
55
|
gem 'json', '~> 1.8.1'
|
51
|
-
gem 'racc', '~> 1.4.
|
56
|
+
gem 'racc', '~> 1.4.11'
|
52
57
|
gem 'rubysl-logger', '~> 2.0.0'
|
53
58
|
gem 'rubysl-open-uri', '~> 2.0.0'
|
54
|
-
gem 'rubysl-prettyprint', '~> 2.0.
|
59
|
+
gem 'rubysl-prettyprint', '~> 2.0.3'
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
58
63
|
group :benchmarks do
|
59
64
|
gem 'rbench', '~> 0.2.3'
|
60
65
|
end
|
66
|
+
|
67
|
+
platform :jruby do
|
68
|
+
group :jruby do
|
69
|
+
gem 'jruby-openssl', '~> 0.8.5'
|
70
|
+
end
|
71
|
+
end
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Generate equivalent source for ASTs from whitequarks [parser](https://github.com
|
|
9
9
|
|
10
10
|
This library is able to reproduce 100% of ruby 1.9 and 2.0 syntax. Including its own source code.
|
11
11
|
|
12
|
-
It serves well for [mutant](https://github.
|
12
|
+
It serves well for [mutant](https://github.com/mbj/mutant) mutators and the in-memory vendoring for self hosting.
|
13
13
|
|
14
14
|
This library dropped the reproduction of 1.8 syntax in the 0.1.0 release.
|
15
15
|
It currently does not have support for 2.1 specific syntax.
|
@@ -50,6 +50,60 @@ Parser::CurrentRuby.parse(generated) == node # true, but identical AST
|
|
50
50
|
|
51
51
|
Summary: unparser does not reproduce your source! It produces equivalent source.
|
52
52
|
|
53
|
+
Testing:
|
54
|
+
--------
|
55
|
+
|
56
|
+
Unparser currently successfully round trips almost all ruby code around. Using MRI-2.0.0.
|
57
|
+
If there is a non round trippable example that is NOT subjected to known [Limitations](#limitations).
|
58
|
+
please report a bug.
|
59
|
+
|
60
|
+
On CI unparser is currently tested against rubyspec with minor [excludes](https://github.com/mbj/unparser/blob/master/spec/integrations.yml).
|
61
|
+
|
62
|
+
Limitations:
|
63
|
+
------------
|
64
|
+
|
65
|
+
Source parsed with magic encoding headers other than UTF-8 and that have literal strings.
|
66
|
+
where parts can be represented in UTF-8 will fail to get reproduced.
|
67
|
+
|
68
|
+
Please note: If you are on 1.9.3 or any 1.9 mode ruby and use UTF-8 encoded source via the magic encoding header:
|
69
|
+
Unparser does not reproduce these.
|
70
|
+
|
71
|
+
A fix might be possible and requires some guessing or parser metadata the raw AST does not carry.
|
72
|
+
|
73
|
+
Example:
|
74
|
+
|
75
|
+
Original-Source:
|
76
|
+
```ruby
|
77
|
+
# -*- encoding: binary -*-
|
78
|
+
|
79
|
+
"\x98\x76\xAB\xCD\x45\x32\xEF\x01\x01\x23\x45\x67\x89\xAB\xCD\xEF"
|
80
|
+
```
|
81
|
+
|
82
|
+
Original-AST:
|
83
|
+
```
|
84
|
+
(str "\x98v\xAB\xCDE2\xEF\x01\x01#Eg\x89\xAB\xCD\xEF")
|
85
|
+
```
|
86
|
+
|
87
|
+
Generated-Source:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
"\x98v\xAB\xCDE2\xEF\x01\x01#Eg\x89\xAB\xCD\xEF"
|
91
|
+
```
|
92
|
+
|
93
|
+
Generated-AST:
|
94
|
+
|
95
|
+
```
|
96
|
+
(str "\x98v\xAB\xCDE2\xEF\u0001\u0001#Eg\x89\xAB\xCD\xEF")
|
97
|
+
```
|
98
|
+
|
99
|
+
Diff:
|
100
|
+
|
101
|
+
```
|
102
|
+
@@ -1,2 +1,2 @@
|
103
|
+
-(str "\x98v\xAB\xCDE2\xEF\x01\x01#Eg\x89\xAB\xCD\xEF")
|
104
|
+
+(str "\x98v\xAB\xCDE2\xEF\u0001\u0001#Eg\x89\xAB\xCD\xEF")
|
105
|
+
```
|
106
|
+
|
53
107
|
Installation
|
54
108
|
------------
|
55
109
|
|
data/circle.yml
CHANGED
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -17,6 +17,8 @@ TooManyInstanceVariables:
|
|
17
17
|
TooManyMethods:
|
18
18
|
exclude:
|
19
19
|
- Unparser::Emitter # TODO: 13 methods, mostly helpers for deduplicate sublcasses
|
20
|
+
- Unparser::Buffer # TODO: 11 methods, mostly helpers for deduplicate sublcasses
|
21
|
+
- Unparser::CLI::Source # 11 methods
|
20
22
|
enabled: true
|
21
23
|
max_methods: 10
|
22
24
|
UncommunicativeMethodName:
|
@@ -41,7 +43,8 @@ FeatureEnvy:
|
|
41
43
|
- Unparser::CLI::Differ#collapsed_hunks
|
42
44
|
- Unparser::Emitter::Send::Arguments#effective_arguments
|
43
45
|
# Helper methods, false positive
|
44
|
-
- Unparser::
|
46
|
+
- Unparser::CLI::Source#strip
|
47
|
+
- Unparser::CLI::Source#report_unparser
|
45
48
|
- Unparser::CLI#sources
|
46
49
|
enabled: true
|
47
50
|
ClassVariable:
|
@@ -73,7 +76,9 @@ TooManyStatements:
|
|
73
76
|
max_statements: 6
|
74
77
|
enabled: true
|
75
78
|
exclude:
|
76
|
-
- Unparser::CLI
|
79
|
+
- Unparser::CLI#add_options
|
80
|
+
- Unparser::CLI#initialize
|
81
|
+
- Unparser::CLI::Source#report_unparser
|
77
82
|
DuplicateMethodCall:
|
78
83
|
allow_calls: []
|
79
84
|
exclude: []
|
@@ -83,7 +88,7 @@ UtilityFunction:
|
|
83
88
|
max_helper_calls: 1
|
84
89
|
exclude:
|
85
90
|
# Intent to be helper methods
|
86
|
-
- Unparser::
|
91
|
+
- Unparser::CLI::Source#strip
|
87
92
|
- Unparser::CLI#sources
|
88
93
|
enabled: true
|
89
94
|
Attribute:
|
data/config/rubocop.yml
CHANGED
data/lib/unparser.rb
CHANGED
data/lib/unparser/ast.rb
CHANGED
@@ -87,7 +87,7 @@ module Unparser
|
|
87
87
|
def self.local_variable_assignments_in_scope(node)
|
88
88
|
Enumerator.new(
|
89
89
|
node,
|
90
|
-
LocalVariableScope.method(:not_reset_scope?)
|
90
|
+
LocalVariableScope.method(:not_reset_scope?)
|
91
91
|
).types(LocalVariableScope::ASSIGN_NODES)
|
92
92
|
end
|
93
93
|
|
@@ -102,7 +102,7 @@ module Unparser
|
|
102
102
|
def self.local_variables_read_in_scope(node)
|
103
103
|
Enumerator.new(
|
104
104
|
node,
|
105
|
-
LocalVariableScope.method(:not_close_scope?)
|
105
|
+
LocalVariableScope.method(:not_close_scope?)
|
106
106
|
).type(:lvar).map(&FIRST_CHILD).to_set
|
107
107
|
end
|
108
108
|
|
data/lib/unparser/buffer.rb
CHANGED
@@ -30,7 +30,7 @@ module Unparser
|
|
30
30
|
if @content[-1] == NL
|
31
31
|
prefix
|
32
32
|
end
|
33
|
-
|
33
|
+
write(string)
|
34
34
|
self
|
35
35
|
end
|
36
36
|
|
@@ -43,7 +43,7 @@ module Unparser
|
|
43
43
|
# @api private
|
44
44
|
#
|
45
45
|
def append_without_prefix(string)
|
46
|
-
|
46
|
+
write(string)
|
47
47
|
self
|
48
48
|
end
|
49
49
|
|
@@ -76,7 +76,7 @@ module Unparser
|
|
76
76
|
# @api private
|
77
77
|
#
|
78
78
|
def nl
|
79
|
-
|
79
|
+
write(NL)
|
80
80
|
self
|
81
81
|
end
|
82
82
|
|
@@ -127,7 +127,15 @@ module Unparser
|
|
127
127
|
# @api private
|
128
128
|
#
|
129
129
|
def prefix
|
130
|
-
|
130
|
+
write(INDENT_SPACE * @indent)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Write to content buffer
|
134
|
+
#
|
135
|
+
# @param [String] fragment
|
136
|
+
#
|
137
|
+
def write(fragment)
|
138
|
+
@content << fragment
|
131
139
|
end
|
132
140
|
|
133
141
|
end # Buffer
|
data/lib/unparser/cli.rb
CHANGED
@@ -42,6 +42,7 @@ module Unparser
|
|
42
42
|
|
43
43
|
@success = true
|
44
44
|
@fail_fast = false
|
45
|
+
@verbose = false
|
45
46
|
|
46
47
|
opts = OptionParser.new do |builder|
|
47
48
|
add_options(builder)
|
@@ -63,12 +64,15 @@ module Unparser
|
|
63
64
|
def add_options(builder)
|
64
65
|
builder.banner = 'usage: unparse [options] FILE [FILE]'
|
65
66
|
builder.separator('')
|
66
|
-
builder.on('-e', '--evaluate SOURCE') do |
|
67
|
-
@sources << Source::String.new(
|
67
|
+
builder.on('-e', '--evaluate SOURCE') do |source|
|
68
|
+
@sources << Source::String.new(source)
|
68
69
|
end
|
69
70
|
builder.on('--start-with FILE') do |file|
|
70
71
|
@start_with = sources(file).first
|
71
72
|
end
|
73
|
+
builder.on('-v', '--verbose') do |file|
|
74
|
+
@verbose = true
|
75
|
+
end
|
72
76
|
builder.on('--ignore FILE') do |file|
|
73
77
|
@ignore.merge(sources(file))
|
74
78
|
end
|
@@ -107,9 +111,10 @@ module Unparser
|
|
107
111
|
#
|
108
112
|
def process_source(source)
|
109
113
|
if source.success?
|
114
|
+
puts source.report if @verbose
|
110
115
|
puts "Success: #{source.identification}"
|
111
116
|
else
|
112
|
-
puts source.
|
117
|
+
puts source.report
|
113
118
|
puts "Error: #{source.identification}"
|
114
119
|
@success = false
|
115
120
|
end
|
data/lib/unparser/cli/source.rb
CHANGED
@@ -6,6 +6,34 @@ module Unparser
|
|
6
6
|
class Source
|
7
7
|
include AbstractType, Adamantium::Flat, NodeHelpers
|
8
8
|
|
9
|
+
# Source state generated after first unparse
|
10
|
+
class Generated
|
11
|
+
include Concord::Public.new(:source, :ast, :error)
|
12
|
+
|
13
|
+
# Test if source was generated successfully
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def success?
|
20
|
+
!error
|
21
|
+
end
|
22
|
+
|
23
|
+
# Build generateg source
|
24
|
+
#
|
25
|
+
# @param [Parser::AST::Node]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
def self.build(ast)
|
30
|
+
source = Unparser.unparse(ast)
|
31
|
+
new(source, ast, nil)
|
32
|
+
rescue => exception
|
33
|
+
new(nil, ast, exception)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
9
37
|
# Test if source could be unparsed successfully
|
10
38
|
#
|
11
39
|
# @return [true]
|
@@ -16,7 +44,7 @@ module Unparser
|
|
16
44
|
# @api private
|
17
45
|
#
|
18
46
|
def success?
|
19
|
-
original_ast && generated_ast && original_ast == generated_ast
|
47
|
+
generated.success? && original_ast && generated_ast && original_ast == generated_ast
|
20
48
|
end
|
21
49
|
|
22
50
|
# Return error report
|
@@ -25,17 +53,21 @@ module Unparser
|
|
25
53
|
#
|
26
54
|
# @api private
|
27
55
|
#
|
28
|
-
def
|
56
|
+
def report
|
29
57
|
case
|
30
58
|
when original_ast && generated_ast
|
31
|
-
|
59
|
+
report_with_ast_diff
|
32
60
|
when !original_ast
|
33
|
-
|
61
|
+
report_original
|
62
|
+
when !generated.success?
|
63
|
+
report_unparser
|
34
64
|
when !generated_ast
|
35
|
-
|
65
|
+
report_generated
|
66
|
+
else
|
67
|
+
raise
|
36
68
|
end
|
37
69
|
end
|
38
|
-
memoize :
|
70
|
+
memoize :report
|
39
71
|
|
40
72
|
private
|
41
73
|
|
@@ -45,10 +77,24 @@ module Unparser
|
|
45
77
|
#
|
46
78
|
# @api private
|
47
79
|
#
|
48
|
-
def
|
49
|
-
|
80
|
+
def generated
|
81
|
+
Source::Generated.build(original_ast)
|
82
|
+
end
|
83
|
+
memoize :generated
|
84
|
+
|
85
|
+
# Return stripped source
|
86
|
+
#
|
87
|
+
# @param [String] string
|
88
|
+
#
|
89
|
+
# @return [String]
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
#
|
93
|
+
def strip(source)
|
94
|
+
source = source.rstrip
|
95
|
+
indent = source.scan(/^\s*/).first
|
96
|
+
source.gsub(/^#{indent}/, '')
|
50
97
|
end
|
51
|
-
memoize :generated_source
|
52
98
|
|
53
99
|
# Return error report for parsing original
|
54
100
|
#
|
@@ -56,26 +102,42 @@ module Unparser
|
|
56
102
|
#
|
57
103
|
# @api private
|
58
104
|
#
|
59
|
-
def
|
105
|
+
def report_original
|
60
106
|
strip(<<-MESSAGE)
|
61
107
|
Parsing of original source failed:
|
62
108
|
#{original_source}
|
63
109
|
MESSAGE
|
64
110
|
end
|
65
111
|
|
112
|
+
# Report unparser bug
|
113
|
+
#
|
114
|
+
# @return [String]
|
115
|
+
#
|
116
|
+
# @api private
|
117
|
+
#
|
118
|
+
def report_unparser
|
119
|
+
message = ['Unparsing parsed AST failed']
|
120
|
+
error = generated.error
|
121
|
+
message << error
|
122
|
+
error.backtrace.take(20).each(&message.method(:<<))
|
123
|
+
message << 'Original-AST:'
|
124
|
+
message << original_ast.inspect
|
125
|
+
message.join("\n")
|
126
|
+
end
|
127
|
+
|
66
128
|
# Return error report for parsing generated
|
67
129
|
#
|
68
130
|
# @return [String]
|
69
131
|
#
|
70
132
|
# @api private
|
71
133
|
#
|
72
|
-
def
|
134
|
+
def report_generated
|
73
135
|
strip(<<-MESSAGE)
|
74
136
|
Parsing of generated source failed:
|
75
137
|
Original-AST:
|
76
138
|
#{original_ast.inspect}
|
77
139
|
Source:
|
78
|
-
#{
|
140
|
+
#{generated.source}
|
79
141
|
MESSAGE
|
80
142
|
end
|
81
143
|
|
@@ -85,12 +147,12 @@ module Unparser
|
|
85
147
|
#
|
86
148
|
# @api private
|
87
149
|
#
|
88
|
-
def
|
150
|
+
def report_with_ast_diff
|
89
151
|
strip(<<-MESSAGE)
|
90
|
-
#{
|
152
|
+
#{ast_diff}
|
91
153
|
Original-Source:\n#{original_source}
|
92
154
|
Original-AST:\n#{original_ast.inspect}
|
93
|
-
Generated-Source:\n#{
|
155
|
+
Generated-Source:\n#{generated.source}
|
94
156
|
Generated-AST:\n#{generated_ast.inspect}
|
95
157
|
MESSAGE
|
96
158
|
end
|
@@ -119,7 +181,7 @@ module Unparser
|
|
119
181
|
# @api private
|
120
182
|
#
|
121
183
|
def generated_ast
|
122
|
-
Preprocessor.run(parse(
|
184
|
+
generated.success? && Preprocessor.run(parse(generated.source))
|
123
185
|
rescue Parser::SyntaxError
|
124
186
|
nil
|
125
187
|
end
|
data/lib/unparser/constants.rb
CHANGED
@@ -106,7 +106,7 @@ module Unparser
|
|
106
106
|
int float self kwbegin const regexp args lvar
|
107
107
|
ivar gvar cvar if case module class sclass super
|
108
108
|
yield zsuper break next defined? str block while loop until
|
109
|
-
def defs true false nil array hash sym return
|
109
|
+
def defs true false nil array hash sym return match_current_line
|
110
110
|
)
|
111
111
|
|
112
112
|
DEFAULT_DELIMITER = ', '.freeze
|
@@ -45,16 +45,6 @@ module Unparser
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
# Emit inner delimited by semicolons
|
49
|
-
#
|
50
|
-
# @return [undefined]
|
51
|
-
#
|
52
|
-
# @api private
|
53
|
-
#
|
54
|
-
def emit_inner_semi
|
55
|
-
delimited(children, ';')
|
56
|
-
end
|
57
|
-
|
58
48
|
end # Implicit
|
59
49
|
|
60
50
|
# Emitter for explicit begins
|
data/lib/unparser/emitter/if.rb
CHANGED
@@ -28,7 +28,7 @@ module Unparser
|
|
28
28
|
# Test for postcondition
|
29
29
|
#
|
30
30
|
# @return [true]
|
31
|
-
# if node must be emitted in
|
31
|
+
# if node must be emitted in postcondition style
|
32
32
|
#
|
33
33
|
# @return [false]
|
34
34
|
# otherwise
|
@@ -36,7 +36,7 @@ module Unparser
|
|
36
36
|
# @api private
|
37
37
|
#
|
38
38
|
def postcondition?
|
39
|
-
return false unless
|
39
|
+
return false unless if_branch.nil? ^ else_branch.nil?
|
40
40
|
|
41
41
|
body = if_branch || else_branch
|
42
42
|
|
@@ -100,7 +100,7 @@ module Unparser
|
|
100
100
|
# @api private
|
101
101
|
#
|
102
102
|
def emit_condition
|
103
|
-
|
103
|
+
visit_terminated(condition)
|
104
104
|
end
|
105
105
|
|
106
106
|
# Emit if branch
|
@@ -14,10 +14,13 @@ module Unparser
|
|
14
14
|
#
|
15
15
|
def dispatch
|
16
16
|
emit_receiver
|
17
|
-
|
17
|
+
emit_attribute
|
18
|
+
emit_operator
|
18
19
|
visit_terminated(arguments.first)
|
19
20
|
end
|
20
21
|
|
22
|
+
private
|
23
|
+
|
21
24
|
# Emit receiver
|
22
25
|
#
|
23
26
|
# @return [Parser::AST::Node]
|
@@ -29,6 +32,36 @@ module Unparser
|
|
29
32
|
write(T_DOT)
|
30
33
|
end
|
31
34
|
|
35
|
+
# Emit attribute
|
36
|
+
#
|
37
|
+
# @return [undefined]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def emit_attribute
|
42
|
+
write(attribute_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Emit assignment operator
|
46
|
+
#
|
47
|
+
# @return [undefined]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
#
|
51
|
+
def emit_operator
|
52
|
+
write(WS, T_ASN, WS)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return attribute name
|
56
|
+
#
|
57
|
+
# @return [String]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
#
|
61
|
+
def attribute_name
|
62
|
+
string_selector[0..-2]
|
63
|
+
end
|
64
|
+
|
32
65
|
end # AttributeAssignment
|
33
66
|
end # Send
|
34
67
|
end # Emitter
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'Unparser on ruby corpus' do
|
6
|
+
before do
|
7
|
+
if RUBY_VERSION == '1.9.3'
|
8
|
+
pending 'Corpus test not active for 1.9.3 because of limitations in encoding singalling, see Readme'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
ROOT = Pathname.new(__FILE__).parent.parent.parent.parent
|
12
|
+
|
13
|
+
TMP = ROOT.join('tmp')
|
14
|
+
|
15
|
+
class Project
|
16
|
+
include Anima.new(:name, :repo_uri, :exclude)
|
17
|
+
|
18
|
+
# Perform verification via unparser cli
|
19
|
+
#
|
20
|
+
# @return [self]
|
21
|
+
# if successful
|
22
|
+
#
|
23
|
+
# @raise [Exception]
|
24
|
+
# otherwise
|
25
|
+
#
|
26
|
+
def verify
|
27
|
+
checkout
|
28
|
+
command = %W(unparser #{repo_path})
|
29
|
+
exclude.each do |name|
|
30
|
+
command.concat(%W(--ignore #{repo_path.join(name)}))
|
31
|
+
end
|
32
|
+
system(command) do
|
33
|
+
raise "Verifing #{name} failed!"
|
34
|
+
end
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
# Checkout repository
|
39
|
+
#
|
40
|
+
# @return [self]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def checkout
|
45
|
+
TMP.mkdir unless TMP.directory?
|
46
|
+
if repo_path.exist?
|
47
|
+
Dir.chdir(repo_path) do
|
48
|
+
system(%w(git pull origin master))
|
49
|
+
system(%w(git clean -f -d -x))
|
50
|
+
end
|
51
|
+
else
|
52
|
+
system(%W(git clone #{repo_uri} #{repo_path}))
|
53
|
+
end
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Return repository path
|
60
|
+
#
|
61
|
+
# @return [Pathname]
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
#
|
65
|
+
def repo_path
|
66
|
+
TMP.join(name)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Helper method to execute system commands
|
70
|
+
#
|
71
|
+
# @param [Array<String>] arguments
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
#
|
75
|
+
def system(arguments)
|
76
|
+
unless Kernel.system(*arguments)
|
77
|
+
if block_given?
|
78
|
+
yield
|
79
|
+
else
|
80
|
+
raise 'System command failed!'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
LOADER = Morpher.build do
|
86
|
+
s(:block,
|
87
|
+
s(:guard, s(:primitive, Array)),
|
88
|
+
s(:map,
|
89
|
+
s(:block,
|
90
|
+
s(:guard, s(:primitive, Hash)),
|
91
|
+
s(:hash_transform,
|
92
|
+
s(:key_symbolize, :repo_uri, s(:guard, s(:primitive, String))),
|
93
|
+
s(:key_symbolize, :name, s(:guard, s(:primitive, String))),
|
94
|
+
s(:key_symbolize, :exclude, s(:map, s(:guard, s(:primitive, String))))
|
95
|
+
),
|
96
|
+
s(:load_attribute_hash,
|
97
|
+
# NOTE: The domain param has no DSL currently!
|
98
|
+
Morpher::Evaluator::Transformer::Domain::Param.new(
|
99
|
+
Project,
|
100
|
+
[:repo_uri, :name, :exclude]
|
101
|
+
)
|
102
|
+
)
|
103
|
+
)
|
104
|
+
)
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
ALL = LOADER.call(YAML.load_file(ROOT.join('spec', 'integrations.yml')))
|
109
|
+
end
|
110
|
+
|
111
|
+
Project::ALL.each do |project|
|
112
|
+
specify "unparsing #{project.name}" do
|
113
|
+
project.verify
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
- name: rubyspec
|
3
|
+
repo_uri: 'https://github.com/rubyspec/rubyspec.git'
|
4
|
+
exclude:
|
5
|
+
# Binary encoded source subjected to limitations see Readme
|
6
|
+
- core/array/pack/{b,h,u}_spec.rb
|
7
|
+
- language/versions/*1.8*
|
8
|
+
- core/array/pack/shared/float.rb
|
9
|
+
- core/array/pack/shared/integer.rb
|
10
|
+
- core/array/pack/{c,m,w}_spec.rb
|
11
|
+
- core/regexp/shared/new.rb
|
12
|
+
- core/regexp/shared/quote.rb
|
13
|
+
- core/encoding/compatible_spec.rb
|
14
|
+
- core/io/readpartial_spec.rb
|
15
|
+
- core/env/element_reference_spec.rb
|
16
|
+
- core/dir/pwd_spec.rb
|
17
|
+
- core/string/casecmp_spec.rb
|
18
|
+
- core/string/unpack/{b,c,h,m,u,w}_spec.rb
|
19
|
+
- core/string/unpack/b_spec.rb
|
20
|
+
- core/string/unpack/shared/float.rb
|
21
|
+
- core/string/unpack/shared/integer.rb
|
22
|
+
- core/symbol/casecmp_spec.rb
|
23
|
+
- optional/capi/integer_spec.rb
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
# encoding:
|
1
|
+
# encoding: UTF-8
|
2
2
|
|
3
|
+
require 'yaml'
|
4
|
+
require 'pathname'
|
3
5
|
require 'unparser'
|
6
|
+
require 'anima'
|
7
|
+
require 'morpher'
|
4
8
|
require 'devtools/spec_helper'
|
5
9
|
|
6
10
|
require 'parser/current'
|
@@ -20,8 +24,6 @@ module SpecHelper
|
|
20
24
|
end
|
21
25
|
|
22
26
|
RSpec.configure do |config|
|
23
|
-
config.extend(Unparser::StripHelper)
|
24
|
-
config.include(Unparser::StripHelper)
|
25
27
|
config.include(SpecHelper)
|
26
28
|
config.extend(SpecHelper)
|
27
29
|
end
|
data/spec/unit/unparser_spec.rb
CHANGED
@@ -503,9 +503,9 @@ describe Unparser do
|
|
503
503
|
assert_source '(array[i] = 1).foo'
|
504
504
|
assert_source 'array[1..2].foo'
|
505
505
|
assert_source '(a.attribute ||= foo).bar'
|
506
|
-
assert_source 'foo.bar=baz[1]'
|
507
|
-
assert_source 'foo.bar=(baz || foo)'
|
508
|
-
assert_source 'foo.bar=baz.bar'
|
506
|
+
assert_source 'foo.bar = baz[1]'
|
507
|
+
assert_source 'foo.bar = (baz || foo)'
|
508
|
+
assert_source 'foo.bar = baz.bar'
|
509
509
|
assert_source 'foo << (bar * baz)'
|
510
510
|
assert_source <<-'RUBY'
|
511
511
|
foo ||= (a, _ = b)
|
@@ -596,8 +596,8 @@ describe Unparser do
|
|
596
596
|
|
597
597
|
assert_source 'foo.bar(&baz)'
|
598
598
|
assert_source 'foo.bar(:baz, &baz)'
|
599
|
-
assert_source 'foo.bar
|
600
|
-
assert_source 'self.foo
|
599
|
+
assert_source 'foo.bar = :baz'
|
600
|
+
assert_source 'self.foo = :bar'
|
601
601
|
|
602
602
|
assert_source 'foo.bar(baz: boz)'
|
603
603
|
assert_source 'foo.bar(foo, "baz" => boz)'
|
@@ -722,6 +722,12 @@ describe Unparser do
|
|
722
722
|
end
|
723
723
|
RUBY
|
724
724
|
|
725
|
+
assert_source <<-'RUBY'
|
726
|
+
begin
|
727
|
+
ensure
|
728
|
+
end
|
729
|
+
RUBY
|
730
|
+
|
725
731
|
assert_source <<-'RUBY'
|
726
732
|
begin
|
727
733
|
rescue
|
@@ -788,6 +794,35 @@ describe Unparser do
|
|
788
794
|
assert_source 'foo rescue(bar)'
|
789
795
|
assert_source 'foo rescue(return bar)'
|
790
796
|
assert_source 'x = foo rescue(return bar)'
|
797
|
+
|
798
|
+
%w(while until if).each do |keyword|
|
799
|
+
assert_source <<-RUBY
|
800
|
+
#{keyword} (
|
801
|
+
foo rescue(false)
|
802
|
+
)
|
803
|
+
end
|
804
|
+
RUBY
|
805
|
+
|
806
|
+
assert_generates <<-RUBY, <<-GENERATED
|
807
|
+
foo rescue(false) #{keyword} true
|
808
|
+
RUBY
|
809
|
+
#{keyword} true
|
810
|
+
foo rescue(false)
|
811
|
+
end
|
812
|
+
GENERATED
|
813
|
+
end
|
814
|
+
|
815
|
+
assert_generates <<-'RUBY', <<-GENERATED
|
816
|
+
case (foo rescue(false))
|
817
|
+
when true
|
818
|
+
end
|
819
|
+
RUBY
|
820
|
+
case (
|
821
|
+
foo rescue(false)
|
822
|
+
)
|
823
|
+
when true
|
824
|
+
end
|
825
|
+
GENERATED
|
791
826
|
end
|
792
827
|
|
793
828
|
context 'super' do
|
@@ -1357,7 +1392,7 @@ describe Unparser do
|
|
1357
1392
|
context 'flip flops' do
|
1358
1393
|
context 'inclusive' do
|
1359
1394
|
assert_source <<-'RUBY'
|
1360
|
-
if (i == 4)..(i == 4)
|
1395
|
+
if ((i == 4)..(i == 4))
|
1361
1396
|
foo
|
1362
1397
|
end
|
1363
1398
|
RUBY
|
@@ -1365,7 +1400,7 @@ describe Unparser do
|
|
1365
1400
|
|
1366
1401
|
context 'exclusive' do
|
1367
1402
|
assert_source <<-'RUBY'
|
1368
|
-
if (i == 4)...(i == 4)
|
1403
|
+
if ((i == 4)...(i == 4))
|
1369
1404
|
foo
|
1370
1405
|
end
|
1371
1406
|
RUBY
|
data/unparser.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = 'unparser'
|
5
|
-
gem.version = '0.1.
|
5
|
+
gem.version = '0.1.10'
|
6
6
|
|
7
7
|
gem.authors = ['Markus Schirp']
|
8
8
|
gem.email = 'mbj@schir-dso.com'
|
@@ -19,10 +19,10 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.required_ruby_version
|
21
21
|
|
22
|
-
gem.add_dependency('parser', '~> 2.1.
|
22
|
+
gem.add_dependency('parser', '~> 2.1.7')
|
23
23
|
gem.add_dependency('procto', '~> 0.0.2')
|
24
24
|
gem.add_dependency('concord', '~> 0.1.4')
|
25
|
-
gem.add_dependency('adamantium', '~> 0.
|
26
|
-
gem.add_dependency('equalizer', '~> 0.0.
|
25
|
+
gem.add_dependency('adamantium', '~> 0.2.0')
|
26
|
+
gem.add_dependency('equalizer', '~> 0.0.9')
|
27
27
|
gem.add_dependency('abstract_type', '~> 0.0.7')
|
28
28
|
end
|
metadata
CHANGED
@@ -1,99 +1,99 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unparser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.7
|
15
20
|
requirement: !ruby/object:Gem::Requirement
|
16
21
|
requirements:
|
17
|
-
- -
|
22
|
+
- - ~>
|
18
23
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.1.
|
20
|
-
type: :runtime
|
24
|
+
version: 2.1.7
|
21
25
|
prerelease: false
|
26
|
+
type: :runtime
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: procto
|
22
29
|
version_requirements: !ruby/object:Gem::Requirement
|
23
30
|
requirements:
|
24
|
-
- -
|
31
|
+
- - ~>
|
25
32
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: procto
|
33
|
+
version: 0.0.2
|
29
34
|
requirement: !ruby/object:Gem::Requirement
|
30
35
|
requirements:
|
31
|
-
- -
|
36
|
+
- - ~>
|
32
37
|
- !ruby/object:Gem::Version
|
33
38
|
version: 0.0.2
|
34
|
-
type: :runtime
|
35
39
|
prerelease: false
|
40
|
+
type: :runtime
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: concord
|
36
43
|
version_requirements: !ruby/object:Gem::Requirement
|
37
44
|
requirements:
|
38
|
-
- -
|
45
|
+
- - ~>
|
39
46
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: concord
|
47
|
+
version: 0.1.4
|
43
48
|
requirement: !ruby/object:Gem::Requirement
|
44
49
|
requirements:
|
45
|
-
- -
|
50
|
+
- - ~>
|
46
51
|
- !ruby/object:Gem::Version
|
47
52
|
version: 0.1.4
|
48
|
-
type: :runtime
|
49
53
|
prerelease: false
|
54
|
+
type: :runtime
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: adamantium
|
50
57
|
version_requirements: !ruby/object:Gem::Requirement
|
51
58
|
requirements:
|
52
|
-
- -
|
59
|
+
- - ~>
|
53
60
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: adamantium
|
61
|
+
version: 0.2.0
|
57
62
|
requirement: !ruby/object:Gem::Requirement
|
58
63
|
requirements:
|
59
|
-
- -
|
64
|
+
- - ~>
|
60
65
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
type: :runtime
|
66
|
+
version: 0.2.0
|
63
67
|
prerelease: false
|
68
|
+
type: :runtime
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: equalizer
|
64
71
|
version_requirements: !ruby/object:Gem::Requirement
|
65
72
|
requirements:
|
66
|
-
- -
|
73
|
+
- - ~>
|
67
74
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: equalizer
|
75
|
+
version: 0.0.9
|
71
76
|
requirement: !ruby/object:Gem::Requirement
|
72
77
|
requirements:
|
73
|
-
- -
|
78
|
+
- - ~>
|
74
79
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.0.
|
76
|
-
type: :runtime
|
80
|
+
version: 0.0.9
|
77
81
|
prerelease: false
|
82
|
+
type: :runtime
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: abstract_type
|
78
85
|
version_requirements: !ruby/object:Gem::Requirement
|
79
86
|
requirements:
|
80
|
-
- -
|
87
|
+
- - ~>
|
81
88
|
- !ruby/object:Gem::Version
|
82
89
|
version: 0.0.7
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: abstract_type
|
85
90
|
requirement: !ruby/object:Gem::Requirement
|
86
91
|
requirements:
|
87
|
-
- -
|
92
|
+
- - ~>
|
88
93
|
- !ruby/object:Gem::Version
|
89
94
|
version: 0.0.7
|
90
|
-
type: :runtime
|
91
95
|
prerelease: false
|
92
|
-
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.0.7
|
96
|
+
type: :runtime
|
97
97
|
description: Generate equivalent source for parser gem AST nodes
|
98
98
|
email: mbj@schir-dso.com
|
99
99
|
executables:
|
@@ -102,10 +102,10 @@ extensions: []
|
|
102
102
|
extra_rdoc_files:
|
103
103
|
- README.md
|
104
104
|
files:
|
105
|
-
-
|
106
|
-
-
|
107
|
-
-
|
108
|
-
-
|
105
|
+
- .gitignore
|
106
|
+
- .rspec
|
107
|
+
- .rubocop.yml
|
108
|
+
- .travis.yml
|
109
109
|
- Changelog.md
|
110
110
|
- Gemfile
|
111
111
|
- Gemfile.devtools
|
@@ -186,8 +186,9 @@ files:
|
|
186
186
|
- lib/unparser/finalize.rb
|
187
187
|
- lib/unparser/node_helpers.rb
|
188
188
|
- lib/unparser/preprocessor.rb
|
189
|
-
- lib/unparser/strip_helper.rb
|
190
189
|
- rubyspec.sh
|
190
|
+
- spec/integration/unparser/corpus_spec.rb
|
191
|
+
- spec/integrations.yml
|
191
192
|
- spec/spec_helper.rb
|
192
193
|
- spec/unit/unparser/buffer/append_spec.rb
|
193
194
|
- spec/unit/unparser/buffer/append_without_prefix_spec.rb
|
@@ -208,27 +209,29 @@ homepage: http://github.com/mbj/unparser
|
|
208
209
|
licenses:
|
209
210
|
- MIT
|
210
211
|
metadata: {}
|
211
|
-
post_install_message:
|
212
|
+
post_install_message:
|
212
213
|
rdoc_options: []
|
213
214
|
require_paths:
|
214
215
|
- lib
|
215
216
|
required_ruby_version: !ruby/object:Gem::Requirement
|
216
217
|
requirements:
|
217
|
-
- -
|
218
|
+
- - '>='
|
218
219
|
- !ruby/object:Gem::Version
|
219
220
|
version: '0'
|
220
221
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
222
|
requirements:
|
222
|
-
- -
|
223
|
+
- - '>='
|
223
224
|
- !ruby/object:Gem::Version
|
224
225
|
version: '0'
|
225
226
|
requirements: []
|
226
|
-
rubyforge_project:
|
227
|
-
rubygems_version: 2.
|
228
|
-
signing_key:
|
227
|
+
rubyforge_project:
|
228
|
+
rubygems_version: 2.1.9
|
229
|
+
signing_key:
|
229
230
|
specification_version: 4
|
230
231
|
summary: Generate equivalent source for parser gem AST nodes
|
231
232
|
test_files:
|
233
|
+
- spec/integration/unparser/corpus_spec.rb
|
234
|
+
- spec/integrations.yml
|
232
235
|
- spec/spec_helper.rb
|
233
236
|
- spec/unit/unparser/buffer/append_spec.rb
|
234
237
|
- spec/unit/unparser/buffer/append_without_prefix_spec.rb
|
@@ -244,4 +247,3 @@ test_files:
|
|
244
247
|
- spec/unit/unparser/comments/take_eol_comments_spec.rb
|
245
248
|
- spec/unit/unparser/emitter/class_methods/handle_spec.rb
|
246
249
|
- spec/unit/unparser_spec.rb
|
247
|
-
has_rdoc:
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
module Unparser
|
4
|
-
# Helpers for stripping source
|
5
|
-
module StripHelper
|
6
|
-
|
7
|
-
INDENT_PATTERN = /^\s*/.freeze
|
8
|
-
|
9
|
-
# String indentation of source away
|
10
|
-
#
|
11
|
-
# @param [String] source
|
12
|
-
#
|
13
|
-
# @return [String]
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
#
|
17
|
-
def strip(source)
|
18
|
-
indent = source.rstrip.scan(INDENT_PATTERN).min_by(&:length)
|
19
|
-
source.gsub(/^#{indent}/, '')
|
20
|
-
end
|
21
|
-
|
22
|
-
end # StripHelper
|
23
|
-
end # Unparser
|