unparser 0.4.7 → 0.5.2

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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/bin/unparser +1 -1
  4. data/lib/unparser.rb +134 -62
  5. data/lib/unparser/ast.rb +0 -1
  6. data/lib/unparser/ast/local_variable_scope.rb +6 -76
  7. data/lib/unparser/buffer.rb +19 -16
  8. data/lib/unparser/cli.rb +84 -77
  9. data/lib/unparser/{cli/color.rb → color.rb} +0 -13
  10. data/lib/unparser/comments.rb +0 -26
  11. data/lib/unparser/constants.rb +4 -53
  12. data/lib/unparser/diff.rb +98 -0
  13. data/lib/unparser/dsl.rb +0 -32
  14. data/lib/unparser/emitter.rb +24 -425
  15. data/lib/unparser/emitter/alias.rb +2 -8
  16. data/lib/unparser/emitter/args.rb +45 -0
  17. data/lib/unparser/emitter/argument.rb +8 -166
  18. data/lib/unparser/emitter/array.rb +27 -0
  19. data/lib/unparser/emitter/array_pattern.rb +29 -0
  20. data/lib/unparser/emitter/assignment.rb +36 -127
  21. data/lib/unparser/emitter/begin.rb +9 -84
  22. data/lib/unparser/emitter/binary.rb +7 -20
  23. data/lib/unparser/emitter/block.rb +57 -41
  24. data/lib/unparser/emitter/case.rb +6 -48
  25. data/lib/unparser/emitter/case_guard.rb +27 -0
  26. data/lib/unparser/emitter/case_match.rb +40 -0
  27. data/lib/unparser/emitter/cbase.rb +1 -3
  28. data/lib/unparser/emitter/class.rb +6 -26
  29. data/lib/unparser/emitter/const_pattern.rb +24 -0
  30. data/lib/unparser/emitter/def.rb +7 -51
  31. data/lib/unparser/emitter/defined.rb +2 -12
  32. data/lib/unparser/emitter/dstr.rb +22 -0
  33. data/lib/unparser/emitter/dsym.rb +41 -0
  34. data/lib/unparser/emitter/flipflop.rb +11 -10
  35. data/lib/unparser/emitter/float.rb +29 -0
  36. data/lib/unparser/emitter/flow_modifier.rb +8 -55
  37. data/lib/unparser/emitter/for.rb +5 -19
  38. data/lib/unparser/emitter/hash.rb +74 -0
  39. data/lib/unparser/emitter/hash_pattern.rb +67 -0
  40. data/lib/unparser/emitter/hookexe.rb +5 -11
  41. data/lib/unparser/emitter/if.rb +9 -73
  42. data/lib/unparser/emitter/in_match.rb +21 -0
  43. data/lib/unparser/emitter/in_pattern.rb +34 -0
  44. data/lib/unparser/emitter/index.rb +21 -88
  45. data/lib/unparser/emitter/kwbegin.rb +31 -0
  46. data/lib/unparser/emitter/lambda.rb +0 -8
  47. data/lib/unparser/emitter/masgn.rb +20 -0
  48. data/lib/unparser/emitter/match.rb +3 -17
  49. data/lib/unparser/emitter/match_alt.rb +23 -0
  50. data/lib/unparser/emitter/match_as.rb +21 -0
  51. data/lib/unparser/emitter/match_rest.rb +26 -0
  52. data/lib/unparser/emitter/match_var.rb +19 -0
  53. data/lib/unparser/emitter/mlhs.rb +40 -0
  54. data/lib/unparser/emitter/module.rb +3 -9
  55. data/lib/unparser/emitter/op_assign.rb +12 -27
  56. data/lib/unparser/emitter/pin.rb +19 -0
  57. data/lib/unparser/emitter/primitive.rb +93 -0
  58. data/lib/unparser/emitter/range.rb +35 -0
  59. data/lib/unparser/emitter/regexp.rb +35 -0
  60. data/lib/unparser/emitter/repetition.rb +17 -57
  61. data/lib/unparser/emitter/rescue.rb +1 -97
  62. data/lib/unparser/emitter/root.rb +17 -1
  63. data/lib/unparser/emitter/send.rb +10 -219
  64. data/lib/unparser/emitter/simple.rb +33 -0
  65. data/lib/unparser/emitter/splat.rb +2 -18
  66. data/lib/unparser/emitter/super.rb +1 -29
  67. data/lib/unparser/emitter/undef.rb +1 -9
  68. data/lib/unparser/emitter/variable.rb +1 -31
  69. data/lib/unparser/emitter/xstr.rb +72 -0
  70. data/lib/unparser/emitter/yield.rb +1 -9
  71. data/lib/unparser/generation.rb +250 -0
  72. data/lib/unparser/node_details.rb +21 -0
  73. data/lib/unparser/node_details/send.rb +62 -0
  74. data/lib/unparser/node_helpers.rb +45 -6
  75. data/lib/unparser/validation.rb +172 -0
  76. data/lib/unparser/writer.rb +15 -0
  77. data/lib/unparser/writer/binary.rb +99 -0
  78. data/lib/unparser/writer/dynamic_string.rb +233 -0
  79. data/lib/unparser/writer/resbody.rb +40 -0
  80. data/lib/unparser/writer/rescue.rb +39 -0
  81. data/lib/unparser/writer/send.rb +124 -0
  82. data/lib/unparser/{emitter → writer}/send/attribute_assignment.rb +11 -26
  83. data/lib/unparser/writer/send/binary.rb +27 -0
  84. data/lib/unparser/writer/send/conditional.rb +25 -0
  85. data/lib/unparser/writer/send/regular.rb +33 -0
  86. data/lib/unparser/{emitter → writer}/send/unary.rb +10 -17
  87. metadata +127 -104
  88. data/.circleci/config.yml +0 -49
  89. data/.gitignore +0 -37
  90. data/.rspec +0 -4
  91. data/.rubocop.yml +0 -9
  92. data/Changelog.md +0 -156
  93. data/Gemfile +0 -9
  94. data/Gemfile.lock +0 -181
  95. data/LICENSE +0 -20
  96. data/Rakefile +0 -22
  97. data/config/devtools.yml +0 -2
  98. data/config/flay.yml +0 -3
  99. data/config/flog.yml +0 -2
  100. data/config/mutant.yml +0 -6
  101. data/config/reek.yml +0 -98
  102. data/config/rubocop.yml +0 -122
  103. data/config/yardstick.yml +0 -2
  104. data/lib/unparser/cli/differ.rb +0 -152
  105. data/lib/unparser/cli/source.rb +0 -267
  106. data/lib/unparser/emitter/empty.rb +0 -23
  107. data/lib/unparser/emitter/ensure.rb +0 -37
  108. data/lib/unparser/emitter/literal.rb +0 -10
  109. data/lib/unparser/emitter/literal/array.rb +0 -29
  110. data/lib/unparser/emitter/literal/dynamic.rb +0 -53
  111. data/lib/unparser/emitter/literal/dynamic_body.rb +0 -132
  112. data/lib/unparser/emitter/literal/execute_string.rb +0 -38
  113. data/lib/unparser/emitter/literal/hash.rb +0 -156
  114. data/lib/unparser/emitter/literal/primitive.rb +0 -145
  115. data/lib/unparser/emitter/literal/range.rb +0 -36
  116. data/lib/unparser/emitter/literal/regexp.rb +0 -114
  117. data/lib/unparser/emitter/literal/singleton.rb +0 -26
  118. data/lib/unparser/emitter/meta.rb +0 -16
  119. data/lib/unparser/emitter/redo.rb +0 -25
  120. data/lib/unparser/emitter/resbody.rb +0 -76
  121. data/lib/unparser/emitter/retry.rb +0 -25
  122. data/lib/unparser/emitter/send/binary.rb +0 -57
  123. data/lib/unparser/emitter/send/conditional.rb +0 -40
  124. data/lib/unparser/emitter/send/regular.rb +0 -40
  125. data/lib/unparser/preprocessor.rb +0 -159
  126. data/spec/integration/unparser/corpus_spec.rb +0 -111
  127. data/spec/integrations.yml +0 -92
  128. data/spec/spec_helper.rb +0 -20
  129. data/spec/unit/unparser/buffer/append_spec.rb +0 -24
  130. data/spec/unit/unparser/buffer/append_without_prefix_spec.rb +0 -23
  131. data/spec/unit/unparser/buffer/capture_content_spec.rb +0 -17
  132. data/spec/unit/unparser/buffer/content_spec.rb +0 -38
  133. data/spec/unit/unparser/buffer/fresh_line_spec.rb +0 -20
  134. data/spec/unit/unparser/buffer/indent_spec.rb +0 -20
  135. data/spec/unit/unparser/buffer/nl_spec.rb +0 -16
  136. data/spec/unit/unparser/buffer/unindent_spec.rb +0 -20
  137. data/spec/unit/unparser/comments/consume_spec.rb +0 -22
  138. data/spec/unit/unparser/comments/take_all_spec.rb +0 -19
  139. data/spec/unit/unparser/comments/take_before_spec.rb +0 -46
  140. data/spec/unit/unparser/comments/take_eol_comments_spec.rb +0 -32
  141. data/spec/unit/unparser/emitter/class_methods/handle_spec.rb +0 -17
  142. data/spec/unit/unparser_spec.rb +0 -1849
  143. data/unparser.gemspec +0 -32
@@ -1,29 +1,61 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'unparser'
4
- require 'optparse'
5
- require 'diff/lcs'
6
- require 'diff/lcs/hunk'
7
-
8
- require 'unparser/cli/source'
9
- require 'unparser/cli/differ'
10
- require 'unparser/cli/color'
11
-
12
3
  module Unparser
13
4
  # Unparser CLI implementation
14
- #
15
- # :reek:InstanceVariableAssumption
16
- # :reek:TooManyInstanceVariables
17
5
  class CLI
18
6
 
19
7
  EXIT_SUCCESS = 0
20
8
  EXIT_FAILURE = 1
21
9
 
10
+ class Target
11
+ include AbstractType
12
+
13
+ # Path target
14
+ class Path < self
15
+ include Concord.new(:path)
16
+
17
+ # Validation for this target
18
+ #
19
+ # @return [Validation]
20
+ def validation
21
+ Validation.from_path(path)
22
+ end
23
+
24
+ # Literal for this target
25
+ #
26
+ # @return [Validation]
27
+ def literal_validation
28
+ Validation::Literal.from_path(path)
29
+ end
30
+ end
31
+
32
+ # String target
33
+ class String
34
+ include Concord.new(:string)
35
+
36
+ # Validation for this target
37
+ #
38
+ # @return [Validation]
39
+ def validation
40
+ Validation.from_string(string)
41
+ end
42
+
43
+ # Literal for this target
44
+ #
45
+ # @return [Validation]
46
+ def literal_validation
47
+ Validation::Literal.from_string(path)
48
+ end
49
+ end # String
50
+ end # Target
51
+
52
+ private_constant(*constants(false))
53
+
22
54
  # Run CLI
23
55
  #
24
56
  # @param [Array<String>] arguments
25
57
  #
26
- # @return [Fixnum]
58
+ # @return [Integer]
27
59
  # the exit status
28
60
  #
29
61
  # @api private
@@ -39,22 +71,21 @@ module Unparser
39
71
  # @return [undefined]
40
72
  #
41
73
  # @api private
42
- #
43
- # ignore :reek:TooManyStatements
44
74
  def initialize(arguments)
45
- @sources = []
46
- @ignore = Set.new
75
+ @ignore = Set.new
76
+ @targets = []
47
77
 
48
- @success = true
49
- @fail_fast = false
50
- @verbose = false
78
+ @fail_fast = false
79
+ @success = true
80
+ @validation = :validation
81
+ @verbose = false
51
82
 
52
83
  opts = OptionParser.new do |builder|
53
84
  add_options(builder)
54
85
  end
55
86
 
56
87
  opts.parse!(arguments).each do |name|
57
- @sources.concat(sources(name))
88
+ @targets.concat(targets(name))
58
89
  end
59
90
  end
60
91
 
@@ -66,38 +97,40 @@ module Unparser
66
97
  #
67
98
  # @api private
68
99
  #
69
- # ignore :reek:TooManyStatements
100
+ # rubocop:disable Metrics/MethodLength
70
101
  def add_options(builder)
71
102
  builder.banner = 'usage: unparse [options] FILE [FILE]'
72
103
  builder.separator('')
73
104
  builder.on('-e', '--evaluate SOURCE') do |source|
74
- @sources << Source::String.new(source)
105
+ @targets << Target::String.new(source)
75
106
  end
76
- builder.on('--start-with FILE') do |file|
77
- @start_with = sources(file).first
107
+ builder.on('--start-with FILE') do |path|
108
+ @start_with = targets(path).first
78
109
  end
79
110
  builder.on('-v', '--verbose') do
80
111
  @verbose = true
81
112
  end
113
+ builder.on('-l', '--literal') do
114
+ @validation = :literal_validation
115
+ end
82
116
  builder.on('--ignore FILE') do |file|
83
- @ignore.merge(sources(file))
117
+ @ignore.merge(targets(file))
84
118
  end
85
119
  builder.on('--fail-fast') do
86
120
  @fail_fast = true
87
121
  end
88
122
  end
123
+ # rubocop:enable Metrics/MethodLength
89
124
 
90
125
  # Return exit status
91
126
  #
92
- # @return [Fixnum]
127
+ # @return [Integer]
93
128
  #
94
129
  # @api private
95
130
  #
96
131
  def exit_status
97
- effective_sources.each do |source|
98
- next if @ignore.include?(source)
99
-
100
- process_source(source)
132
+ effective_targets.each do |target|
133
+ process_target(target)
101
134
  break if @fail_fast && !@success
102
135
  end
103
136
 
@@ -106,67 +139,41 @@ module Unparser
106
139
 
107
140
  private
108
141
 
109
- # Process source
110
- #
111
- # @param [CLI::Source] source
112
- #
113
- # @return [undefined]
114
- #
115
- # @api private
116
- #
117
- def process_source(source)
118
- if source.success?
119
- puts source.report if @verbose
120
- puts "Success: #{source.identification}"
142
+ def process_target(target)
143
+ validation = target.public_send(@validation)
144
+ if validation.success?
145
+ puts validation.report if @verbose
146
+ puts "Success: #{validation.identification}"
121
147
  else
122
- puts source.report
123
- puts "Error: #{source.identification}"
148
+ puts validation.report
149
+ puts "Error: #{validation.identification}"
124
150
  @success = false
125
151
  end
126
152
  end
127
153
 
128
- # Return effective sources
129
- #
130
- # @return [Enumerable<CLI::Source>]
131
- #
132
- # @api private
133
- #
134
- def effective_sources
154
+ def effective_targets
135
155
  if @start_with
136
156
  reject = true
137
- @sources.reject do |source|
138
- if reject && source.eql?(@start_with)
157
+ @targets.reject do |targets|
158
+ if reject && targets.eql?(@start_with)
139
159
  reject = false
140
160
  end
141
161
 
142
162
  reject
143
163
  end
144
164
  else
145
- @sources
146
- end
165
+ @targets
166
+ end.reject(&@ignore.method(:include?))
147
167
  end
148
168
 
149
- # Return sources for file name
150
- #
151
- # @param [String] file_name
152
- #
153
- # @return [Enumerable<CLI::Source>]
154
- #
155
- # @api private
156
- #
157
- # ignore :reek:UtilityFunction
158
- def sources(file_name)
159
- files =
160
- if File.directory?(file_name)
161
- Dir.glob(File.join(file_name, '**/*.rb')).sort
162
- elsif File.file?(file_name)
163
- [file_name]
164
- else
165
- Dir.glob(file_name).sort
166
- end
167
-
168
- files.map(&Source::File.method(:new))
169
+ def targets(file_name)
170
+ if File.directory?(file_name)
171
+ Dir.glob(File.join(file_name, '**/*.rb')).sort
172
+ elsif File.file?(file_name)
173
+ [file_name]
174
+ else
175
+ Dir.glob(file_name).sort
176
+ end.map { |file| Target::Path.new(Pathname.new(file)) }
169
177
  end
170
-
171
178
  end # CLI
172
179
  end # Unparser
@@ -10,9 +10,6 @@ module Unparser
10
10
  # @param [String] text
11
11
  #
12
12
  # @return [String]
13
- #
14
- # @api private
15
- #
16
13
  def format(text)
17
14
  "\e[#{code}m#{text}\e[0m"
18
15
  end
@@ -25,28 +22,18 @@ module Unparser
25
22
  #
26
23
  # @return [String]
27
24
  # the argument string
28
- #
29
- # @api private
30
- #
31
25
  def format(text)
32
26
  text
33
27
  end
34
28
 
35
29
  private
36
30
 
37
- # Initialize null color
38
- #
39
- # @return [undefined]
40
- #
41
- # @api private
42
- #
43
31
  def initialize; end
44
32
 
45
33
  end.new
46
34
 
47
35
  RED = Color.new(31)
48
36
  GREEN = Color.new(32)
49
- BLUE = Color.new(34)
50
37
 
51
38
  end # Color
52
39
  end # Unparser
@@ -3,8 +3,6 @@
3
3
  module Unparser
4
4
 
5
5
  # Holds the comments that remain to be emitted
6
- #
7
- # ignore :reek:RepeatedConditional
8
6
  class Comments
9
7
 
10
8
  # Proxy to singleton
@@ -113,39 +111,15 @@ module Unparser
113
111
 
114
112
  private
115
113
 
116
- # Take comments while the provided block returns true
117
- #
118
- # @yield [Parser::Source::Comment]
119
- #
120
- # @return [Array]
121
- #
122
- # @api private
123
- #
124
114
  def take_while
125
115
  number_to_take = @comments.index { |comment| !yield(comment) } || @comments.size
126
116
  @comments.shift(number_to_take)
127
117
  end
128
118
 
129
- # Take comments up to the line number
130
- #
131
- # @param [Fixnum] line
132
- #
133
- # @return [Array]
134
- #
135
- # @api private
136
- #
137
119
  def take_up_to_line(line)
138
120
  take_while { |comment| comment.location.expression.line <= line }
139
121
  end
140
122
 
141
- # Unshift document comments and return the rest
142
- #
143
- # @param [Array] comments
144
- #
145
- # @return [Array]
146
- #
147
- # @api private
148
- #
149
123
  def unshift_documents(comments)
150
124
  doc_comments, other_comments = comments.partition(&:document?)
151
125
  doc_comments.reverse_each { |comment| @comments.unshift(comment) }
@@ -2,66 +2,19 @@
2
2
 
3
3
  module Unparser
4
4
  # All unparser constants maybe included in other libraries.
5
- #
6
- # False positive since constants are frozen dynamically
7
- # to avoid duplication of `.freeze` calls
8
- #
9
- # :reek:TooManyConstants
10
5
  module Constants
11
6
 
12
- # Return frozen symbol set from enumerable
13
- #
14
- # @param [Enumerable] enumerable
15
- #
16
- # @return [Set<Symbol>]
17
- #
18
- # @api private
19
- #
20
- def self.symbol_set(enumerable)
21
- enumerable.map(&:to_sym).freeze
22
- end
23
- private_class_method :symbol_set
24
-
25
- BRACKETS_CURLY = IceNine.deep_freeze(%w[{ }])
26
- BRACKETS_ROUND = IceNine.deep_freeze(%w[( )])
27
- BRACKETS_SQUARE = IceNine.deep_freeze(%w([ ]))
28
-
29
7
  # All unary operators of the ruby language
30
- UNARY_OPERATORS = symbol_set %w[
8
+ UNARY_OPERATORS = %i[
31
9
  ! ~ -@ +@
32
- ]
10
+ ].to_set.freeze
33
11
 
34
12
  # All binary operators of the ruby language
35
- BINARY_OPERATORS = symbol_set %w[
13
+ BINARY_OPERATORS = %i[
36
14
  + - * / & | && || << >> ==
37
15
  === != <= < <=> > >= =~ !~ ^
38
16
  ** %
39
- ]
40
-
41
- COMMENT = '#'
42
-
43
- WS = ' '
44
- NL = "\n"
45
- T_DOT = '.'
46
- T_LT = '<'
47
- T_DLT = '<<'
48
- T_AMP = '&'
49
- T_ASN = '='
50
- T_SPLAT = '*'
51
- T_DSPLAT = '**'
52
- T_ASR = '=>'
53
- T_PIPE = '|'
54
- T_DCL = '::'
55
- T_NEG = '!'
56
- T_OR = '||'
57
- T_AND = '&&'
58
- T_COLON = ':'
59
-
60
- M_PO = '('
61
- M_PC = ')'
62
-
63
- SNGL_QUOTE = "'"
64
- DBL_QUOTE = '"'
17
+ ].to_set.freeze
65
18
 
66
19
  # Keywords
67
20
  K_DO = 'do'
@@ -107,8 +60,6 @@ module Unparser
107
60
  K_FILE = '__FILE__'
108
61
  K_THEN = 'then'
109
62
 
110
- DEFAULT_DELIMITER = ', '.freeze
111
-
112
63
  KEYWORDS = constants.each_with_object([]) do |name, keywords|
113
64
  value = const_get(name).freeze
114
65
  next unless name.to_s.start_with?('K_')
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ # Class to create diffs from source code
5
+ class Diff
6
+ include Adamantium::Flat, Concord.new(:old, :new)
7
+
8
+ ADDITION = '+'
9
+ DELETION = '-'
10
+ NEWLINE = "\n"
11
+
12
+ # Unified source diff between old and new
13
+ #
14
+ # @return [String]
15
+ # if there is exactly one diff
16
+ #
17
+ # @return [nil]
18
+ # otherwise
19
+ def diff
20
+ return if diffs.empty?
21
+
22
+ minimized_hunk.diff(:unified) + NEWLINE
23
+ end
24
+ memoize :diff
25
+
26
+ # Colorized unified source diff between old and new
27
+ #
28
+ # @return [String]
29
+ # if there is a diff
30
+ #
31
+ # @return [nil]
32
+ # otherwise
33
+ def colorized_diff
34
+ return unless diff
35
+
36
+ diff.lines.map(&self.class.method(:colorize_line)).join
37
+ end
38
+ memoize :colorized_diff
39
+
40
+ # Build new object from source strings
41
+ #
42
+ # @param [String] old
43
+ # @param [String] new
44
+ #
45
+ # @return [Diff]
46
+ def self.build(old, new)
47
+ new(lines(old), lines(new))
48
+ end
49
+
50
+ # Break up source into lines
51
+ #
52
+ # @param [String] source
53
+ #
54
+ # @return [Array<String>]
55
+ def self.lines(source)
56
+ source.lines.map(&:chomp)
57
+ end
58
+ private_class_method :lines
59
+
60
+ private
61
+
62
+ def diffs
63
+ ::Diff::LCS.diff(old, new)
64
+ end
65
+
66
+ def hunks
67
+ diffs.map do |diff|
68
+ ::Diff::LCS::Hunk.new(old.map(&:dup), new, diff, max_length, 0)
69
+ end
70
+ end
71
+
72
+ def minimized_hunk
73
+ head, *tail = hunks
74
+
75
+ tail.reduce(head) do |left, right|
76
+ right.merge(left)
77
+ right
78
+ end
79
+ end
80
+
81
+ def max_length
82
+ [old, new].map(&:length).max
83
+ end
84
+
85
+ def self.colorize_line(line)
86
+ case line[0]
87
+ when ADDITION
88
+ Color::GREEN
89
+ when DELETION
90
+ Color::RED
91
+ else
92
+ Color::NONE
93
+ end.format(line)
94
+ end
95
+ private_class_method :colorize_line
96
+
97
+ end # Diff
98
+ end # Unparser