ruby_transform 0.1.1
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.
- data/Gemfile +3 -0
- data/Gemfile.lock +40 -0
- data/LICENSE +20 -0
- data/README.rdoc +21 -0
- data/Rakefile +14 -0
- data/TODO.rdoc +4 -0
- data/bin/rubytransform +6 -0
- data/lib/ruby_transform/registry.rb +38 -0
- data/lib/ruby_transform/runner.rb +8 -0
- data/lib/ruby_transform/transform_helpers.rb +7 -0
- data/lib/ruby_transform/transformer.rb +18 -0
- data/lib/ruby_transform/transformers/block_method_to_procifier.rb +47 -0
- data/lib/ruby_transform/transformers/clear_explicit_returns.rb +49 -0
- data/lib/ruby_transform/transformers/composite.rb +28 -0
- data/lib/ruby_transform/transformers/custom.rb +27 -0
- data/lib/ruby_transform/transformers/eachifier.rb +43 -0
- data/lib/ruby_transform/transformers/symbol_names.rb +68 -0
- data/lib/ruby_transform/transformers/tapifier.rb +77 -0
- data/lib/ruby_transform/version.rb +3 -0
- data/lib/ruby_transform.rb +8 -0
- data/spec/matchers/should_transform_to.rb +25 -0
- data/spec/ruby_transform/registry_spec.rb +49 -0
- data/spec/ruby_transform/transformer_spec.rb +27 -0
- data/spec/ruby_transform/transformers/block_method_to_procifier_spec.rb +20 -0
- data/spec/ruby_transform/transformers/clear_explicit_returns.rb +23 -0
- data/spec/ruby_transform/transformers/composite_spec.rb +58 -0
- data/spec/ruby_transform/transformers/custom_transformer_spec.rb +25 -0
- data/spec/ruby_transform/transformers/eachifier_spec.rb +27 -0
- data/spec/ruby_transform/transformers/symbol_names_spec.rb +44 -0
- data/spec/ruby_transform/transformers/tapifier_spec.rb +57 -0
- data/spec/spec_helper.rb +9 -0
- metadata +143 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruby_transform (0.1.1)
|
5
|
+
activesupport (~> 3.0.10)
|
6
|
+
i18n (~> 0.6.0)
|
7
|
+
ruby_parser (~> 2.3.1)
|
8
|
+
ruby_scribe (~> 0.1.0)
|
9
|
+
thor (~> 0.13)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: http://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activesupport (3.0.10)
|
15
|
+
diff-lcs (1.1.3)
|
16
|
+
i18n (0.6.0)
|
17
|
+
rspec (2.6.0)
|
18
|
+
rspec-core (~> 2.6.0)
|
19
|
+
rspec-expectations (~> 2.6.0)
|
20
|
+
rspec-mocks (~> 2.6.0)
|
21
|
+
rspec-core (2.6.4)
|
22
|
+
rspec-expectations (2.6.0)
|
23
|
+
diff-lcs (~> 1.1.2)
|
24
|
+
rspec-mocks (2.6.0)
|
25
|
+
ruby_parser (2.3.1)
|
26
|
+
sexp_processor (~> 3.0)
|
27
|
+
ruby_scribe (0.1.2)
|
28
|
+
activesupport (~> 3.0.10)
|
29
|
+
i18n (~> 0.6.0)
|
30
|
+
ruby_parser (~> 2.3.1)
|
31
|
+
thor (~> 0.13)
|
32
|
+
sexp_processor (3.0.7)
|
33
|
+
thor (0.14.6)
|
34
|
+
|
35
|
+
PLATFORMS
|
36
|
+
ruby
|
37
|
+
|
38
|
+
DEPENDENCIES
|
39
|
+
rspec (~> 2.0)
|
40
|
+
ruby_transform!
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Ben Hughes
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
= Ruby Transform
|
2
|
+
|
3
|
+
== Introduction
|
4
|
+
|
5
|
+
Provides a series of s-expression transformations useful for automatic refactoring or morphing of Ruby/Rails/Sinatra code.
|
6
|
+
|
7
|
+
== Example
|
8
|
+
|
9
|
+
This is just one of many examples:
|
10
|
+
|
11
|
+
= Block Method To Proc Transform
|
12
|
+
Looks for cases where we're calling a single method on a single-parameter block argument.
|
13
|
+
These instances can use the Ruby 1.9 and ActiveSupport "Symbol#to_proc" trick.
|
14
|
+
|
15
|
+
Example:
|
16
|
+
|
17
|
+
collection.map {|d| d.name }
|
18
|
+
|
19
|
+
Transforms To:
|
20
|
+
|
21
|
+
collect.map(&:name)
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake"
|
3
|
+
require "rake/rdoctask"
|
4
|
+
|
5
|
+
desc "Generate documentation for the plugin."
|
6
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
7
|
+
rdoc.rdoc_dir = "rdoc"
|
8
|
+
rdoc.title = "has_draft"
|
9
|
+
rdoc.options << "--line-numbers" << "--inline-source"
|
10
|
+
rdoc.rdoc_files.include('README')
|
11
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
12
|
+
end
|
13
|
+
|
14
|
+
Dir["#{File.dirname(__FILE__)}/lib/tasks/*.rake"].sort.each { |ext| load ext }
|
data/TODO.rdoc
ADDED
data/bin/rubytransform
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
class Registry < HashWithIndifferentAccess
|
3
|
+
def self.instance
|
4
|
+
@registry ||= new
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.[](name)
|
8
|
+
instance[name]
|
9
|
+
end
|
10
|
+
def self.[]=(name, value)
|
11
|
+
instance[name] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.configure(&block)
|
15
|
+
instance.tap do |registry|
|
16
|
+
registry.instance_eval(&block) if block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def register(name, transform = nil, &block)
|
21
|
+
if block
|
22
|
+
self[name.to_s] = RubyTransform::Transformers::Custom.new(&block)
|
23
|
+
elsif transform.is_a?(Array)
|
24
|
+
self[name.to_s] = RubyTransform::Transformers::Composite.new(transform.map {|t|
|
25
|
+
if t.is_a?(Symbol) or t.is_a?(String)
|
26
|
+
self[t] or raise ArgumentError, "#{t} is not a registered transform name."
|
27
|
+
else
|
28
|
+
t
|
29
|
+
end
|
30
|
+
})
|
31
|
+
elsif transform.is_a?(RubyTransform::Transformer)
|
32
|
+
self[name.to_s] = transform
|
33
|
+
else
|
34
|
+
raise ArgumentError, "Please provide a transform or custom block processor."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
|
3
|
+
# Takes a raw S-expression and transforms it (replaces the node with the return value of the process method).
|
4
|
+
# This is meant to be subclassed, and in the process method you should either return a transformed version of the node,
|
5
|
+
# or just call super which will leave the node in place and iterate through the children.
|
6
|
+
#
|
7
|
+
class Transformer
|
8
|
+
include TransformerHelpers
|
9
|
+
|
10
|
+
def transform(sexp)
|
11
|
+
if sexp.is_a?(Sexp)
|
12
|
+
Sexp.new(*([sexp.kind] + sexp.body.map {|c| transform(c) }))
|
13
|
+
else
|
14
|
+
sexp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
module Transformers
|
3
|
+
|
4
|
+
# = Block Method To Proc Transform
|
5
|
+
# Looks for cases where we're calling a single method on a single-parameter block argument.
|
6
|
+
# These instances can use the Ruby 1.9 and ActiveSupport "Symbol#to_proc" trick.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# collection.map {|d| d.name }
|
11
|
+
#
|
12
|
+
# Transforms To:
|
13
|
+
#
|
14
|
+
# collect.map(&:name)
|
15
|
+
#
|
16
|
+
class BlockMethodToProcifier < Transformer
|
17
|
+
def transform(e)
|
18
|
+
super transform_block_methods_to_proc(e)
|
19
|
+
end
|
20
|
+
|
21
|
+
def transform_block_methods_to_proc(e)
|
22
|
+
if sexp?(e) && matches_block_to_use_tap?(e)
|
23
|
+
transform_block_to_use_tap(e)
|
24
|
+
else
|
25
|
+
e
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def matches_block_to_use_tap?(e)
|
30
|
+
e.kind == :iter && # Calls block
|
31
|
+
e.body[2] && e.body[2].kind == :call && # Body of block is a simple method call
|
32
|
+
e.body[2] && e.body[2].body[0] && e.body[2].body[0].kind == :lvar && # Simple method call is on a local variable
|
33
|
+
e.body[1] && e.body[1].kind == :lasgn && # Block parameter is a single assign
|
34
|
+
e.body[2] && e.body[2].body[0].body[0] == e.body[1].body[0] # Local variable is identical to the first block argument
|
35
|
+
end
|
36
|
+
|
37
|
+
def transform_block_to_use_tap(e)
|
38
|
+
s(:call,
|
39
|
+
e.body[0].body[0],
|
40
|
+
e.body[0].body[1],
|
41
|
+
s(:arglist, s(:block_pass, s(:lit, e.body[2].body[1])))
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
module Transformers
|
3
|
+
|
4
|
+
# = Clear Explicit Returns
|
5
|
+
# Looks for cases where the last expression in a method contains an explicit "return" statement, which is unnecessary
|
6
|
+
# in ruby, and removes it.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# def my_method
|
11
|
+
# a = 1
|
12
|
+
# call_something(a)
|
13
|
+
# return a
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# Transforms To:
|
17
|
+
#
|
18
|
+
# def my_method
|
19
|
+
# a = 1
|
20
|
+
# call_something(a)
|
21
|
+
# a
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
class ClearExplicitReturns < RubyTransform::Transformer
|
25
|
+
def transform(e)
|
26
|
+
super(transform_explicit_returns(e))
|
27
|
+
end
|
28
|
+
|
29
|
+
def transform_explicit_returns(e)
|
30
|
+
if matches_explicit_return_method?(e)
|
31
|
+
transform_explicit_return_method(e)
|
32
|
+
else
|
33
|
+
e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def matches_explicit_return_method?(e)
|
38
|
+
e.is_a?(Sexp) && e.method? && e.block && e.block.body.last && e.block.body.last.kind == :return
|
39
|
+
end
|
40
|
+
|
41
|
+
def transform_explicit_return_method(e)
|
42
|
+
e.clone.tap do |exp|
|
43
|
+
exp.block[-1] = exp.block[-1].body[0]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
module Transformers
|
3
|
+
|
4
|
+
# = Composite Transformer
|
5
|
+
# Combines transformations by chaining them.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# RubyTransform::Transformers::Composite.new([
|
10
|
+
# RubyTransform::Transformers::Eachifier.new,
|
11
|
+
# RubyTransform::Transformers::BlockMethodToProcifier.new,
|
12
|
+
# RubyTransform::Transformers::Tapifier.new
|
13
|
+
# ])
|
14
|
+
#
|
15
|
+
class Composite < RubyTransform::Transformer
|
16
|
+
def initialize(transformers = [])
|
17
|
+
class_eval do
|
18
|
+
define_method :transform do |e|
|
19
|
+
transformers.inject(e) do |transformed, transformer|
|
20
|
+
transformer.transform(transformed)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
module Transformers
|
3
|
+
|
4
|
+
# = Custom Transformer
|
5
|
+
# Allows for implementation of the transform to happen in-line through a block passed to the initializer.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# # This contrived example reverses all string literals
|
10
|
+
# RubyTransform::Transformers::Custom.new do |expression|
|
11
|
+
# if sexp?(expression) && expression.kind == :str
|
12
|
+
# s(:str, expression.body[0].reverse)
|
13
|
+
# else
|
14
|
+
# super
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
class Custom < RubyTransform::Transformer
|
19
|
+
def initialize(&block)
|
20
|
+
class_eval do
|
21
|
+
define_method(:transform, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
module Transformers
|
3
|
+
|
4
|
+
# = For to Each Block Transform
|
5
|
+
# Finds instances using "for something in collection"-style of iteration and converts
|
6
|
+
# it to using a standard collection.each block.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# for element in collection
|
11
|
+
# do_something(element)
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# Converts To:
|
15
|
+
#
|
16
|
+
# collection.each do |element|
|
17
|
+
# do_something(element)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class Eachifier < Transformer
|
21
|
+
def transform(e)
|
22
|
+
super(transform_fors_to_eaches(e))
|
23
|
+
end
|
24
|
+
|
25
|
+
def transform_fors_to_eaches(e)
|
26
|
+
if sexp?(e) && e.kind == :for
|
27
|
+
transform_for_to_each(e)
|
28
|
+
else
|
29
|
+
e
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def transform_for_to_each(e)
|
34
|
+
s(:iter,
|
35
|
+
s(:call, e.body[0], :each, s(:arglist)),
|
36
|
+
e.body[1],
|
37
|
+
e.body[2]
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
module Transformers
|
3
|
+
|
4
|
+
# = Symbol Names
|
5
|
+
# Sometimes you'll come across code written by a Java developer who uses camel-cased names for variables and methods.
|
6
|
+
# This transformer will allow you to apply some transformation (defined through a block to initialize) to every symbol name
|
7
|
+
# in the application, which includes all of these:
|
8
|
+
# * Method Names (Definitions and Calls)
|
9
|
+
# * Local Variable Names
|
10
|
+
# * Instance Variable Names
|
11
|
+
# * Class Variable Names
|
12
|
+
#
|
13
|
+
# Big Caveat: This transformer does not detect instances where the symbol name is referenced inside an eval-ed string, for example
|
14
|
+
# when you are instance_evaling some large string. As always, run your tests after any transformation.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
#
|
18
|
+
# # Underscores symbol names
|
19
|
+
# RubyTransform::Transformers::SymbolNames.new {|name| name.underscore }
|
20
|
+
#
|
21
|
+
# # Given This:
|
22
|
+
# def myMethod
|
23
|
+
# myVariable = 1
|
24
|
+
# @iVar = myMethod(myVariable)
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # Translates to This:
|
28
|
+
# def my_method
|
29
|
+
# my_variable = 1
|
30
|
+
# @i_var = my_method(my_variable)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # Or maybe translate from English to French
|
34
|
+
# RubyTransform::Transformers::SymbolNames.new {|name| Google::Translate.new(:fr).translate(name) }
|
35
|
+
#
|
36
|
+
class SymbolNames < RubyTransform::Transformer
|
37
|
+
def initialize(&block)
|
38
|
+
@name_transformer = block
|
39
|
+
end
|
40
|
+
|
41
|
+
def transform(e)
|
42
|
+
super(transform_symbols(e))
|
43
|
+
end
|
44
|
+
|
45
|
+
def transform_symbols(e)
|
46
|
+
return e unless sexp?(e)
|
47
|
+
|
48
|
+
case e.kind
|
49
|
+
when :defn
|
50
|
+
e.clone.tap {|c| c[1] = @name_transformer.call(c[1].to_s).to_sym }
|
51
|
+
when :defs
|
52
|
+
e.clone.tap {|c| c[2] = @name_transformer.call(c[2].to_s).to_sym }
|
53
|
+
when :call
|
54
|
+
e.clone.tap {|c| c[2] = @name_transformer.call(c[2].to_s).to_sym }
|
55
|
+
when :lasgn, :lvar
|
56
|
+
e.clone.tap {|c| c[1] = @name_transformer.call(c[1].to_s).to_sym }
|
57
|
+
when :cvdecl, :cvasgn, :cvar
|
58
|
+
e.clone.tap {|c| c[1] = ("@@" + @name_transformer.call(c[1].to_s.gsub(/^@@/, ''))).to_sym }
|
59
|
+
when :iasgn, :ivar
|
60
|
+
e.clone.tap {|c| c[1] = ("@" + @name_transformer.call(c[1].to_s.gsub(/^@/, ''))).to_sym }
|
61
|
+
else
|
62
|
+
e
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module RubyTransform
|
2
|
+
module Transformers
|
3
|
+
|
4
|
+
# = Method Temporary Variables to Tap Block
|
5
|
+
# Looks for instances of method declarations where:
|
6
|
+
# 1. A local variable is assigned to something as the first statement.
|
7
|
+
# 2. As the last statement, that local variable is returned is expressed.
|
8
|
+
#
|
9
|
+
# These instances of using "temporary variables" to construct something for returning can be more
|
10
|
+
# elegantly expressed by using the .tap idiom.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
#
|
14
|
+
# def my_method
|
15
|
+
# temp = ""
|
16
|
+
# temp << "Something"
|
17
|
+
# call_something(temp)
|
18
|
+
# temp
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Converts To:
|
22
|
+
#
|
23
|
+
# def my_method
|
24
|
+
# "".tap do |temp|
|
25
|
+
# temp << "Something"
|
26
|
+
# call_something(temp)
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
class Tapifier < Transformer
|
31
|
+
def transform(e)
|
32
|
+
super(transform_tapify_candidates(e))
|
33
|
+
end
|
34
|
+
|
35
|
+
def transform_tapify_candidates(e)
|
36
|
+
if matches_method_to_use_tap?(e)
|
37
|
+
transform_method_to_use_tap(e)
|
38
|
+
else
|
39
|
+
e
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def matches_method_to_use_tap?(e)
|
44
|
+
e.is_a?(Sexp) && [:defn, :defs].include?(e.kind) &&
|
45
|
+
matches_block_to_use_tap?(e.body[2])
|
46
|
+
end
|
47
|
+
|
48
|
+
def matches_block_to_use_tap?(e)
|
49
|
+
return matches_block_to_use_tap?(e.body[0]) if e.body.size == 1 && e.body[0].kind == :block
|
50
|
+
|
51
|
+
e.is_a?(Sexp) && e.kind == :block && # Some block (or method body)
|
52
|
+
e.body[0].kind == :lasgn && # The first line assigns to a local variable
|
53
|
+
expresses_local_variable?(e.body[-1], e.body[0].body[0])
|
54
|
+
end
|
55
|
+
|
56
|
+
def expresses_local_variable?(e, local_variable)
|
57
|
+
(e.kind == :lvar && e.body[0] == local_variable) ||
|
58
|
+
(e.kind == :return && expresses_local_variable?(e.body[0], local_variable))
|
59
|
+
end
|
60
|
+
|
61
|
+
def transform_method_to_use_tap(e)
|
62
|
+
s(e.kind, e.body[0], e.body[1], transform_block_to_use_tap(e.body[2]))
|
63
|
+
end
|
64
|
+
|
65
|
+
def transform_block_to_use_tap(e)
|
66
|
+
return s(:scope, transform_block_to_use_tap(e.body[0])) if e.body.size == 1 && e.kind == :scope && e.body[0].kind == :block
|
67
|
+
|
68
|
+
s(:block, s(:iter,
|
69
|
+
s(:call, e.body[0].body[1], :tap, s(:arglist)),
|
70
|
+
s(:lasgn, e.body[0].body[0]),
|
71
|
+
s(*([:block] + e.body[1..-2]))
|
72
|
+
))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
RSpec::Matchers.define :transform_to do |desc, expected|
|
2
|
+
match do |actual|
|
3
|
+
actual_as_sexp = actual.is_a?(String) ? RubyParser.new.parse(actual) : actual
|
4
|
+
expected_as_sexp = expected.is_a?(String) ? RubyParser.new.parse(expected) : expected
|
5
|
+
|
6
|
+
@transformed = described_class.transform(actual_as_sexp)
|
7
|
+
@transformed == expected_as_sexp
|
8
|
+
end
|
9
|
+
|
10
|
+
failure_message_for_should do |actual|
|
11
|
+
"expected that:\n\n#{RubyParser.new.parse(actual)}\n\nwould transform to:\n\n#{RubyParser.new.parse(expected)}\n\nbut instead was:\n\n#{@transformed}"
|
12
|
+
end
|
13
|
+
|
14
|
+
failure_message_for_should_not do |actual|
|
15
|
+
"expected that:\n\n#{RubyParser.new.parse(actual)}\n\nwould not transform to:\n\n#{RubyParser.new.parse(expected)}\n\nbut instead was:\n\n#{@transformed}"
|
16
|
+
end
|
17
|
+
|
18
|
+
description do
|
19
|
+
"transform with to #{desc}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def transformed_as_ruby
|
23
|
+
RubyTransform::Emitter.new.emit(@transformed)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RubyTransform::Registry do
|
4
|
+
before do
|
5
|
+
RubyTransform::Registry.configure do
|
6
|
+
register :blocks_to_symbols, RubyTransform::Transformers::BlockMethodToProcifier.new
|
7
|
+
register :eachify, RubyTransform::Transformers::Eachifier.new
|
8
|
+
register :tapify, RubyTransform::Transformers::Tapifier.new
|
9
|
+
|
10
|
+
register :underscore_names, RubyTransform::Transformers::SymbolNames.new {|name| name.underscore }
|
11
|
+
|
12
|
+
register :composite_with_objects, [
|
13
|
+
RubyTransform::Transformers::BlockMethodToProcifier.new,
|
14
|
+
RubyTransform::Transformers::Eachifier.new,
|
15
|
+
RubyTransform::Transformers::Tapifier.new
|
16
|
+
]
|
17
|
+
|
18
|
+
register :composite_with_symbols, [
|
19
|
+
:blocks_to_symbols,
|
20
|
+
:eachify,
|
21
|
+
:tapify
|
22
|
+
]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have registered blocks to symbols" do
|
27
|
+
RubyTransform::Registry["blocks_to_symbols"].should be_a(RubyTransform::Transformers::BlockMethodToProcifier)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should have registered eachify" do
|
31
|
+
RubyTransform::Registry["eachify"].should be_a(RubyTransform::Transformers::Eachifier)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should have registered tapify" do
|
35
|
+
RubyTransform::Registry["tapify"].should be_a(RubyTransform::Transformers::Tapifier)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have registered underscore_names" do
|
39
|
+
RubyTransform::Registry["underscore_names"].should be_a(RubyTransform::Transformers::SymbolNames)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have registered composite_with_objects" do
|
43
|
+
RubyTransform::Registry["composite_with_objects"].should be_a(RubyTransform::Transformers::Composite)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have registered composite_with_symbols" do
|
47
|
+
RubyTransform::Registry["composite_with_symbols"].should be_a(RubyTransform::Transformers::Composite)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RubyTransform::Transformer.new do
|
4
|
+
|
5
|
+
describe "a for block" do
|
6
|
+
subject { %{
|
7
|
+
def my_method
|
8
|
+
call_something
|
9
|
+
|
10
|
+
for element in array
|
11
|
+
do_something(element)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
}}
|
15
|
+
|
16
|
+
it { should transform_to("the same", %{
|
17
|
+
def my_method
|
18
|
+
call_something
|
19
|
+
|
20
|
+
for element in array
|
21
|
+
do_something(element)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
}) }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RubyTransform::Transformers::BlockMethodToProcifier.new do
|
4
|
+
|
5
|
+
describe "a block call with method invocation" do
|
6
|
+
subject { %{collection.map {|d| d.name }}}
|
7
|
+
it { should transform_to("use Symbol#to_proc", %{collection.map(&:name)}) }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "a block call with chained method invocation" do
|
11
|
+
subject { %{collection.map {|d| d.name.first }}}
|
12
|
+
it { should transform_to("itself", subject) }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "a multiple-argument block call with method invocation" do
|
16
|
+
subject { %{collection.map {|d, i| d.name + i }}}
|
17
|
+
it { should transform_to("itself", subject) }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RubyTransform::Transformers::ClearExplicitReturns.new do
|
4
|
+
|
5
|
+
describe "a method with explicit return" do
|
6
|
+
subject { %{
|
7
|
+
def my_method
|
8
|
+
a = 1
|
9
|
+
call_something(a)
|
10
|
+
return a
|
11
|
+
end
|
12
|
+
}}
|
13
|
+
|
14
|
+
it { should transform_to("no return", %{
|
15
|
+
def my_method
|
16
|
+
a = 1
|
17
|
+
call_something(a)
|
18
|
+
a
|
19
|
+
end
|
20
|
+
}) }
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
transformer = RubyTransform::Transformers::Composite.new([
|
4
|
+
RubyTransform::Transformers::Eachifier.new,
|
5
|
+
RubyTransform::Transformers::BlockMethodToProcifier.new,
|
6
|
+
RubyTransform::Transformers::Tapifier.new
|
7
|
+
])
|
8
|
+
|
9
|
+
describe(transformer) do
|
10
|
+
|
11
|
+
describe "a block call with method invocation" do
|
12
|
+
subject { %{collection.map {|d| d.name }}}
|
13
|
+
it { should transform_to("use Symbol#to_proc", %{collection.map(&:name)}) }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "a for block" do
|
17
|
+
subject { %{
|
18
|
+
def my_method
|
19
|
+
call_something
|
20
|
+
|
21
|
+
for element in array
|
22
|
+
do_something(element)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
}}
|
26
|
+
|
27
|
+
it { should transform_to("each", %{
|
28
|
+
def my_method
|
29
|
+
call_something
|
30
|
+
|
31
|
+
array.each do |element|
|
32
|
+
do_something(element)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
}) }
|
36
|
+
end
|
37
|
+
#
|
38
|
+
# describe "a method setting up and returning a temporary variable" do
|
39
|
+
# subject {%{
|
40
|
+
# def my_method
|
41
|
+
# temp = ""
|
42
|
+
# temp << "Something"
|
43
|
+
# call_something(temp)
|
44
|
+
# temp
|
45
|
+
# end
|
46
|
+
# }}
|
47
|
+
#
|
48
|
+
# it { should transform_to("wrap in #tap", %{
|
49
|
+
# def my_method
|
50
|
+
# "".tap do |temp|
|
51
|
+
# temp << "Something"
|
52
|
+
# call_something(temp)
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
# }) }
|
56
|
+
# end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
transformer = RubyTransform::Transformers::Custom.new do |expression|
|
4
|
+
if sexp?(expression) && expression.kind == :str
|
5
|
+
s(:str, expression.body[0].reverse)
|
6
|
+
else
|
7
|
+
super(expression)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe(transformer) do
|
12
|
+
|
13
|
+
describe "some strings" do
|
14
|
+
subject { %{
|
15
|
+
s = "one"
|
16
|
+
t = "two"
|
17
|
+
}}
|
18
|
+
|
19
|
+
it { should transform_to("reverse", %{
|
20
|
+
s = "eno"
|
21
|
+
t = "owt"
|
22
|
+
}) }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RubyTransform::Transformers::Eachifier.new do
|
4
|
+
|
5
|
+
describe "a for block" do
|
6
|
+
subject { %{
|
7
|
+
def my_method
|
8
|
+
call_something
|
9
|
+
|
10
|
+
for element in array
|
11
|
+
do_something(element)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
}}
|
15
|
+
|
16
|
+
it { should transform_to("each", %{
|
17
|
+
def my_method
|
18
|
+
call_something
|
19
|
+
|
20
|
+
array.each do |element|
|
21
|
+
do_something(element)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
}) }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
SymbolUnderscorer = RubyTransform::Transformers::SymbolNames.new do |name|
|
4
|
+
name.underscore
|
5
|
+
end
|
6
|
+
|
7
|
+
describe SymbolUnderscorer do
|
8
|
+
|
9
|
+
describe "method definition" do
|
10
|
+
subject { %{def myMethod; end; def self.anotherMethod; end} }
|
11
|
+
it { should transform_to("underscored", %{def my_method; end; def self.another_method; end}) }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "method call" do
|
15
|
+
subject { %{myMethod.doSomething} }
|
16
|
+
it { should transform_to("underscored", %{my_method.do_something}) }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "method arguments" do
|
20
|
+
subject { %{my(argOne, argTwo)} }
|
21
|
+
it { should transform_to("underscored", %{my(arg_one, arg_two)}) }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "block arguments" do
|
25
|
+
subject { %{collection.each {|argOne, argTwo| something }} }
|
26
|
+
it { should transform_to("underscored", %{collection.each {|arg_one, arg_two| something }}) }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "local variable" do
|
30
|
+
subject { %{def my; myVariable = 1; myVariable; end} }
|
31
|
+
it { should transform_to("underscored", %{def my; my_variable = 1; my_variable; end}) }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "instance variable" do
|
35
|
+
subject { %{@myVariable = 1; @myVariable} }
|
36
|
+
it { should transform_to("underscored", %{@my_variable = 1; @my_variable}) }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "class variable" do
|
40
|
+
subject { %{@@myVariable = 1; @@myVariable; def my; @@myVariable = 1; end} }
|
41
|
+
it { should transform_to("underscored", %{@@my_variable = 1; @@my_variable; def my; @@my_variable = 1; end}) }
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RubyTransform::Transformers::Tapifier.new do
|
4
|
+
|
5
|
+
describe "a method setting up and returning a temporary variable" do
|
6
|
+
subject {%{
|
7
|
+
def my_method
|
8
|
+
temp = ""
|
9
|
+
temp << "Something"
|
10
|
+
call_something(temp)
|
11
|
+
temp
|
12
|
+
end
|
13
|
+
}}
|
14
|
+
|
15
|
+
it { should transform_to("wrap in #tap", %{
|
16
|
+
def my_method
|
17
|
+
"".tap do |temp|
|
18
|
+
temp << "Something"
|
19
|
+
call_something(temp)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
}) }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "a method setting up and explicitly returning a temporary variable" do
|
26
|
+
subject {%{
|
27
|
+
def my_method
|
28
|
+
temp = ""
|
29
|
+
temp << "Something"
|
30
|
+
call_something(temp)
|
31
|
+
return temp
|
32
|
+
end
|
33
|
+
}}
|
34
|
+
|
35
|
+
it { should transform_to("wrap in #tap", %{
|
36
|
+
def my_method
|
37
|
+
"".tap do |temp|
|
38
|
+
temp << "Something"
|
39
|
+
call_something(temp)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
}) }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "a method setting up and not returning a temporary variable" do
|
46
|
+
subject {%{
|
47
|
+
def my_method
|
48
|
+
temp = ""
|
49
|
+
temp << "Something"
|
50
|
+
call_something(temp)
|
51
|
+
end
|
52
|
+
}}
|
53
|
+
|
54
|
+
it { should transform_to("itself", subject) }
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), "../lib"))
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "rspec"
|
5
|
+
require "ruby_transform"
|
6
|
+
|
7
|
+
# Requires supporting files with custom matchers and macros, etc,
|
8
|
+
# in ./support/ and its subdirectories.
|
9
|
+
Dir["#{File.dirname(__FILE__)}/matchers/**/*.rb"].each {|f| require f}
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_transform
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ben Hughes
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &70114553708920 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.13'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70114553708920
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70114553704060 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.10
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70114553704060
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: i18n
|
38
|
+
requirement: &70114553703580 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.6.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70114553703580
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: ruby_parser
|
49
|
+
requirement: &70114553703100 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.3.1
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70114553703100
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: ruby_scribe
|
60
|
+
requirement: &70114553702620 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.1.0
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70114553702620
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: &70114553702140 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70114553702140
|
80
|
+
description: Provides a series of s-expression transformations useful for automatic
|
81
|
+
refactoring or morphing of Ruby/Rails/Sinatra code.
|
82
|
+
email: ben@railsgarden.com
|
83
|
+
executables:
|
84
|
+
- rubytransform
|
85
|
+
extensions: []
|
86
|
+
extra_rdoc_files: []
|
87
|
+
files:
|
88
|
+
- lib/ruby_transform/registry.rb
|
89
|
+
- lib/ruby_transform/runner.rb
|
90
|
+
- lib/ruby_transform/transform_helpers.rb
|
91
|
+
- lib/ruby_transform/transformer.rb
|
92
|
+
- lib/ruby_transform/transformers/block_method_to_procifier.rb
|
93
|
+
- lib/ruby_transform/transformers/clear_explicit_returns.rb
|
94
|
+
- lib/ruby_transform/transformers/composite.rb
|
95
|
+
- lib/ruby_transform/transformers/custom.rb
|
96
|
+
- lib/ruby_transform/transformers/eachifier.rb
|
97
|
+
- lib/ruby_transform/transformers/symbol_names.rb
|
98
|
+
- lib/ruby_transform/transformers/tapifier.rb
|
99
|
+
- lib/ruby_transform/version.rb
|
100
|
+
- lib/ruby_transform.rb
|
101
|
+
- spec/matchers/should_transform_to.rb
|
102
|
+
- spec/ruby_transform/registry_spec.rb
|
103
|
+
- spec/ruby_transform/transformer_spec.rb
|
104
|
+
- spec/ruby_transform/transformers/block_method_to_procifier_spec.rb
|
105
|
+
- spec/ruby_transform/transformers/clear_explicit_returns.rb
|
106
|
+
- spec/ruby_transform/transformers/composite_spec.rb
|
107
|
+
- spec/ruby_transform/transformers/custom_transformer_spec.rb
|
108
|
+
- spec/ruby_transform/transformers/eachifier_spec.rb
|
109
|
+
- spec/ruby_transform/transformers/symbol_names_spec.rb
|
110
|
+
- spec/ruby_transform/transformers/tapifier_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
- Gemfile
|
113
|
+
- Gemfile.lock
|
114
|
+
- LICENSE
|
115
|
+
- Rakefile
|
116
|
+
- README.rdoc
|
117
|
+
- TODO.rdoc
|
118
|
+
- bin/rubytransform
|
119
|
+
homepage: http://github.com/rubiety/ruby_transform
|
120
|
+
licenses: []
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ! '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 1.3.4
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project: ruby_transform
|
139
|
+
rubygems_version: 1.8.10
|
140
|
+
signing_key:
|
141
|
+
specification_version: 3
|
142
|
+
summary: S-expression transformations for Ruby.
|
143
|
+
test_files: []
|