unparser 0.1.10 → 0.1.11

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: 034e53fe83f3cb6b5d1c99e64f35b73d505812bf
4
- data.tar.gz: 261ece646cfa726f17d70c2d82a44f837d6155b2
3
+ metadata.gz: e21010b4e759db5c1502593760f8480381ed63fd
4
+ data.tar.gz: c6549debc54796bf1151ee522d85caef6b6db7a2
5
5
  SHA512:
6
- metadata.gz: ff483fa78c83e951ff869033f025238d75dbbba20a747952a32ce034c3a88ee346a0aeab555053fb27b94a440a38b4a9a18b036d672b7e64545fec4d0bec788b
7
- data.tar.gz: db9c2c31f83b67d7bf70893c774a53b764a4e02ff7f096555fe42c88ba1ee504e962ff6e0e4e20be3febfa08ad09884a0b0e363bab05034127aef404af552064
6
+ metadata.gz: 342af109c4ede135af5f555073dcb2b10c1bdef9b1873598e5fc84dd5c57d517e8d6d5f51c4a856695f10fd0ead95ab68a19acd060c8acda82564bf95a5de2e0
7
+ data.tar.gz: 9abf7e144000af5631f23440abc8557210a67dbc935793ab3add786ba838ae77f19c5f5a428932f92c6a596c6892b68d7051c2dbd0a5afc32c07d4f1d91ff74c
data/Changelog.md CHANGED
@@ -1,3 +1,7 @@
1
+ # v0.1.11 2014-04-11
2
+
3
+ * Fix performance on local variable scope inspection
4
+
1
5
  # v0.1.10 2014-04-06
2
6
 
3
7
  * Fix emit of inline rescues in combination with control flow keywords.
data/Gemfile CHANGED
@@ -3,7 +3,5 @@ source 'https://rubygems.org'
3
3
 
4
4
  gemspec
5
5
 
6
- gem 'morpher', git: 'https://github.com/mbj/morpher.git'
7
-
8
6
  gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
9
7
  eval_gemfile 'Gemfile.devtools'
data/Guardfile CHANGED
@@ -1,10 +1,12 @@
1
1
  # encoding: utf-8
2
2
 
3
+ ENV['GUARD'] = '1'
4
+
3
5
  guard :bundler do
4
6
  watch('Gemfile')
5
7
  end
6
8
 
7
- guard :rspec, :all_on_start => false, :all_after_pass => false, :cli => '--fail-fast --seed 1' do
9
+ guard :rspec, :all_on_start => false, :all_after_pass => false, :cmd => 'bundle exec rspec --fail-fast --seed 1' do
8
10
  # run all specs if the spec_helper or supporting files files are modified
9
11
  watch('spec/spec_helper.rb') { 'spec/unit' }
10
12
  watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec/unit' }
data/config/flay.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 13
3
- total_score: 720
3
+ total_score: 718
data/lib/unparser/ast.rb CHANGED
@@ -7,73 +7,46 @@ module Unparser
7
7
  FIRST_CHILD = ->(node) { node.children.first }.freeze
8
8
  TAUTOLOGY = ->(node) { true }.freeze
9
9
 
10
- # Test if local variable was first at given assignment
10
+ RESET_NODES = [:module, :class, :sclass, :def, :defs].freeze
11
+ INHERIT_NODES = [:block].freeze
12
+ CLOSE_NODES = (RESET_NODES + INHERIT_NODES).freeze
13
+
14
+ # Nodes that assign a local variable
15
+ #
16
+ # FIXME: Kwargs are missing.
17
+ #
18
+ ASSIGN_NODES = [:lvasgn, :arg, :optarg, :restarg].freeze
19
+
20
+ # Test for local variable inherited scope reset
11
21
  #
12
- # @param [Parser::AST::Node] root
13
- # @param [Parser::AST::Node] assignment
22
+ # @param [Parser::AST::Node] node
14
23
  #
15
24
  # @return [true]
16
- # if local variable was firstly introduced in body
25
+ # if local variable scope must NOT be reset
17
26
  #
18
27
  # @return [false]
19
28
  # otherwise
20
29
  #
21
30
  # @api private
22
31
  #
23
- def self.first_assignment?(root, assignment)
24
- name = assignment.children.first
25
- AST::LocalVariableScope.each(root) do |node, current, before|
26
- if node.equal?(assignment) && current.include?(name) && !before.include?(name)
27
- return true
28
- end
29
- end
30
-
31
- false
32
+ def self.not_close_scope?(node)
33
+ !CLOSE_NODES.include?(node.type)
32
34
  end
33
35
 
34
- # Test if local variable is defined for given node
36
+ # Test for local variable scope reset
35
37
  #
36
- # @param [Parser::AST::Node] root
37
38
  # @param [Parser::AST::Node] node
38
- # @param [Symbol] name
39
39
  #
40
40
  # @return [true]
41
- # if local variable is defined
41
+ # if local variable scope must NOT be reset
42
42
  #
43
43
  # @return [false]
44
44
  # otherwise
45
45
  #
46
46
  # @api private
47
47
  #
48
- def self.local_variable_defined_for_node?(root, node, name)
49
- AST::LocalVariableScope.each(root) do |child, current, before|
50
- if child.equal?(node) && current.include?(name)
51
- return true
52
- end
53
- end
54
-
55
- false
56
- end
57
-
58
- # Test if local variables where first assigned in body and read by conditional
59
- #
60
- # @param [Parser::AST::Node] root
61
- # @param [Parser::AST::Node] conditional
62
- # @param [Parser::AST::Node] body
63
- #
64
- # @api private
65
- #
66
- def self.first_assignment_in_body_and_used_in_condition?(root, body, condition)
67
- condition_reads = local_variables_read_in_scope(condition)
68
-
69
- candidates = AST.local_variable_assignments_in_scope(body).select do |node|
70
- name = node.children.first
71
- condition_reads.include?(name)
72
- end
73
-
74
- candidates.any? do |node|
75
- first_assignment?(root, node)
76
- end
48
+ def self.not_reset_scope?(node)
49
+ !RESET_NODES.include?(node.type)
77
50
  end
78
51
 
79
52
  # Return local variables that get assigned in scope
@@ -84,11 +57,11 @@ module Unparser
84
57
  #
85
58
  # @api private
86
59
  #
87
- def self.local_variable_assignments_in_scope(node)
60
+ def self.local_variable_assignments(node)
88
61
  Enumerator.new(
89
62
  node,
90
- LocalVariableScope.method(:not_reset_scope?)
91
- ).types(LocalVariableScope::ASSIGN_NODES)
63
+ method(:not_reset_scope?)
64
+ ).types(ASSIGN_NODES)
92
65
  end
93
66
 
94
67
  # Return local variables read
@@ -99,10 +72,10 @@ module Unparser
99
72
  #
100
73
  # @api private
101
74
  #
102
- def self.local_variables_read_in_scope(node)
75
+ def self.local_variable_reads(node)
103
76
  Enumerator.new(
104
77
  node,
105
- LocalVariableScope.method(:not_close_scope?)
78
+ method(:not_close_scope?)
106
79
  ).type(:lvar).map(&FIRST_CHILD).to_set
107
80
  end
108
81
 
@@ -2,73 +2,137 @@
2
2
 
3
3
  module Unparser
4
4
  module AST
5
- # Local variable scope enumerator
6
- class LocalVariableScope
7
- include Enumerable
8
5
 
9
- RESET_NODES = [:module, :class, :sclass, :def, :defs].freeze
10
- INHERIT_NODES = [:block].freeze
11
- CLOSE_NODES = (RESET_NODES + INHERIT_NODES).freeze
12
-
13
- # Nodes that assign a local variable
14
- #
15
- # FIXME: Kwargs are missing.
16
- #
17
- ASSIGN_NODES = [:lvasgn, :arg, :optarg, :restarg].freeze
6
+ # Calculated local variable scope for a given node
7
+ class LocalVariableScope
8
+ include Enumerable, Adamantium, Concord.new(:node)
18
9
 
19
10
  # Initialize object
20
11
  #
12
+ # @param [Parser::AST::Node] node
13
+ #
21
14
  # @return [undefined]
22
15
  #
23
16
  # @api private
24
17
  #
25
- def initialize
26
- @stack = [Set.new]
18
+ def initialize(node)
19
+ items = []
20
+ LocalVariableScopeEnumerator.each(node) do |*scope|
21
+ items << scope
22
+ end
23
+ @items = items
24
+ @node = node
27
25
  end
28
26
 
29
- # Enumerate each node with its local variable scope
27
+ # Test if local variable was first at given assignment
30
28
  #
31
29
  # @param [Parser::AST::Node] node
32
30
  #
33
- # @return [self]
31
+ # @return [true]
32
+ # if local variable was firstly introduced in body
33
+ #
34
+ # @return [false]
35
+ # otherwise
34
36
  #
35
37
  # @api private
36
38
  #
37
- def self.each(node, &block)
38
- new.each(node, &block)
39
- self
39
+ def first_assignment?(node)
40
+ name = node.children.first
41
+ match(node) do |current, before|
42
+ current.include?(name) && !before.include?(name)
43
+ end
40
44
  end
41
45
 
42
- # Test for local variable inherited scope reset
46
+ # Test if local variable is defined for given node
43
47
  #
44
48
  # @param [Parser::AST::Node] node
49
+ # @param [Symbol] name
45
50
  #
46
51
  # @return [true]
47
- # if local variable scope must NOT be reset
52
+ # if local variable is defined
48
53
  #
49
54
  # @return [false]
50
55
  # otherwise
51
56
  #
52
57
  # @api private
53
58
  #
54
- def self.not_close_scope?(node)
55
- !CLOSE_NODES.include?(node.type)
59
+ def local_variable_defined_for_node?(node, name)
60
+ match(node) do |current|
61
+ current.include?(name)
62
+ end
63
+ end
64
+
65
+ # Test if local variables where first assigned in body and read by conditional
66
+ #
67
+ # @param [Parser::AST::Node] conditional
68
+ # @param [Parser::AST::Node] body
69
+ #
70
+ # @api private
71
+ #
72
+ def first_assignment_in_body_and_used_in_condition?(body, condition)
73
+ condition_reads = AST.local_variable_reads(condition)
74
+
75
+ candidates = AST.local_variable_assignments(body).select do |node|
76
+ name = node.children.first
77
+ condition_reads.include?(name)
78
+ end
79
+
80
+ candidates.any? do |node|
81
+ first_assignment?(node)
82
+ end
56
83
  end
57
84
 
58
- # Test for local variable scope reset
85
+ private
86
+
87
+ # Match node
59
88
  #
60
89
  # @param [Parser::AST::Node] node
90
+ # if block given
61
91
  #
62
92
  # @return [true]
63
- # if local variable scope must NOT be reset
93
+ # if found an matched
64
94
  #
65
95
  # @return [false]
66
96
  # otherwise
67
97
  #
68
98
  # @api private
69
99
  #
70
- def self.not_reset_scope?(node)
71
- !RESET_NODES.include?(node.type)
100
+ def match(neddle)
101
+ @items.each do |node, current, before|
102
+ if node.equal?(neddle)
103
+ return yield(current, before)
104
+ end
105
+ end
106
+ false
107
+ end
108
+
109
+ end # LocalVariableScope
110
+
111
+ # Local variable scope enumerator
112
+ class LocalVariableScopeEnumerator
113
+ include Enumerable
114
+
115
+ # Initialize object
116
+ #
117
+ # @return [undefined]
118
+ #
119
+ # @api private
120
+ #
121
+ def initialize
122
+ @stack = [Set.new]
123
+ end
124
+
125
+ # Enumerate each node with its local variable scope
126
+ #
127
+ # @param [Parser::AST::Node] node
128
+ #
129
+ # @return [self]
130
+ #
131
+ # @api private
132
+ #
133
+ def self.each(node, &block)
134
+ new.each(node, &block)
135
+ self
72
136
  end
73
137
 
74
138
  # Enumerate local variable scope scope
@@ -109,7 +173,7 @@ module Unparser
109
173
  def visit(node, &block)
110
174
  before = current.dup
111
175
  enter(node)
112
- yield node, current, before
176
+ yield node, current.dup, before
113
177
  node.children.each do |child|
114
178
  if child.kind_of?(Parser::AST::Node)
115
179
  visit(child, &block)
@@ -193,6 +257,6 @@ module Unparser
193
257
  @stack.pop
194
258
  end
195
259
 
196
- end # LocalVariableScope
260
+ end # LocalVariableScopeEnumerator
197
261
  end # AST
198
262
  end # Unparser
@@ -15,8 +15,14 @@ module Unparser
15
15
  #
16
16
  # @api private
17
17
  #
18
- def local_variable_root
19
- node
18
+ def local_variable_scope
19
+ AST::LocalVariableScope.new(node)
20
+ end
21
+
22
+ def self.included(descendant)
23
+ descendant.class_eval do
24
+ memoize :local_variable_scope
25
+ end
20
26
  end
21
27
 
22
28
  end
@@ -27,8 +33,8 @@ module Unparser
27
33
  #
28
34
  # @api private
29
35
  #
30
- def local_variable_root
31
- parent.local_variable_root
36
+ def local_variable_scope
37
+ parent.local_variable_scope
32
38
  end
33
39
 
34
40
  # Registry for node emitters
@@ -40,7 +40,7 @@ module Unparser
40
40
 
41
41
  body = if_branch || else_branch
42
42
 
43
- AST.first_assignment_in_body_and_used_in_condition?(local_variable_root, body, condition)
43
+ local_variable_scope.first_assignment_in_body_and_used_in_condition?(body, condition)
44
44
  end
45
45
 
46
46
  # Emit in postcondition style
@@ -70,7 +70,7 @@ module Unparser
70
70
  #
71
71
  def postcontrol?
72
72
  return false unless body
73
- AST.first_assignment_in_body_and_used_in_condition?(local_variable_root, body, condition)
73
+ local_variable_scope.first_assignment_in_body_and_used_in_condition?(body, condition)
74
74
  end
75
75
 
76
76
  # Emit keyword
@@ -229,7 +229,7 @@ module Unparser
229
229
  # @api private
230
230
  #
231
231
  def local_variable_clash?
232
- AST.local_variable_defined_for_node?(local_variable_root, node, selector)
232
+ local_variable_scope.local_variable_defined_for_node?(node, selector)
233
233
  end
234
234
 
235
235
  end # Send
@@ -7,6 +7,9 @@ describe 'Unparser on ruby corpus' do
7
7
  if RUBY_VERSION == '1.9.3'
8
8
  pending 'Corpus test not active for 1.9.3 because of limitations in encoding singalling, see Readme'
9
9
  end
10
+ if ENV['GUARD']
11
+ pending 'Do not execute corpus spec under guard'
12
+ end
10
13
  end
11
14
  ROOT = Pathname.new(__FILE__).parent.parent.parent.parent
12
15
 
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.10'
5
+ gem.version = '0.1.11'
6
6
 
7
7
  gem.authors = ['Markus Schirp']
8
8
  gem.email = 'mbj@schir-dso.com'
@@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.required_ruby_version
21
21
 
22
- gem.add_dependency('parser', '~> 2.1.7')
22
+ gem.add_dependency('parser', '~> 2.1')
23
23
  gem.add_dependency('procto', '~> 0.0.2')
24
24
  gem.add_dependency('concord', '~> 0.1.4')
25
25
  gem.add_dependency('adamantium', '~> 0.2.0')
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.10
4
+ version: 0.1.11
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-04-06 00:00:00.000000000 Z
11
+ date: 2014-04-11 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
15
+ requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 2.1.7
20
- requirement: !ruby/object:Gem::Requirement
19
+ version: '2.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
21
23
  requirements:
22
24
  - - ~>
23
25
  - !ruby/object:Gem::Version
24
- version: 2.1.7
25
- prerelease: false
26
- type: :runtime
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: procto
29
- version_requirements: !ruby/object:Gem::Requirement
29
+ requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.0.2
34
- requirement: !ruby/object:Gem::Requirement
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
35
37
  requirements:
36
38
  - - ~>
37
39
  - !ruby/object:Gem::Version
38
40
  version: 0.0.2
39
- prerelease: false
40
- type: :runtime
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: concord
43
- version_requirements: !ruby/object:Gem::Requirement
43
+ requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: 0.1.4
48
- requirement: !ruby/object:Gem::Requirement
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
49
51
  requirements:
50
52
  - - ~>
51
53
  - !ruby/object:Gem::Version
52
54
  version: 0.1.4
53
- prerelease: false
54
- type: :runtime
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: adamantium
57
- version_requirements: !ruby/object:Gem::Requirement
57
+ requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: 0.2.0
62
- requirement: !ruby/object:Gem::Requirement
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
63
65
  requirements:
64
66
  - - ~>
65
67
  - !ruby/object:Gem::Version
66
68
  version: 0.2.0
67
- prerelease: false
68
- type: :runtime
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: equalizer
71
- version_requirements: !ruby/object:Gem::Requirement
71
+ requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ~>
74
74
  - !ruby/object:Gem::Version
75
75
  version: 0.0.9
76
- requirement: !ruby/object:Gem::Requirement
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
77
79
  requirements:
78
80
  - - ~>
79
81
  - !ruby/object:Gem::Version
80
82
  version: 0.0.9
81
- prerelease: false
82
- type: :runtime
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: abstract_type
85
- version_requirements: !ruby/object:Gem::Requirement
85
+ requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ~>
88
88
  - !ruby/object:Gem::Version
89
89
  version: 0.0.7
90
- requirement: !ruby/object:Gem::Requirement
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
91
93
  requirements:
92
94
  - - ~>
93
95
  - !ruby/object:Gem::Version
94
96
  version: 0.0.7
95
- prerelease: false
96
- type: :runtime
97
97
  description: Generate equivalent source for parser gem AST nodes
98
98
  email: mbj@schir-dso.com
99
99
  executables:
@@ -209,7 +209,7 @@ homepage: http://github.com/mbj/unparser
209
209
  licenses:
210
210
  - MIT
211
211
  metadata: {}
212
- post_install_message:
212
+ post_install_message:
213
213
  rdoc_options: []
214
214
  require_paths:
215
215
  - lib
@@ -224,9 +224,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
224
  - !ruby/object:Gem::Version
225
225
  version: '0'
226
226
  requirements: []
227
- rubyforge_project:
228
- rubygems_version: 2.1.9
229
- signing_key:
227
+ rubyforge_project:
228
+ rubygems_version: 2.0.14
229
+ signing_key:
230
230
  specification_version: 4
231
231
  summary: Generate equivalent source for parser gem AST nodes
232
232
  test_files:
@@ -247,3 +247,4 @@ test_files:
247
247
  - spec/unit/unparser/comments/take_eol_comments_spec.rb
248
248
  - spec/unit/unparser/emitter/class_methods/handle_spec.rb
249
249
  - spec/unit/unparser_spec.rb
250
+ has_rdoc: