zombie-killer 0.3 → 0.4

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
- SHA1:
3
- metadata.gz: 0c386e33153b7b34e0563e9359b3aa5262ee316a
4
- data.tar.gz: 68e8158e89c4e04778126ef089dc47ee9db2b3f4
2
+ SHA256:
3
+ metadata.gz: 3e180c7784f993ba500fad7e16198be9e6478ba85d7c6817e701fa7b2ba85e7e
4
+ data.tar.gz: cabad90fad0492478d2ded00b62b1d45435cbc5750fcc1010a36483bac314710
5
5
  SHA512:
6
- metadata.gz: 6feac8928e83b35f14a31a1f355386a823f5472ceab730b3e60fd8c1aa9fac198a6a548e4e2ae5a5d119c580f2aef973a7c9ed1cfaf99156c6606c8142b4208d
7
- data.tar.gz: b5feb7a3335c43a141b620db9fb2c1ba647ab11a836b2022b9f9338d3e79e7fdd0562c188601baf16a27f1f7a43bc5f61fb7dbbce8cdf3eac48cd58ecd94db58
6
+ metadata.gz: c27fc0f8f743e91a93dc3c0edd041538c5933015f0c30ede75e537267e3baadce783c8e3d2491f063dad3b1c9d782e8045851e5371344b15e52e3bb4ef6b41d5
7
+ data.tar.gz: 61a29a2baee22c6190718405e436cc7889c3315cfcb1831864091ead8ae5d551637cc783a42b649167e7f314b926389e559aa00a1490a11f772a5d8715e222bf
data/NEWS.md ADDED
@@ -0,0 +1,18 @@
1
+ # News
2
+
3
+ ## unreleased
4
+
5
+ ## 0.4, 2018-11-02
6
+
7
+ - Added zk -e, EagerRewriter (don't care about niceness, replace all)
8
+ - Recover from parse errors by reverting to the original file
9
+ - Fixed reporting unhandled node types
10
+ - Handle keyword arguments, regex match
11
+
12
+ ## 0.3, 2014-12-02
13
+
14
+ - bin/count_method_calls added
15
+
16
+ ## 0.2, 2014-11-28
17
+
18
+ - first release as a gem
data/bin/zk CHANGED
@@ -12,6 +12,7 @@ Usage: zk [options] [FILES...]
12
12
  Arguments:
13
13
  FILES Files to operate on, patterns allowed [default: **/*.rb]
14
14
  Options:
15
+ -e, --eager Translate all zombies regardless of niceness.
15
16
  -u, --unsafe Translate even constructs not known to be safe.
16
17
  -s, --stats Also print statistics about node types.
17
18
  -v, --version Print version information and exit.
@@ -21,7 +22,7 @@ EOT
21
22
  begin
22
23
  options = Docopt.docopt(doc, help: true, version: ZombieKiller::VERSION)
23
24
 
24
- killer = ZombieKiller.new
25
+ killer = ZombieKiller.new(eager: options["--eager"])
25
26
 
26
27
  files = options["FILES"]
27
28
  files << "**/*.rb" if files.empty?
@@ -0,0 +1,56 @@
1
+ require "unparser"
2
+ require "set"
3
+
4
+ # Rewrite Zombies with their idiomatic replacements
5
+ class EagerRewriter < Parser::TreeRewriter
6
+ OPS = Parser::AST::Node.new(:const, [nil, :Ops])
7
+
8
+ INFIX = {
9
+ add: :+,
10
+ subtract: :-,
11
+ multiply: :*,
12
+ divide: :/,
13
+ modulo: :%,
14
+ bitwise_and: :&,
15
+ bitwise_or: :|,
16
+ bitwise_xor: :^,
17
+
18
+ less_than: :<,
19
+ less_or_equal: :<=,
20
+ greater_than: :>,
21
+ greater_or_equal: :>=
22
+ }.freeze
23
+
24
+ def s(name, *children)
25
+ Parser::AST::Node.new(name, children)
26
+ end
27
+
28
+ def replace_node(old_node, new_node)
29
+ source_range = old_node.loc.expression
30
+ replace(source_range, Unparser.unparse(new_node))
31
+ end
32
+
33
+ def on_send(node)
34
+ super
35
+ receiver, name, *args = *node
36
+ replacement = INFIX[name]
37
+ if receiver == OPS && replacement && args.size == 2
38
+ replace_node(node, s(:send, args[0], replacement, args[1]))
39
+ end
40
+ end
41
+
42
+ AS_OPS = Set.new [:+, :-]
43
+ def on_lvasgn(node)
44
+ super
45
+ vname1, value = *node
46
+ return unless value && value.type == :send
47
+ receiver, oname, *args = *value
48
+ if vname1 == lvar_vname2(receiver) && AS_OPS.include?(oname)
49
+ replace_node(node, s(:op_asgn, s(:lvasgn, vname1), oname, args[0]))
50
+ end
51
+ end
52
+
53
+ def lvar_vname2(receiver)
54
+ receiver.children.first if receiver && receiver.type == :lvar
55
+ end
56
+ end
@@ -1,17 +1,34 @@
1
1
  require "parser"
2
2
  require "parser/current"
3
3
 
4
+ require_relative "eager_rewriter"
4
5
  require_relative "rewriter"
5
6
 
7
+ # The main class called from the CLI
6
8
  class ZombieKiller
9
+ # @return [Boolean] use the EagerRewriter
10
+ attr_reader :eager
11
+
12
+ def initialize(eager: false)
13
+ @eager = eager
14
+ end
15
+
16
+ # @param code [String]
17
+ # @param filename [String]
7
18
  # @returns new string
8
19
  def kill_string(code, filename = "(inline code)", unsafe: false)
9
20
  fixed_point(code) do |c|
10
21
  parser = Parser::CurrentRuby.new
11
- rewriter = ZombieKillerRewriter.new(unsafe: unsafe)
22
+ rewriter = eager ? EagerRewriter.new : ZombieKillerRewriter.new(unsafe: unsafe)
12
23
  buffer = Parser::Source::Buffer.new(filename)
13
24
  buffer.source = c
14
- rewriter.rewrite(buffer, parser.parse(buffer))
25
+ ast = parser.parse(buffer)
26
+ if ast
27
+ rewriter.rewrite(buffer, ast)
28
+ else
29
+ puts "Parse error for '#{filename}', returning it unchanged"
30
+ return code
31
+ end
15
32
  end
16
33
  end
17
34
  alias_method :kill, :kill_string
@@ -21,6 +38,9 @@ class ZombieKiller
21
38
  new_string = kill_string(File.read(filename), filename, unsafe: unsafe)
22
39
 
23
40
  File.write(new_filename, new_string)
41
+ rescue
42
+ puts "While processing #{filename}"
43
+ raise
24
44
  end
25
45
 
26
46
  private
@@ -8,9 +8,20 @@ require_relative "variable_scope"
8
8
 
9
9
  # We have encountered code that does satisfy our simplifying assumptions,
10
10
  # translating it would not be correct.
11
- class TooComplexToTranslateError < Exception
11
+ class TooComplexToTranslateError < RuntimeError
12
12
  end
13
13
 
14
+ # An error related to a node
15
+ class NodeError < RuntimeError
16
+ attr_reader :node
17
+
18
+ def initialize(message, node)
19
+ @node = node
20
+ super(message)
21
+ end
22
+ end
23
+
24
+ # The main rewriter
14
25
  class ZombieKillerRewriter < Parser::Rewriter
15
26
  include Niceness
16
27
 
@@ -63,10 +74,14 @@ class ZombieKillerRewriter < Parser::Rewriter
63
74
  :if, # If and Unless
64
75
  :ivar, # Instance variable value
65
76
  :ivasgn, # Instance variable assignment
77
+ :kwarg, # Keyword argument, def m(a:)
66
78
  :kwbegin, # A variant of begin; for rescue and while_post
67
79
  :kwoptarg, # Keyword optional argument, def m(a: 1)
80
+ :kwrestarg, # Rest of keyword arguments, def m(**kwargs)
81
+ :kwsplat, # Hash **splatting
68
82
  :lvar, # Local variable value
69
83
  :lvasgn, # Local variable assignment
84
+ :match_with_lvasgn, # /regex/ =~ value
70
85
  :masgn, # Multiple assigment: a, b = c, d
71
86
  :mlhs, # Left-hand side of a multiple assigment: a, b = c, d
72
87
  :module, # Module body
@@ -101,8 +116,8 @@ class ZombieKillerRewriter < Parser::Rewriter
101
116
 
102
117
  def process(node)
103
118
  return if node.nil?
104
- if ! @unsafe
105
- oops(node, RuntimeError.new("Unknown node type #{node.type}")) unless
119
+ unless @unsafe
120
+ raise NodeError.new("Unknown node type #{node.type}", node) unless
106
121
  HANDLED_NODE_TYPES.include? node.type
107
122
  end
108
123
  super
@@ -117,8 +132,10 @@ class ZombieKillerRewriter < Parser::Rewriter
117
132
  scopes.with_new do
118
133
  block.call
119
134
  end
120
- rescue => e
121
- oops(node, e)
135
+ rescue NodeError => e
136
+ puts e
137
+ puts "Node exception @ #{e.node.loc.expression}"
138
+ puts "Offending node: #{e.node.inspect}"
122
139
  end
123
140
 
124
141
  def on_def(node)
@@ -276,12 +293,6 @@ class ZombieKillerRewriter < Parser::Rewriter
276
293
 
277
294
  private
278
295
 
279
- def oops(node, exception)
280
- puts "Node exception @ #{node.loc.expression}"
281
- puts "Offending node: #{node.inspect}"
282
- raise exception
283
- end
284
-
285
296
  def is_call(node, namespace, message)
286
297
  n_receiver, n_message = *node
287
298
  n_receiver && n_receiver.type == :const &&
@@ -1,3 +1,3 @@
1
1
  class ZombieKiller
2
- VERSION = "0.3"
2
+ VERSION = "0.4".freeze
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,25 @@
1
- $:.unshift File.expand_path("../../lib", __FILE__)
1
+ if ENV["COVERAGE"]
2
+ require "simplecov"
3
+ SimpleCov.start
4
+
5
+ top_location = File.expand_path("../../", __FILE__)
6
+ # track all ruby files under lib
7
+ SimpleCov.track_files("#{top_location}/lib/**/*.rb")
8
+
9
+ # use coveralls for on-line code coverage reporting at Travis CI
10
+ if ENV["TRAVIS"]
11
+ require "coveralls"
12
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new [
13
+ SimpleCov::Formatter::HTMLFormatter,
14
+ Coveralls::SimpleCov::Formatter
15
+ ]
16
+ end
17
+ end
18
+
19
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
20
  require "zombie_killer"
3
21
 
4
22
  def cleanup(s)
5
23
  s.split("\n").reject { |l| l =~ /^\s*$/ }.first =~ /^(\s*)/
6
- s.gsub(Regexp.new("^#{$1}"), "")[0..-2]
24
+ s.gsub(Regexp.new("^#{Regexp.last_match(1)}"), "")[0..-2]
7
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zombie-killer
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.3'
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Vidner
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-12-02 00:00:00.000000000 Z
12
+ date: 2018-11-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: docopt
@@ -29,9 +29,9 @@ dependencies:
29
29
  name: parser
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">"
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 2.2.0.pre.5
34
+ version: 2.2.0
35
35
  - - "<"
36
36
  - !ruby/object:Gem::Version
37
37
  version: '3'
@@ -39,9 +39,9 @@ dependencies:
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  requirements:
42
- - - ">"
42
+ - - ">="
43
43
  - !ruby/object:Gem::Version
44
- version: 2.2.0.pre.5
44
+ version: 2.2.0
45
45
  - - "<"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3'
@@ -59,6 +59,40 @@ dependencies:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: coveralls
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: rake
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '10'
83
+ - - "<"
84
+ - !ruby/object:Gem::Version
85
+ version: '999'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '10'
93
+ - - "<"
94
+ - !ruby/object:Gem::Version
95
+ version: '999'
62
96
  - !ruby/object:Gem::Dependency
63
97
  name: rspec
64
98
  requirement: !ruby/object:Gem::Requirement
@@ -93,6 +127,20 @@ dependencies:
93
127
  - - "~>"
94
128
  - !ruby/object:Gem::Version
95
129
  version: '3'
130
+ - !ruby/object:Gem::Dependency
131
+ name: simplecov
132
+ requirement: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ type: :development
138
+ prerelease: false
139
+ version_requirements: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
96
144
  description: Translate YCP-like library calls (Ops.*, Builtins.*) to idiomatic Ruby
97
145
  email:
98
146
  - martin@vidner.net
@@ -104,11 +152,13 @@ extensions: []
104
152
  extra_rdoc_files: []
105
153
  files:
106
154
  - LICENSE
155
+ - NEWS.md
107
156
  - README.md
108
157
  - bin/count_method_calls
109
158
  - bin/zk
110
159
  - lib/zombie_killer.rb
111
160
  - lib/zombie_killer/code_histogram.rb
161
+ - lib/zombie_killer/eager_rewriter.rb
112
162
  - lib/zombie_killer/killer.rb
113
163
  - lib/zombie_killer/niceness.rb
114
164
  - lib/zombie_killer/node_type_counter.rb
@@ -139,9 +189,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
189
  version: '0'
140
190
  requirements: []
141
191
  rubyforge_project:
142
- rubygems_version: 2.2.2
192
+ rubygems_version: 2.7.3
143
193
  signing_key:
144
194
  specification_version: 4
145
195
  summary: Resocialize YCP Zombies
146
196
  test_files: []
147
- has_rdoc: