unparser 0.1.6 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b62c76f077c1633ea95d4b674eef40c4862bd841
4
- data.tar.gz: 77d01fff24751db00c267068880942f8df8a588a
3
+ metadata.gz: bbd1a7e700a15704cf6045d49b60c819fa098a56
4
+ data.tar.gz: c4309776665a4ee2703ff6569d57423d17b20bd7
5
5
  SHA512:
6
- metadata.gz: e0cf99eb3262e4d55e8899a1c924d5388cdb55d5991ce33da2ac2717a9cdf8c9bccabaf56c316c8615184627ede859e2cdbfe2472507a7d6985c7ead2e57c26f
7
- data.tar.gz: 7b78d0c2cdedf07d26f7f7f166587a08f2142be202de2fe1bba51b6ce3a12aff60f0abdb8164342b4b7ae3c516959ae580e83c33e266263c46b6d5e2bdd584a7
6
+ metadata.gz: 96cad113e6bd2c968267edb3f3008e64bcb7c1e217f7256b182ebb3e7412a51a8bb7675204a9b897a926da7e3cdb8ed49a9f34c2516f2db901adcef65c302c68
7
+ data.tar.gz: a9a4694e7475058e25e97f107a835cf704533937ea9bfa08985593abb85dfd150daa48633497d354f1ed53ebee3c27bb8fbc04bf1833d2e096933adcad29b214
data/Changelog.md CHANGED
@@ -1,3 +1,7 @@
1
+ # v0.1.7 2013-12-31
2
+
3
+ * Add back support for root nodes of type resbody https://github.com/mbj/unparser/issues/24
4
+
1
5
  # v0.1.6 2013-12-31
2
6
 
3
7
  * Emit 1.9 style hashes where possible: https://github.com/mbj/unparser/pull/23
data/lib/unparser.rb CHANGED
@@ -4,6 +4,7 @@ require 'abstract_type'
4
4
  require 'procto'
5
5
  require 'concord'
6
6
  require 'parser/all'
7
+ require 'parser/current'
7
8
 
8
9
  # Library namespace
9
10
  module Unparser
data/lib/unparser/cli.rb CHANGED
@@ -1,12 +1,14 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'unparser'
4
- require 'mutant'
5
4
  require 'optparse'
5
+ require 'diff/lcs'
6
+ require 'diff/lcs/hunk'
6
7
 
7
8
  require 'unparser/cli/preprocessor'
8
9
  require 'unparser/cli/source'
9
10
  require 'unparser/cli/differ'
11
+ require 'unparser/cli/color'
10
12
 
11
13
  module Unparser
12
14
  # Unparser CLI implementation
@@ -46,10 +48,14 @@ module Unparser
46
48
  add_options(builder)
47
49
  end
48
50
 
49
- file_names = opts.parse!(arguments)
51
+ arguments = opts.parse!(arguments)
50
52
 
51
- file_names.each do |file_name|
52
- @sources << Source::File.new(file_name)
53
+ arguments.each do |name|
54
+ if File.directory?(name)
55
+ add_directory(name)
56
+ else
57
+ add_file(name)
58
+ end
53
59
  end
54
60
  end
55
61
 
@@ -109,5 +115,31 @@ module Unparser
109
115
  end
110
116
  end
111
117
 
118
+ # Add file
119
+ #
120
+ # @param [String] file_name
121
+ #
122
+ # @return [undefined]
123
+ #
124
+ # @api private
125
+ #
126
+ def add_file(file_name)
127
+ @sources << Source::File.new(file_name)
128
+ end
129
+
130
+ # Add directory
131
+ #
132
+ # @param [String] directory_name
133
+ #
134
+ # @return [undefined]
135
+ #
136
+ # @api private
137
+ #
138
+ def add_directory(directory_name)
139
+ Dir.glob(File.join(directory_name, '**/*.rb')).each do |file_name|
140
+ add_file(file_name)
141
+ end
142
+ end
143
+
112
144
  end # CLI
113
145
  end # Unparser
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ module Unparser
4
+ # Class to colorize strings
5
+ class Color
6
+ include Adamantium::Flat, Concord.new(:code)
7
+
8
+ # Format text with color
9
+ #
10
+ # @param [String] text
11
+ #
12
+ # @return [String]
13
+ #
14
+ # @api private
15
+ #
16
+ def format(text)
17
+ "\e[#{@code}m#{text}\e[0m"
18
+ end
19
+
20
+ NONE = Class.new(self) do
21
+
22
+ # Format null color
23
+ #
24
+ # @param [String] text
25
+ #
26
+ # @return [String]
27
+ # the argument string
28
+ #
29
+ # @api private
30
+ #
31
+ def format(text)
32
+ text
33
+ end
34
+
35
+ private
36
+
37
+ # Initialize null color
38
+ #
39
+ # @return [undefined]
40
+ #
41
+ # @api private
42
+ #
43
+ def initialize
44
+ end
45
+
46
+ end.new
47
+
48
+ RED = Color.new(31)
49
+ GREEN = Color.new(32)
50
+ BLUE = Color.new(34)
51
+
52
+ end # Color
53
+ end # Unparser
@@ -2,14 +2,12 @@
2
2
 
3
3
  module Unparser
4
4
  class CLI
5
- # Unparser CLI specific differ
6
- class Differ < Mutant::Differ
7
- include Procto.call(:colorized_diff)
5
+ # Class to create diffs from source code
6
+ class Differ
7
+ include Adamantium::Flat, Concord.new(:old, :new), Procto.call(:colorized_diff)
8
8
 
9
9
  # Return source diff
10
10
  #
11
- # FIXME: Multiple diffs get screwed up!
12
- #
13
11
  # @return [String]
14
12
  # if there is a diff
15
13
  #
@@ -19,12 +17,114 @@ module Unparser
19
17
  # @api private
20
18
  #
21
19
  def diff
22
- diffs.map do |piece|
23
- Diff::LCS::Hunk.new(old, new, piece, max_length, old.length - new.length).diff(:unified) << "\n"
24
- end.join
20
+ output = ""
21
+ lines = 5
22
+ hunk = oldhunk = nil
23
+ file_length_difference = new.length - old.length
24
+ diffs.each do |piece|
25
+ begin
26
+ hunk = Diff::LCS::Hunk.new(old, new, piece, lines, file_length_difference)
27
+ file_length_difference = hunk.file_length_difference
28
+
29
+ next unless oldhunk
30
+ next if (lines > 0) && hunk.merge(oldhunk)
31
+
32
+ output << oldhunk.diff(:unified) << "\n"
33
+ ensure
34
+ oldhunk = hunk
35
+ end
36
+ end
37
+ output << oldhunk.diff(:unified) << "\n"
38
+
39
+ output
25
40
  end
26
41
  memoize :diff
27
42
 
28
- end # Differ
29
- end # CLI
43
+ # Return colorized source diff
44
+ #
45
+ # @return [String]
46
+ # if there is a diff
47
+ #
48
+ # @return [nil]
49
+ # otherwise
50
+ #
51
+ # @api private
52
+ #
53
+ def colorized_diff
54
+ diff.lines.map do |line|
55
+ self.class.colorize_line(line)
56
+ end.join
57
+ end
58
+ memoize :colorized_diff
59
+
60
+ # Return new object
61
+ #
62
+ # @param [String] old
63
+ # @param [String] new
64
+ #
65
+ # @return [Differ]
66
+ #
67
+ # @api private
68
+ #
69
+ def self.build(old, new)
70
+ new(lines(old), lines(new))
71
+ end
72
+
73
+ # Break up source into lines
74
+ #
75
+ # @param [String] source
76
+ #
77
+ # @return [Array<String>]
78
+ #
79
+ # @api private
80
+ #
81
+ def self.lines(source)
82
+ source.lines.map { |line| line.chomp }
83
+ end
84
+ private_class_method :lines
85
+
86
+ private
87
+
88
+ # Return diffs
89
+ #
90
+ # @return [Array<Array>]
91
+ #
92
+ # @api private
93
+ #
94
+ def diffs
95
+ Diff::LCS.diff(old, new)
96
+ end
97
+ memoize :diffs
98
+
99
+ # Return max length
100
+ #
101
+ # @return [Fixnum]
102
+ #
103
+ # @api private
104
+ #
105
+ def max_length
106
+ [old, new].map(&:length).max
107
+ end
108
+
109
+ # Return colorized diff line
110
+ #
111
+ # @param [String] line
112
+ #
113
+ # @return [String]
114
+ #
115
+ # @api private
116
+ #
117
+ def self.colorize_line(line)
118
+ case line[0]
119
+ when '+'
120
+ Color::GREEN
121
+ when '-'
122
+ Color::RED
123
+ else
124
+ Color::NONE
125
+ end.format(line)
126
+ end
127
+
128
+ end # CLI
129
+ end # Differ
30
130
  end # Unparser
@@ -91,8 +91,9 @@ module Unparser
91
91
  # @api private
92
92
  #
93
93
  def result
94
- s(node.type, *mapped_children)
94
+ s(node.type, mapped_children)
95
95
  end
96
+
96
97
  end # Noop
97
98
 
98
99
  # Preprocessor for dynamic string nodes. Collapses adjacent string segments into one.
@@ -108,7 +109,7 @@ module Unparser
108
109
  #
109
110
  def result
110
111
  if collapsed_children.all? { |node| node.type == :str }
111
- s(:str, collapsed_children.map { |node| node.children.first }.join)
112
+ s(:str, [collapsed_children.map { |node| node.children.first }.join])
112
113
  else
113
114
  node.updated(nil, collapsed_children)
114
115
  end
@@ -125,7 +126,7 @@ module Unparser
125
126
  def collapsed_children
126
127
  chunked_children.each_with_object([]) do |(type, nodes), aggregate|
127
128
  if type == :str
128
- aggregate << s(:str, nodes.map { |node| node.children.first }.join)
129
+ aggregate << s(:str, [nodes.map { |node| node.children.first }.join])
129
130
  else
130
131
  aggregate.concat(nodes)
131
132
  end
@@ -4,7 +4,7 @@ module Unparser
4
4
  class CLI
5
5
  # Source representation for CLI sources
6
6
  class Source
7
- include AbstractType, Adamantium::Flat
7
+ include AbstractType, Adamantium::Flat, NodeHelpers
8
8
 
9
9
  # Test if source could be unparsed successfully
10
10
  #
@@ -16,7 +16,7 @@ module Unparser
16
16
  # @api private
17
17
  #
18
18
  def success?
19
- original_ast == generated_ast
19
+ original_ast && generated_ast && original_ast == generated_ast
20
20
  end
21
21
 
22
22
  # Return error report
@@ -26,14 +26,15 @@ module Unparser
26
26
  # @api private
27
27
  #
28
28
  def error_report
29
- diff = Differ.call(
30
- original_ast.inspect.lines.map(&:chomp),
31
- generated_ast.inspect.lines.map(&:chomp)
32
- )
33
- "#{diff}\nOriginal:\n#{original_source}\nGenerated:\n#{generated_source}"
29
+ if original_ast && generated_ast
30
+ error_report_with_ast_diff
31
+ else
32
+ error_report_with_parser_error
33
+ end
34
34
  end
35
35
  memoize :error_report
36
36
 
37
+
37
38
  private
38
39
 
39
40
  # Return generated source
@@ -47,14 +48,51 @@ module Unparser
47
48
  end
48
49
  memoize :generated_source
49
50
 
51
+ # Return error report with parser error
52
+ #
53
+ # @return [String]
54
+ #
55
+ # @api private
56
+ #
57
+ def error_report_with_parser_error
58
+ unless original_ast
59
+ return "Parsing of original source failed:\n#{original_source}"
60
+ end
61
+
62
+ unless generated_ast
63
+ return "Parsing of generated source failed:\nOriginal-AST:#{original_ast.inspect}\nSource:\n#{generated_source}"
64
+ end
65
+
66
+ end
67
+
68
+ # Return error report with AST difference
69
+ #
70
+ # @return [String]
71
+ #
72
+ # @api private
73
+ #
74
+ def error_report_with_ast_diff
75
+ diff = Differ.call(
76
+ original_ast.inspect.lines.map(&:chomp),
77
+ generated_ast.inspect.lines.map(&:chomp)
78
+ )
79
+ "#{diff}\nOriginal:\n#{original_source}\nGenerated:\n#{generated_source}"
80
+ end
81
+
50
82
  # Return generated AST
51
83
  #
52
84
  # @return [Parser::AST::Node]
85
+ # if parser was sucessful for generated ast
86
+ #
87
+ # @return [nil]
88
+ # otherwise
53
89
  #
54
90
  # @api private
55
91
  #
56
92
  def generated_ast
57
- Preprocessor.run(Parser::CurrentRuby.parse(generated_source))
93
+ Preprocessor.run(parse(generated_source)) || s(:empty)
94
+ rescue Parser::SyntaxError
95
+ nil
58
96
  end
59
97
  memoize :generated_ast
60
98
 
@@ -65,10 +103,24 @@ module Unparser
65
103
  # @api private
66
104
  #
67
105
  def original_ast
68
- Preprocessor.run(Parser::CurrentRuby.parse(original_source))
106
+ Preprocessor.run(parse(original_source)) || s(:empty)
107
+ rescue Parser::SyntaxError
108
+ nil
69
109
  end
70
110
  memoize :original_ast
71
111
 
112
+ # Parse source with current ruby
113
+ #
114
+ # @param [String] source
115
+ #
116
+ # @return [Parser::AST::Node]
117
+ #
118
+ # @api private
119
+ #
120
+ def parse(source)
121
+ Parser::CurrentRuby.parse(source)
122
+ end
123
+
72
124
  # CLI source from string
73
125
  class String < self
74
126
  include Concord.new(:original_source)
@@ -67,6 +67,8 @@ module Unparser
67
67
  [key, "\\#{value}"] unless key == WS
68
68
  end.compact
69
69
 
70
+ pairs << ['#{', '\#{']
71
+
70
72
  ESCAPES = ::Hash[pairs]
71
73
 
72
74
  REPLACEMENTS = ::Regexp.union(ESCAPES.keys)
@@ -5,49 +5,92 @@ module Unparser
5
5
  # Emitter for rescue body nodes
6
6
  class Resbody < self
7
7
 
8
- handle :resbody
9
-
10
- children :exception, :assignment, :body
11
-
12
- private
13
-
14
- # Perform dispatch
15
- #
16
- # @return [undefined]
17
- #
18
- # @api private
19
- #
20
- def dispatch
21
- write(K_RESCUE)
22
- emit_exception
23
- emit_assignment
24
- emit_body
25
- end
8
+ children :exception, :assignment, :body
26
9
 
27
- # Emit exception
28
- #
29
- # @return [undefined]
30
- #
31
- # @api private
32
- #
33
- def emit_exception
34
- return unless exception
35
- ws
36
- delimited(exception.children)
37
- end
10
+ class Standalone < self
11
+
12
+ handle :resbody
13
+
14
+ private
15
+
16
+ # Perform dispatch
17
+ #
18
+ # @return [undefined]
19
+ #
20
+ # @api private
21
+ #
22
+ def dispatch
23
+ write(K_RESCUE)
24
+ parentheses { visit(body) }
25
+ end
26
+
27
+ # Emit exception
28
+ #
29
+ # @return [undefined]
30
+ #
31
+ # @api private
32
+ #
33
+ def emit_exception
34
+ return unless exception
35
+ ws
36
+ delimited(exception.children)
37
+ end
38
38
 
39
- # Emit assignment
40
- #
41
- # @return [undefined]
42
- #
43
- # @api private
44
- #
45
- def emit_assignment
46
- return unless assignment
47
- write(WS, T_ASR, WS)
48
- visit(assignment)
39
+ # Emit assignment
40
+ #
41
+ # @return [undefined]
42
+ #
43
+ # @api private
44
+ #
45
+ def emit_assignment
46
+ return unless assignment
47
+ write(WS, T_ASR, WS)
48
+ visit(assignment)
49
+ end
49
50
  end
50
51
 
51
- end # Resbody
52
+ class Embedded < self
53
+
54
+ private
55
+
56
+ # Perform dispatch
57
+ #
58
+ # @return [undefined]
59
+ #
60
+ # @api private
61
+ #
62
+ def dispatch
63
+ write(K_RESCUE)
64
+ emit_exception
65
+ emit_assignment
66
+ emit_body
67
+ end
68
+
69
+ # Emit exception
70
+ #
71
+ # @return [undefined]
72
+ #
73
+ # @api private
74
+ #
75
+ def emit_exception
76
+ return unless exception
77
+ ws
78
+ delimited(exception.children)
79
+ end
80
+
81
+ # Emit assignment
82
+ #
83
+ # @return [undefined]
84
+ #
85
+ # @api private
86
+ #
87
+ def emit_assignment
88
+ return unless assignment
89
+ write(WS, T_ASR, WS)
90
+ visit(assignment)
91
+ end
92
+
93
+ end # Resbody
94
+ end
52
95
  end # Emitter
53
96
  end # Unparser
@@ -7,7 +7,11 @@ module Unparser
7
7
 
8
8
  handle :rescue
9
9
 
10
- children :body
10
+ children :body, :rescue_body
11
+
12
+ RESCUE_BODIES_RANGE = (1..-2).freeze
13
+
14
+ EMBEDDED_TYPES = [:def, :defs, :kwbegin, :ensure].to_set.freeze
11
15
 
12
16
  private
13
17
 
@@ -18,13 +22,53 @@ module Unparser
18
22
  # @api private
19
23
  #
20
24
  def dispatch
25
+ if standalone?
26
+ emit_standalone
27
+ else
28
+ emit_embedded
29
+ end
30
+ end
31
+
32
+ # Test if rescue node ist standalone
33
+ #
34
+ # @return [true]
35
+ # if rescue node is standalone
36
+ #
37
+ # @return [false]
38
+ # otherwise
39
+ #
40
+ # @api private
41
+ #
42
+ def standalone?
43
+ !EMBEDDED_TYPES.include?(parent_type) && body
44
+ end
45
+
46
+ # Emit standalone form
47
+ #
48
+ # @return [undefined]
49
+ #
50
+ # @api private
51
+ #
52
+ def emit_standalone
53
+ visit(body)
54
+ ws
55
+ run(Resbody::Standalone, rescue_body)
56
+ end
57
+
58
+ # Emit embedded form
59
+ #
60
+ # @return [undefined]
61
+ #
62
+ # @api private
63
+ #
64
+ def emit_embedded
21
65
  if body
22
66
  visit_indented(body)
23
67
  else
24
68
  nl
25
69
  end
26
70
  rescue_bodies.each do |child|
27
- visit(child)
71
+ run(Resbody::Embedded, child)
28
72
  end
29
73
  emit_else
30
74
  end
@@ -36,7 +80,7 @@ module Unparser
36
80
  # @api private
37
81
  #
38
82
  def rescue_bodies
39
- children[1..-2]
83
+ children[RESCUE_BODIES_RANGE]
40
84
  end
41
85
 
42
86
  # Emit else
@@ -11,8 +11,8 @@ module Unparser
11
11
  #
12
12
  # @api private
13
13
  #
14
- def s(type, *children)
15
- Parser::AST::Node.new(type, *children)
14
+ def s(type, children = [])
15
+ Parser::AST::Node.new(type, children)
16
16
  end
17
17
 
18
18
  end # NodeHelpers
@@ -91,6 +91,8 @@ describe Unparser do
91
91
  assert_source %q("foo\nbar")
92
92
  assert_source %q("foo bar #{}")
93
93
  assert_source %q("foo\nbar #{}")
94
+ assert_source %q("#{}\#{}")
95
+ assert_source %q("\#{}#{}")
94
96
  # Within indentation
95
97
  assert_generates <<-'RUBY', <<-'RUBY'
96
98
  if foo
@@ -632,6 +634,10 @@ describe Unparser do
632
634
  baz
633
635
  end
634
636
  RUBY
637
+
638
+ assert_source 'foo rescue(bar)'
639
+ assert_source 'foo rescue(return(bar))'
640
+ assert_source 'x = foo rescue(return(bar))'
635
641
  end
636
642
 
637
643
  context 'super' do
@@ -770,12 +776,30 @@ describe Unparser do
770
776
 
771
777
  assert_source <<-'RUBY'
772
778
  def foo
779
+ foo
780
+ rescue
773
781
  bar
774
782
  ensure
775
783
  baz
776
784
  end
777
785
  RUBY
778
786
 
787
+ assert_source <<-'RUBY'
788
+ def foo
789
+ bar
790
+ ensure
791
+ baz
792
+ end
793
+ RUBY
794
+
795
+ assert_source <<-'RUBY'
796
+ def self.foo
797
+ bar
798
+ rescue
799
+ baz
800
+ end
801
+ RUBY
802
+
779
803
  assert_source <<-'RUBY'
780
804
  def foo
781
805
  bar
data/unparser.gemspec CHANGED
@@ -1,26 +1,28 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- Gem::Specification.new do |s|
4
- s.name = 'unparser'
5
- s.version = '0.1.6'
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'unparser'
5
+ gem.version = '0.1.7'
6
6
 
7
- s.authors = ['Markus Schirp']
8
- s.email = 'mbj@schir-dso.com'
9
- s.summary = 'Generate equivalent source for parser gem AST nodes'
10
- s.description = s.summary
11
- s.homepage = 'http://github.com/mbj/unparser'
12
- s.license = 'MIT'
7
+ gem.authors = ['Markus Schirp']
8
+ gem.email = 'mbj@schir-dso.com'
9
+ gem.summary = 'Generate equivalent source for parser gem AST nodes'
10
+ gem.description = gem.summary
11
+ gem.homepage = 'http://github.com/mbj/unparser'
12
+ gem.license = 'MIT'
13
13
 
14
- s.files = `git ls-files`.split("\n")
15
- s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
16
- s.require_paths = %w(lib)
17
- s.extra_rdoc_files = %w(README.md)
18
- s.executables = [ 'unparser' ]
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = `git ls-files -- {spec,features}/*`.split("\n")
16
+ gem.require_paths = %w(lib)
17
+ gem.extra_rdoc_files = %w(README.md)
18
+ gem.executables = [ 'unparser' ]
19
19
 
20
- s.add_dependency('parser', '~> 2.1.0')
21
- s.add_dependency('procto', '~> 0.0.2')
22
- s.add_dependency('concord', '~> 0.1.4')
23
- s.add_dependency('adamantium', '~> 0.1')
24
- s.add_dependency('equalizer', '~> 0.0.7')
25
- s.add_dependency('abstract_type', '~> 0.0.7')
20
+ gem.required_ruby_version
21
+
22
+ gem.add_dependency('parser', '~> 2.1.0')
23
+ gem.add_dependency('procto', '~> 0.0.2')
24
+ gem.add_dependency('concord', '~> 0.1.4')
25
+ gem.add_dependency('adamantium', '~> 0.1')
26
+ gem.add_dependency('equalizer', '~> 0.0.7')
27
+ gem.add_dependency('abstract_type', '~> 0.0.7')
26
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-31 00:00:00.000000000 Z
11
+ date: 2014-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -125,6 +125,7 @@ files:
125
125
  - lib/unparser.rb
126
126
  - lib/unparser/buffer.rb
127
127
  - lib/unparser/cli.rb
128
+ - lib/unparser/cli/color.rb
128
129
  - lib/unparser/cli/differ.rb
129
130
  - lib/unparser/cli/preprocessor.rb
130
131
  - lib/unparser/cli/source.rb