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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d8979355b8d41bbbc8c4f0a547f68e92cef86b17
4
- data.tar.gz: bc38d9940581f4172e381617cd127d8e2e862994
3
+ metadata.gz: 88f1db209b504179ee9762641fc8455a0a3f410a
4
+ data.tar.gz: 0b29350be7f0b56188f05247beb0f3258e53ffb1
5
5
  SHA512:
6
- metadata.gz: 0f78c4e7669975915d24d7a75bcdfb1481745a01c8fbad1f0264137d55b5630d1e87173000cb86f3c2f70869dfdb5ad880a65dc5cefeea1db1d5d6895ee9ff84
7
- data.tar.gz: da8af5b60c5f6ce8ce759838668d57127b29e9f1277f99ca90c11f45ed6169517bc6853b1f5e47d3d74958c2c112aefa8a747507f36056e69d30ad99f17e29bd
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: ->(*args) { block.call(*args, Builder.new) }
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, @replacement = variable_name, replacement
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, rewritten = match.root, replacement.substitute(match.substitution)
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
@@ -3,7 +3,7 @@ require "metamorpher/terms/term"
3
3
  module Metamorpher
4
4
  module Terms
5
5
  class Derived < Term
6
- attributes :base, :derivation
6
+ attributes :base, derivation: -> (t) { t }
7
7
 
8
8
  def inspect
9
9
  "[#{base.map(&:upcase).join(', ')}] -> ..."
@@ -1,3 +1,3 @@
1
1
  module Metamorpher
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
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.3"
23
+ spec.add_runtime_dependency "unparser", "~> 0.2.4"
24
24
 
25
- spec.add_development_dependency "bundler", "~> 1.9.4"
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.30.1"
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
@@ -3,7 +3,7 @@ require "metamorpher/terms/literal"
3
3
  require "metamorpher/terms/derived"
4
4
 
5
5
  module Metamorpher
6
- module Terms
6
+ module Terms # rubocop:disable Metrics/ModuleLength
7
7
  describe Variable do
8
8
  let(:root) do
9
9
  Literal.new(
@@ -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.1
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-05-12 00:00:00.000000000 Z
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.3
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.3
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.9.4
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.9.4
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.30.1
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.30.1
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: