unparser 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
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