ruby_transform 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/Gemfile +3 -0
  2. data/Gemfile.lock +40 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +21 -0
  5. data/Rakefile +14 -0
  6. data/TODO.rdoc +4 -0
  7. data/bin/rubytransform +6 -0
  8. data/lib/ruby_transform/registry.rb +38 -0
  9. data/lib/ruby_transform/runner.rb +8 -0
  10. data/lib/ruby_transform/transform_helpers.rb +7 -0
  11. data/lib/ruby_transform/transformer.rb +18 -0
  12. data/lib/ruby_transform/transformers/block_method_to_procifier.rb +47 -0
  13. data/lib/ruby_transform/transformers/clear_explicit_returns.rb +49 -0
  14. data/lib/ruby_transform/transformers/composite.rb +28 -0
  15. data/lib/ruby_transform/transformers/custom.rb +27 -0
  16. data/lib/ruby_transform/transformers/eachifier.rb +43 -0
  17. data/lib/ruby_transform/transformers/symbol_names.rb +68 -0
  18. data/lib/ruby_transform/transformers/tapifier.rb +77 -0
  19. data/lib/ruby_transform/version.rb +3 -0
  20. data/lib/ruby_transform.rb +8 -0
  21. data/spec/matchers/should_transform_to.rb +25 -0
  22. data/spec/ruby_transform/registry_spec.rb +49 -0
  23. data/spec/ruby_transform/transformer_spec.rb +27 -0
  24. data/spec/ruby_transform/transformers/block_method_to_procifier_spec.rb +20 -0
  25. data/spec/ruby_transform/transformers/clear_explicit_returns.rb +23 -0
  26. data/spec/ruby_transform/transformers/composite_spec.rb +58 -0
  27. data/spec/ruby_transform/transformers/custom_transformer_spec.rb +25 -0
  28. data/spec/ruby_transform/transformers/eachifier_spec.rb +27 -0
  29. data/spec/ruby_transform/transformers/symbol_names_spec.rb +44 -0
  30. data/spec/ruby_transform/transformers/tapifier_spec.rb +57 -0
  31. data/spec/spec_helper.rb +9 -0
  32. metadata +143 -0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
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
@@ -0,0 +1,4 @@
1
+ = TODO
2
+
3
+ * Eventually going to need some similar concept of "checks" like exist in rails_best_practices.
4
+ * What about transforms that work across files? For example complex view snippets that can automatically be refactored to helpers.
data/bin/rubytransform ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "ruby_transform/runner"
5
+
6
+ RubyTransform::Runner.start
@@ -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,8 @@
1
+ require "thor"
2
+ require "ruby_transform"
3
+
4
+ module RubyTransform
5
+ class Runner < Thor
6
+
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module RubyTransform
2
+ module TransformerHelpers
3
+ def sexp?(e)
4
+ e.is_a?(Sexp)
5
+ end
6
+ end
7
+ 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,3 @@
1
+ module RubyTransform
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,8 @@
1
+ require "rubygems"
2
+ require "active_support"
3
+ require "ruby_parser"
4
+ require "ruby_scribe"
5
+
6
+ Dir[File.join(File.dirname(__FILE__), "ruby_transform/**/**/*.rb")].each do |file|
7
+ require file
8
+ 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
@@ -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: []