lib/reciper/helpers.rb in reciper-0.0.4 vs lib/reciper/helpers.rb in reciper-0.1.0
- old
+ new
@@ -5,116 +5,221 @@
end
class NoFileToBeOverriden < RuntimeError
end
+ class NoFileOrMultipleFilesFound < RuntimeError
+ end
+
module Helpers
+ # Copies the file from recipe to ruby_app. It is reversible.
+ #
+ # filename - The file to be copied relative to the recipe_path
+ # options - The hash options to configure the copy (default: {}):
+ # :as - The copy name (default: the file name).
+ # :to - The destination dir relative to the ruby_app_path. If the directory doesn't exists, it will be created (default: ruby_app_path root path).
+ #
+ # Examples
+ #
+ # copy_file("a.rb")
+ # copy_file("a.rb", :to => "app/models", :as => "person.rb")
+ #
+ # Returns nothing.
def copy_file(filename, options={})
- destination_dir = @ruby_app_path + "/" + (options[:to] || "")
+ destination_file_name = options[:as] || filename
+ destination_dir = options[:to] || ""
- unless File.directory?(destination_dir)
- FileUtils.mkdir_p(destination_dir)
- end
+ destination = File.join(destination_dir , destination_file_name)
+ global_destination = File.join(@ruby_app_path, destination)
- FileUtils.cp(@recipe_path + "/" + filename, destination_dir)
+ create_directory_if_not_exists(File.join(@ruby_app_path, destination_dir))
- new_filename = options[:as] || filename
+ FileUtils.cp(File.join(@recipe_path, filename), global_destination)
- if(options[:as])
- FileUtils.mv(destination_dir + "/" + filename, destination_dir + "/" + new_filename)
- end
-
- @operations << [:copy, (options[:to] || "") + new_filename]
+ @operations << [:copy_file, { :destination => destination }]
end
- def run_tests(options={})
- Dir.chdir(@ruby_app_path) do
- response = `bundle exec rspec spec`
+ # Run the tests on the ruby app. It is NOT reversible.
+ #
+ # Examples
+ #
+ # run_tests()
+ # # => 2
+ #
+ # Returns the number of failures
+ def run_tests
+ result = run_command("bundle exec rspec spec")
- if response =~ /([.FE*]+)/
- $1.split("").reject { |char| char == "." }.size
- else
- puts "Can't get any test output"
- fail NoTestOutput
- end
+ if result[:response] =~ /([\.FE*]+)/
+ $1.split("").reject { |char| (char == "." || char == "*") }.size
+ else
+ puts "Can't get any test output"
+ fail NoTestOutput
end
end
+ # Run a rake task on the ruby app. It is NOT reversible.
+ #
+ # task - the desired task
+ #
+ # Examples
+ #
+ # rake_task("db:migrate")
+ # # => { :successful => true, :response => ""}
+ # rake_task("db:migrate")
+ # # => { :successful => false, :response => "Couldn't find the specified DB"}
+ #
+ # Returns a command execution hash
def run_rake_task(task)
- Dir.chdir(@ruby_app_path) do
- spawn("bundle exec rake #{task}", :out => "/dev/null", :err => "/dev/null")
-
- Process.wait
- end
-
- $?.exitstatus == 0
+ run_command("bundle exec rake #{task}")
end
+ # Copies a range of lines from a file on the recipe path to a file on the ruby app path. It is reversible.
+ #
+ # from - the file, relative to the recipe path, that contains the file with the lines that will be copied
+ # to - the file, relative to the ruby app path, that contains the file that will receive the files. You can also specify a suffix like *.rb and if it matches only one file, it will insert the lines to it, otherwise it will raise a NoFileOrMultipleFilesFound exception
+ # options - some options related to the line copy (default: {})
+ # :to_line - The line where the content will be inserted (default: raises an exception)
+ # :lines - A range that specifies the lines that will be copied (default: whole file (0..-1))
+ #
+ # Examples
+ #
+ # copy_line_range("a.rb", "app/models/person.rb", :to_line => 42)
+ # copy_line_range("a.rb", "app/models/person.rb", :to_line => 42, :lines => (4..10))
+ # copy_line_range("a.rb", "db/migrate/*create_users.rb", :to_line => 10, :lines => (1..5))
+ #
+ # Returns nothing.
def copy_line_range(from, to, options={})
- if options[:from_lines]
- from_lines = Range.new(options[:from_lines].first - 1, options[:from_lines].last - 1)
- else
- from_lines = (0..-1)
- end
+ original_file = filename_from_suffix(to)
- from_file_lines = File.open(@recipe_path + "/" + from, "r").readlines
- output_lines = File.read(@ruby_app_path + "/" + to).split("\n")
- original_output = output_lines.dup
- to_file_output = File.open(@ruby_app_path + "/" + to, "w")
+ original_content = File.read(original_file)
+ original = original_content.split("\n")
- to_output = output_lines.insert(options[:to_line] - 1, from_file_lines.map(&:chomp).slice(from_lines)).flatten!.join("\n")
+ new_content = File.read(File.join(@recipe_path, from)).split("\n")
- to_file_output.write(to_output)
+ range = options[:lines] || (0..-1)
- to_file_output.close
+ original.insert(options[:to_line], new_content[range])
- @operations << [:copy_range, to, original_output.join("\n")]
+ File.open(original_file, "w") do |file|
+ file.write(original.flatten.join("\n"))
+ end
+
+ @operations << [:copy_line_range, { :original_content => original_content, :original_file => original_file }]
end
+ # Does the rollback on all reversible operations.
+ #
+ # Examples
+ #
+ # rollback
+ #
+ # Returns nothing
def rollback
@operations.reverse.each do |operation|
- if operation[0] == :copy
- FileUtils.rm(@ruby_app_path + "/" + operation[1])
- elsif operation[0] == :copy_range
- File.open(@ruby_app_path + "/" + operation[1], "w") { |file| file.write(operation[2]) }
- elsif operation[0] == :run_command
- spawn(operation[1]) if operation[1]
+ operation_name, arguments = operation
- Process.wait
- elsif operation[0] == :override_file
- FileUtils.cp(operation[1], @ruby_app_path + "/" + operation[2])
+ case operation_name
+ when :copy_file
+ then remove_file(arguments[:destination])
+ when :copy_range
+ then write_content_to_file(arguments[:original_file], arguments[:original_content])
+ when :run_command
+ then run_command(arguments[:rollback_command]) if arguments[:rollback_command]
+ when :override_file
+ then FileUtils.cp(arguments[:tmp_file], File.join(@ruby_app_path, arguments[:overriden_file]))
end
end
end
+ # Runs a command using bundle exec on the ruby app path. If you specify a rollback command, it is reversible.
+ #
+ # command - the command. It will run inside a bundle exec.
+ # rollback_command - the command which rollbacks the command (default: nil)
+ #
+ # Examples
+ #
+ # run_command("ls")
+ # # => { :successful => true, response => "file.rb\n\file2.rb" }
+ # run_command("rails g model user", "rails d model user")
+ # # => { :successful => true, response => "model was generated" }
+ # run_command("cp a.rb b.rb")
+ # # => { :successful => false, response => "file a.rb doesn't exists" }
+ #
+ # Returns a command execution hash
def run_command(command, rollback_command=nil)
- Dir.chdir(@ruby_app_path) do
- spawn("bundle exec #{command}", :out => "/dev/null", :err => "/dev/null")
+ response = ""
+ successful = ""
- Process.wait
- end
+ run_on_app_path do
+ IO.popen(command) do |io|
+ response = io.read
+ end
- if $?.exitstatus == 0
- @operations << [:run_command, rollback_command || nil]
- true
- else
- false
+ successful = ($?.exitstatus == 0)
end
+
+ @operations << [:run_command, { :rollback_command => rollback_command }]
+
+ {
+ :successful => successful,
+ :response => response
+ }
end
+ # Overrides a file of the ruby app with a file from the recipe path. It is reversible.
+ #
+ # file - The file that will override relative to the recipe path
+ # file_to_be_overriden - The file that will be overriden
+ #
+ # Examples
+ #
+ # override_file("a.rb", "app/controller/application_controller.rb")
+ #
+ # Returns nothing
def override_file(file, file_to_be_overriden)
- Dir.chdir(@ruby_app_path) do
+ run_on_app_path do
fail NoFileToBeOverriden unless File.exists?(file_to_be_overriden)
FileUtils.mkdir_p("/tmp/reciper")
filename = File.basename(file_to_be_overriden)
tmp_file = "/tmp/reciper/#{filename}"
FileUtils.cp(file_to_be_overriden, tmp_file)
- @operations << [:override_file, tmp_file, file_to_be_overriden]
+ @operations << [:override_file, { :tmp_file => tmp_file, :overriden_file => file_to_be_overriden }]
end
- FileUtils.cp(@recipe_path + "/" + file, @ruby_app_path + "/" + file_to_be_overriden)
+ FileUtils.cp(File.join(@recipe_path,file), File.join(@ruby_app_path, file_to_be_overriden))
+ end
+
+ private
+
+ def filename_from_suffix(suffix)
+ files = Dir.glob(File.join(@ruby_app_path, suffix))
+ fail NoFileOrMultipleFilesFound if files.size != 1
+ files.first
+ end
+
+ def create_directory_if_not_exists(directory)
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
+ end
+
+ def run_on_app_path
+ Dir.chdir(@ruby_app_path) do
+ yield
+ end
+ end
+
+ def remove_file(file)
+ run_on_app_path do
+ FileUtils.rm(file)
+ end
+ end
+
+ def write_content_to_file(filename, content)
+ File.open(filename, "w") do |file|
+ file.write(content)
+ end
end
end
end
\ No newline at end of file