Permalink
Browse files

simple extract variable

  • Loading branch information...
Flavio Mori authored and fabiokung committed Dec 22, 2009
1 parent fee699a commit 24fc0a2ba5b9ac4605c009e01d0c539bd3cce721
Showing with 127 additions and 1 deletion.
  1. +68 −0 features/extract_variable.feature
  2. +16 −0 features/steps/code_steps.rb
  3. +43 −1 lib/rfactor/code.rb
@@ -0,0 +1,68 @@
+Feature: Extract Variable
+ In order to improve my code's quality
+ As a developer
+ I want to extract variables
+
+ Scenario: Extracting a variable
+ Given I have the following code:
+ """
+ def method
+ puts "string" + "other"
+ end
+ """
+ And text '"string"' from line 2 is selected
+ And I want it to be in the variable called 'var'
+ When I call 'extract variable'
+ Then the code should be:
+ """
+ def method
+ var = "string"
+ puts var + "other"
+ end
+ """
+
+ Scenario: Extracting a variable on multiple occurrences
+ Given I have the following code:
+ """
+ def method
+ puts "string" + "other"
+ puts "string" + "another"
+ end
+ """
+ And text '"string"' from line 2 is selected
+ And I want it to be in the variable called 'var'
+ When I call 'extract variable'
+ Then the code should be:
+ """
+ def method
+ var = "string"
+ puts var + "other"
+ puts var + "another"
+ end
+ """
+
+ Scenario: Extracting a variable just in the current method
+ Given I have the following code:
+ """
+ def method
+ puts "string" + "other"
+ end
+
+ def other_method
+ puts "string" + "other"
+ end
+ """
+ And text '"string"' from line 2 is selected
+ And I want it to be in the variable called 'var'
+ When I call 'extract variable'
+ Then the code should be:
+ """
+ def method
+ var = "string"
+ puts var + "other"
+ end
+
+ def other_method
+ puts "string" + "other"
+ end
+ """
@@ -6,17 +6,33 @@
@selected_lines = [start_line.to_i, end_line.to_i]
end
+Given /^text '(.+)' from line (\d+) is selected$/ do |text, line|
+ @text = text
+ @line = line.to_i
+end
+
Given /^I want them to be in the method called '(.+)'$/ do |name|
@method_name = name
end
+Given /^I want it to be in the variable called '(.+)'$/ do |name|
+ @variable_name = name
+end
+
When /^I call 'extract method'$/ do
@code = Rfactor::Code.new(@code)
@new_code = @code.extract_method :name => @method_name,
:start => @selected_lines[0],
:end => @selected_lines[1]
end
+When /^I call 'extract variable'$/ do
+ @code = Rfactor::Code.new(@code)
+ @new_code = @code.extract_variable :name => @variable_name,
+ :text => @text,
+ :line => @line
+end
+
Then /^the code should be:$/ do |expected|
@new_code.should == expected
end
View
@@ -58,13 +58,55 @@ def extract_method(args)
new_code
end
+ # == Required arguments
+ #
+ # You must pass them inside a Hash:
+ #
+ # * :name => 'the new variable name'
+ # * :text => what to be extracted to the variable
+ # * :line => line number where the variable to be extracted is
+ #
+ # == Example
+ #
+ # code.extract_variable :name => 'common_code', :text => "'string'", :line => 3
+ def extract_variable(args)
+ raise ":name is required" unless args.has_key?(:name)
+
+ ast = RubyParser.new.parse(@code)
+ line_finder = LineFinder.new(ast)
+
+ method_lines = line_finder.method_lines(args[:line])
+
+ new_code = ""
+ added = false
+ identation = 0
+
+ @code.each_with_index do |line, n|
+ line_number = n + 1 # not 0-based
+ if line_number == method_lines.first
+ identation = extract_identation_level_from line
+ end
+ if line_number == method_lines.first + 1
+ new_code << "#{identation} #{args[:name]} = #{args[:text]}\n"
+ end
+ if method_lines.include? line_number
+ new_line = line.gsub(args[:text], args[:name])
+ new_code << new_line
+ else
+ new_code << line
+ end
+ end
+ new_code
+ end
+
+ private
+
def assignment_value(method_contents)
last_instruction = method_contents.split("\n")[-1]
is_assignment = remove_constants(last_instruction).match(/\s*(#{VALID_NAME})\s*=/)
$1
end
- private
def raise_error_if_absent(arguments, keys)
keys.each do |key|
raise ":#{key} is required" unless arguments.has_key?(key.to_sym)

0 comments on commit 24fc0a2

Please sign in to comment.