metamorpher 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -0
- data/RELEASES.md +4 -0
- data/lib/metamorpher/builders/ast/derivation_builder.rb +11 -2
- data/lib/metamorpher/builders/ruby/variable_replacement_visitor.rb +2 -1
- data/lib/metamorpher/rewriter/rule.rb +9 -1
- data/lib/metamorpher/terms/derived.rb +1 -1
- data/lib/metamorpher/version.rb +1 -1
- data/metamorpher.gemspec +3 -3
- data/spec/integration/ast/rewriter_spec.rb +50 -0
- data/spec/support/shared_examples/shared_examples_for_derivation_builders.rb +12 -5
- data/spec/unit/matcher/matching_spec.rb +1 -1
- data/spec/unit/rewriter/substitution_spec.rb +10 -0
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88f1db209b504179ee9762641fc8455a0a3f410a
|
4
|
+
data.tar.gz: 0b29350be7f0b56188f05247beb0f3258e53ffb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8739bffe9edec1e31138a85b925d2de93dde9ba421a4c088b6bdc6916bd691f2d93375b765818c7974e823a74172a64a4096dcc919e18bd724ef7997ce10d47a
|
7
|
+
data.tar.gz: f6777b8c3e2de91a1d780d5d4441bedf4dd8febac23c19375cbe7184895368b5dddc4713b2038dc858ffe26a2c4121e16ceec3c2dea95f6a78e4704c46ee0797
|
data/README.md
CHANGED
@@ -373,6 +373,32 @@ builder.derivation! :key, :value do |key, value|
|
|
373
373
|
end
|
374
374
|
```
|
375
375
|
|
376
|
+
When deriving a variable's value without changing it, there's no need to supply a block:
|
377
|
+
|
378
|
+
```ruby
|
379
|
+
builder.derivation! :value
|
380
|
+
# builder.derivation! :value { |value| value }
|
381
|
+
```
|
382
|
+
|
383
|
+
To obtain the entire match during a derivation, use the special variable `&`:
|
384
|
+
|
385
|
+
```ruby
|
386
|
+
class ReverseVariables
|
387
|
+
include Metamorpher::Rewriter
|
388
|
+
include Metamorpher::Builders::AST
|
389
|
+
|
390
|
+
def pattern
|
391
|
+
builder.literal!(:send, nil, builder.VAR)
|
392
|
+
end
|
393
|
+
|
394
|
+
def replacement
|
395
|
+
builder.derivation! :& do |match|
|
396
|
+
builder.literal(:send, match, :reverse)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
```
|
401
|
+
|
376
402
|
## Practicalities
|
377
403
|
|
378
404
|
Metamorpher provides modules that can be used to simplify the transformation of Ruby programs. This section describes how to build metamorpher terms that represent Ruby programs, and how to refactor Ruby programs. [Matchers](#matchers) and [Rewriters](#rewriters) can be used to manipulate Ruby programs too.
|
data/RELEASES.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
## v0.2.2 (4 June 2015)
|
4
|
+
* Provide whole match special variable (&) for derivations
|
5
|
+
* Provide sensible default logic (derive the value of their first argument) for derivations
|
6
|
+
|
3
7
|
## v0.2.1 (12 May 2015)
|
4
8
|
* Provide support for term sets, which make it possible to match (or rewrite to) multiple expressions at once
|
5
9
|
|
@@ -7,13 +7,22 @@ module Metamorpher
|
|
7
7
|
class DerivationBuilder
|
8
8
|
def derivation!(*base, &block)
|
9
9
|
fail ArgumentError, "wrong number of arguments (0)" if base.empty?
|
10
|
-
fail ArgumentError, "a block must be provided" if block.nil?
|
11
10
|
|
12
11
|
Terms::Derived.new(
|
13
12
|
base: base,
|
14
|
-
derivation:
|
13
|
+
derivation: derivation_strategy(block)
|
15
14
|
)
|
16
15
|
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def derivation_strategy(block)
|
20
|
+
if block.nil?
|
21
|
+
->(*args) { args.first }
|
22
|
+
else
|
23
|
+
->(*args) { block.call(*args, Builder.new) }
|
24
|
+
end
|
25
|
+
end
|
17
26
|
end
|
18
27
|
end
|
19
28
|
end
|
@@ -5,7 +5,8 @@ module Metamorpher
|
|
5
5
|
attr_accessor :variable_name, :replacement
|
6
6
|
|
7
7
|
def initialize(variable_name, replacement)
|
8
|
-
@variable_name
|
8
|
+
@variable_name = variable_name
|
9
|
+
@replacement = replacement
|
9
10
|
end
|
10
11
|
|
11
12
|
def visit_literal(literal)
|
@@ -22,11 +22,19 @@ module Metamorpher
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def rewrite(ast, match, &block)
|
25
|
-
original
|
25
|
+
original = match.root
|
26
|
+
substitution = substitution_with_special_values(match)
|
27
|
+
rewritten = replacement.substitute(substitution)
|
26
28
|
block.call(original, rewritten) if block
|
27
29
|
ast.replace(original.path, rewritten)
|
28
30
|
end
|
29
31
|
|
32
|
+
def substitution_with_special_values(match)
|
33
|
+
match.substitution.dup.tap do |substitution|
|
34
|
+
substitution[:&] = match.root.dup # add the "whole match" special variable (&)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
30
38
|
def matches_for(ast)
|
31
39
|
traverser.traverse(ast)
|
32
40
|
.lazy # only compute the next match when needed
|
data/lib/metamorpher/version.rb
CHANGED
data/metamorpher.gemspec
CHANGED
@@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "attributable", "~> 0.1.0"
|
22
22
|
spec.add_runtime_dependency "parser", "~> 2.2.2"
|
23
|
-
spec.add_runtime_dependency "unparser", "~> 0.2.
|
23
|
+
spec.add_runtime_dependency "unparser", "~> 0.2.4"
|
24
24
|
|
25
|
-
spec.add_development_dependency "bundler", "~> 1.
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.10.2"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.4.2"
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.2.0"
|
28
28
|
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4.6"
|
29
|
-
spec.add_development_dependency "rubocop", "~> 0.
|
29
|
+
spec.add_development_dependency "rubocop", "~> 0.31.0"
|
30
30
|
end
|
@@ -162,6 +162,32 @@ describe "Rewriting" do
|
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
165
|
+
describe "from entire value" do
|
166
|
+
class Inverter
|
167
|
+
include Metamorpher::Rewriter
|
168
|
+
include Metamorpher::Builders::AST
|
169
|
+
|
170
|
+
def pattern
|
171
|
+
builder.true
|
172
|
+
end
|
173
|
+
|
174
|
+
def replacement
|
175
|
+
builder.derivation!(:&) do |matched|
|
176
|
+
builder.literal!(:not, matched)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
subject { Inverter.new }
|
182
|
+
|
183
|
+
it "should rewrite yielding the entire match to the derivation logic" do
|
184
|
+
expression = builder.literal! :true
|
185
|
+
reduced = builder.literal!(:not, :true)
|
186
|
+
|
187
|
+
expect(subject.reduce(expression)).to eq(reduced)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
165
191
|
describe "to several alternatives" do
|
166
192
|
class FlexiblePluraliseRewriterInner
|
167
193
|
include Metamorpher::Rewriter
|
@@ -190,5 +216,29 @@ describe "Rewriting" do
|
|
190
216
|
expect(subject.reduce(expression)).to eq(reduced)
|
191
217
|
end
|
192
218
|
end
|
219
|
+
|
220
|
+
describe "using implicit derivation" do
|
221
|
+
class KeyExtractor
|
222
|
+
include Metamorpher::Rewriter
|
223
|
+
include Metamorpher::Builders::AST
|
224
|
+
|
225
|
+
def pattern
|
226
|
+
builder.literal!(:"=>", builder.KEY, builder.VALUE)
|
227
|
+
end
|
228
|
+
|
229
|
+
def replacement
|
230
|
+
builder.derivation!(:key)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
subject { KeyExtractor.new }
|
235
|
+
|
236
|
+
it "should rewrite using the implicit derivation" do
|
237
|
+
expression = builder.literal! :"=>", :foo, :bar
|
238
|
+
reduced = builder.literal! :foo
|
239
|
+
|
240
|
+
expect(subject.reduce(expression)).to eq(reduced)
|
241
|
+
end
|
242
|
+
end
|
193
243
|
end
|
194
244
|
end
|
@@ -14,11 +14,22 @@ module Metamorpher
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should capture all arguments as the base" do
|
17
|
-
built = subject.derivation!(:key, :value)
|
17
|
+
built = subject.derivation!(:key, :value)
|
18
18
|
|
19
19
|
expect(built.base).to eq([:key, :value])
|
20
20
|
end
|
21
21
|
|
22
|
+
it "should derive the first argument if no block is passed" do
|
23
|
+
built = subject.derivation!(:key, :value)
|
24
|
+
|
25
|
+
derived = built.derivation.call(
|
26
|
+
Literal.new(name: :dog),
|
27
|
+
Literal.new(name: :lassie)
|
28
|
+
)
|
29
|
+
|
30
|
+
expect(derived).to eq(Literal.new(name: :dog))
|
31
|
+
end
|
32
|
+
|
22
33
|
it "should provide a builder for use in the block" do
|
23
34
|
built = subject.derivation!(:key, :value) do |key, value, builder|
|
24
35
|
builder.pair(key, value)
|
@@ -43,10 +54,6 @@ module Metamorpher
|
|
43
54
|
it "should raise if no arguments are passed" do
|
44
55
|
expect { subject.derivation! { nil } }.to raise_error(ArgumentError)
|
45
56
|
end
|
46
|
-
|
47
|
-
it "should raise if no block is passed" do
|
48
|
-
expect { subject.derivation!(:method) }.to raise_error(ArgumentError)
|
49
|
-
end
|
50
57
|
end
|
51
58
|
end
|
52
59
|
end
|
@@ -36,6 +36,16 @@ module Metamorpher
|
|
36
36
|
it "should raise if the substitution contains no value for variable's name" do
|
37
37
|
expect { subject.substitute({}) }.to raise_error(Rewriter::SubstitutionError)
|
38
38
|
end
|
39
|
+
|
40
|
+
context "default derivations" do
|
41
|
+
it "should be the identity function for a single parameter" do
|
42
|
+
subject = Derived.new(base: [:type])
|
43
|
+
literal = Literal.new(name: :foo)
|
44
|
+
substitution = { type: literal }
|
45
|
+
|
46
|
+
expect(subject.substitute(substitution)).to eq(literal)
|
47
|
+
end
|
48
|
+
end
|
39
49
|
end
|
40
50
|
|
41
51
|
describe Literal do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metamorpher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Louis Rose
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attributable
|
@@ -44,28 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.2.
|
47
|
+
version: 0.2.4
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.2.
|
54
|
+
version: 0.2.4
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 1.
|
61
|
+
version: 1.10.2
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 1.
|
68
|
+
version: 1.10.2
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.
|
117
|
+
version: 0.31.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
124
|
+
version: 0.31.0
|
125
125
|
description: Provides structures that support program transformations, such as refactoring
|
126
126
|
or program mutation.
|
127
127
|
email:
|