unparser 0.1.10 → 0.1.11

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: 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: