zombie-killer 0.3 → 0.4

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