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.
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: []