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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a121bb510d3b91c074428c68acea8438039c5aef
4
- data.tar.gz: dba0b6b1581e9c836aba08636caa16eb4568b115
3
+ metadata.gz: 034e53fe83f3cb6b5d1c99e64f35b73d505812bf
4
+ data.tar.gz: 261ece646cfa726f17d70c2d82a44f837d6155b2
5
5
  SHA512:
6
- metadata.gz: 2bacdbaebd34a249353a85597a13be21df7d9026676c0f44460a4dc7c9dc8922ca92c731cbc26af1b1716b242f2535b779be63f30bedd399b7b601b098165097
7
- data.tar.gz: df148e906844b84143ae3ccf505b9d4b087babcae7e9df977cd8b0e8733a4e6618e5154378253bf8d30ba1ac75a272f090d312d6b07ab9ddc30e151a29c91bb9
6
+ metadata.gz: ff483fa78c83e951ff869033f025238d75dbbba20a747952a32ce034c3a88ee346a0aeab555053fb27b94a440a38b4a9a18b036d672b7e64545fec4d0bec788b
7
+ data.tar.gz: db9c2c31f83b67d7bf70893c774a53b764a4e02ff7f096555fe42c88ba1ee504e962ff6e0e4e20be3febfa08ad09884a0b0e363bab05034127aef404af552064
@@ -5,3 +5,4 @@ AllCops:
5
5
  - 'Gemfile.devtools'
6
6
  - 'vendor/**'
7
7
  - 'benchmarks/**'
8
+ - 'tmp/**'
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
- script: 'bundle exec rake spec'
2
+ script: 'bundle exec rake ci'
3
3
  rvm:
4
4
  - 1.9.3
5
5
  - 2.0.0
@@ -9,6 +9,7 @@ rvm:
9
9
  matrix:
10
10
  allow_failures:
11
11
  - rvm: rbx
12
+ - rvm: ruby
12
13
  notifications:
13
14
  irc:
14
15
  channels:
@@ -1,3 +1,8 @@
1
+ # v0.1.10 2014-04-06
2
+
3
+ * Fix emit of inline rescues in combination with control flow keywords.
4
+ * Begin corpus testing on rake ci against rubyspec
5
+
1
6
  # v0.1.9 2014-01-14
2
7
 
3
8
  * Fix emit of proc { |(a) }
data/Gemfile CHANGED
@@ -3,5 +3,7 @@ source 'https://rubygems.org'
3
3
 
4
4
  gemspec
5
5
 
6
+ gem 'morpher', git: 'https://github.com/mbj/morpher.git'
7
+
6
8
  gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
7
9
  eval_gemfile 'Gemfile.devtools'
@@ -1,9 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  group :development do
4
- gem 'rake', '~> 10.1.0'
5
- gem 'rspec', '~> 2.14.1'
6
- gem 'yard', '~> 0.8.7'
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.0'
15
+ gem 'kramdown', '~> 1.3.3'
15
16
  end
16
17
 
17
18
  group :guard do
18
- gem 'guard', '~> 2.2.4'
19
+ gem 'guard', '~> 2.6.0'
19
20
  gem 'guard-bundler', '~> 2.0.0'
20
- gem 'guard-rspec', '~> 4.2.0'
21
- gem 'guard-rubocop', '~> 1.0.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.4.0'
25
+ gem 'listen', '~> 2.7.1'
25
26
  gem 'rb-fchange', '~> 0.0.6', require: false
26
- gem 'rb-fsevent', '~> 0.9.3', require: false
27
- gem 'rb-inotify', '~> 0.9.0', require: false
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.0', require: false
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.2'
40
- gem 'rubocop', '~> 0.16.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.7', git: 'https://github.com/dkubb/yardstick.git'
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.10'
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.2'
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.cm/mbj/mutant) mutators and the in-memory vendoring for self hosting.
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
@@ -1,6 +1,6 @@
1
- ---
2
- ruby:
3
- version: 2.0.0-p353
1
+ machine:
2
+ ruby:
3
+ version: 2.0.0
4
4
  test:
5
5
  override:
6
6
  - bundle exec rake ci
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 13
3
- total_score: 700
3
+ total_score: 720
@@ -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::StripHelper#strip
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::Source#error_report
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::StripHelper#strip
91
+ - Unparser::CLI::Source#strip
87
92
  - Unparser::CLI#sources
88
93
  enabled: true
89
94
  Attribute:
@@ -13,7 +13,7 @@ ParameterLists:
13
13
 
14
14
  MethodLength:
15
15
  CountComments: false
16
- Max: 15
16
+ Max: 17
17
17
 
18
18
  # Avoid more than `Max` levels of nesting.
19
19
  BlockNesting:
@@ -34,7 +34,6 @@ module Unparser
34
34
 
35
35
  end # Unparser
36
36
 
37
- require 'unparser/strip_helper'
38
37
  require 'unparser/buffer'
39
38
  require 'unparser/node_helpers'
40
39
  require 'unparser/preprocessor'
@@ -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
 
@@ -30,7 +30,7 @@ module Unparser
30
30
  if @content[-1] == NL
31
31
  prefix
32
32
  end
33
- @content << string
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
- @content << string
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
- @content << NL
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
- @content << INDENT_SPACE * @indent
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
@@ -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 |original_source|
67
- @sources << Source::String.new(original_source)
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.error_report
117
+ puts source.report
113
118
  puts "Error: #{source.identification}"
114
119
  @success = false
115
120
  end
@@ -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 error_report
56
+ def report
29
57
  case
30
58
  when original_ast && generated_ast
31
- error_report_with_ast_diff
59
+ report_with_ast_diff
32
60
  when !original_ast
33
- error_report_original
61
+ report_original
62
+ when !generated.success?
63
+ report_unparser
34
64
  when !generated_ast
35
- error_report_generated
65
+ report_generated
66
+ else
67
+ raise
36
68
  end
37
69
  end
38
- memoize :error_report
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 generated_source
49
- Unparser.unparse(original_ast)
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 error_report_original
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 error_report_generated
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
- #{generated_source}
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 error_report_with_ast_diff
150
+ def report_with_ast_diff
89
151
  strip(<<-MESSAGE)
90
- #{diff}
152
+ #{ast_diff}
91
153
  Original-Source:\n#{original_source}
92
154
  Original-AST:\n#{original_ast.inspect}
93
- Generated-Source:\n#{generated_source}
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(generated_source))
184
+ generated.success? && Preprocessor.run(parse(generated.source))
123
185
  rescue Parser::SyntaxError
124
186
  nil
125
187
  end
@@ -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
@@ -19,7 +19,11 @@ module Unparser
19
19
  # @api private
20
20
  #
21
21
  def dispatch
22
- visit_indented(body)
22
+ if body
23
+ visit_indented(body)
24
+ else
25
+ nl
26
+ end
23
27
  write(K_ENSURE)
24
28
  if ensure_body
25
29
  visit_indented(ensure_body)
@@ -7,7 +7,7 @@ module Unparser
7
7
 
8
8
  MAP = IceNine.deep_freeze(
9
9
  iflipflop: '..',
10
- eflipflop: '...',
10
+ eflipflop: '...'
11
11
  ).freeze
12
12
 
13
13
  handle(*MAP.keys)
@@ -8,7 +8,7 @@ module Unparser
8
8
  MAP = {
9
9
  return: K_RETURN,
10
10
  next: K_NEXT,
11
- break: K_BREAK,
11
+ break: K_BREAK
12
12
  }
13
13
 
14
14
  handle(*MAP.keys)
@@ -28,7 +28,7 @@ module Unparser
28
28
  # Test for postcondition
29
29
  #
30
30
  # @return [true]
31
- # if node must be emitted in postconditin style
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 !!if_branch ^ !!else_branch
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
- visit(condition)
103
+ visit_terminated(condition)
104
104
  end
105
105
 
106
106
  # Emit if branch
@@ -91,7 +91,7 @@ module Unparser
91
91
  #
92
92
  def emit_normal
93
93
  emit_keyword
94
- visit(condition)
94
+ visit_terminated(condition)
95
95
  emit_body
96
96
  k_end
97
97
  end
@@ -5,7 +5,7 @@ module Unparser
5
5
  # Emitter for rescue body nodes
6
6
  class Resbody < self
7
7
 
8
- children :exception, :assignment, :body
8
+ children :exception, :assignment, :body
9
9
 
10
10
  # Emitter for resbody in standalone form
11
11
  class Standalone < self
@@ -49,7 +49,7 @@ module Unparser
49
49
  if parent_type == :ensure
50
50
  !parent.node.children.first.equal?(node)
51
51
  else
52
- !EMBEDDED_TYPES.include?(parent_type) && body
52
+ !EMBEDDED_TYPES.include?(parent_type)
53
53
  end
54
54
  end
55
55
 
@@ -14,10 +14,13 @@ module Unparser
14
14
  #
15
15
  def dispatch
16
16
  emit_receiver
17
- emit_selector
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
@@ -1,6 +1,10 @@
1
- # encoding: utf-8
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
@@ -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=:baz'
600
- assert_source 'self.foo=:bar'
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = 'unparser'
5
- gem.version = '0.1.9'
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.0')
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.1')
26
- gem.add_dependency('equalizer', '~> 0.0.7')
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.9
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-01-14 00:00:00.000000000 Z
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.0
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: 2.1.0
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.0.2
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.1.4
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: '0.1'
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: '0.1'
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.7
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
- version_requirements: !ruby/object:Gem::Requirement
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
- - ".gitignore"
106
- - ".rspec"
107
- - ".rubocop.yml"
108
- - ".travis.yml"
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.2.0
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