![show/hide quicksearch [+]](../../images/find.png)
Injects the given content into a file. Different from #gsub_file, this method is reversible.
Relative path to the destination root
Data to add to the file. Can be given as a block.
give :verbose => false to not log the status and the flag for injection (:after or :before) or :force => true for insert two or more times the same content.
insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n" insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do gems = ask "Which gems would you like to add?" gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n") end
Extends initializer to add more configuration options.
The actions default behavior. Can be :invoke or :revoke. It also accepts :force, :skip and :pretend to set the behavior and the respective option.
The root directory needed for some actions.
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 72
def initialize(args = [], options = {}, config = {})
  self.behavior = case config[:behavior].to_s
  when "force", "skip"
    _cleanup_options_and_set(options, config[:behavior])
    :invoke
  when "revoke"
    :revoke
  else
    :invoke
  end
  super
  self.destination_root = config[:destination_root]
end
             
            Append text to a file. Since it depends on #insert_into_file, it’s reversible.
path of the file to be changed
the data to append to the file, can be also given as a block.
give :verbose => false to not log the status.
append_to_file 'config/environments/test.rb', 'config.gem "rspec"' append_to_file 'config/environments/test.rb' do 'config.gem "rspec"' end
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 195
def append_to_file(path, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  config[:before] = /\z/
  insert_into_file(path, *(args << config), &block)
end
             
            Loads an external file and execute it in the instance binding.
The path to the file to execute. Can be a web address or a relative path from the source root.
apply "http://gist.github.com/103208" apply "recipes/jquery.rb"
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 212
def apply(path, config = {})
  verbose = config.fetch(:verbose, true)
  is_uri  = path =~ %r{^https?\://}
  path    = find_in_source_paths(path) unless is_uri
  say_status :apply, path, verbose
  shell.padding += 1 if verbose
  contents = if is_uri
    require "open-uri"
    open(path, "Accept" => "application/x-thor-template", &:read)
  else
    open(path, &:read)
  end
  instance_eval(contents, path)
  shell.padding -= 1 if verbose
end
             
            Changes the mode of the given file or directory.
the file mode
the name of the file to change mode
give :verbose => false to not log the status.
chmod "script/server", 0755
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 148
def chmod(path, mode, config = {})
  return unless behavior == :invoke
  path = File.expand_path(path, destination_root)
  say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
  unless options[:pretend]
    require "fileutils"
    FileUtils.chmod_R(mode, path)
  end
end
             
            Comment all lines matching a given regex. It will leave the space which existed before the beginning of the line in tact and will insert a single space after the comment hash.
path of the file to be changed
the regexp or string used to decide which lines to comment
give :verbose => false to not log the status.
comment_lines 'config/initializers/session_store.rb', /cookie_store/
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 310
def comment_lines(path, flag, *args)
  flag = flag.respond_to?(:source) ? flag.source : flag
  gsub_file(path, /^(\s*)([^#\n]*#{flag})/, '\1# \2', *args)
end
             
            copy_file "README", "doc/README" copy_file "doc/README"
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 21
def copy_file(source, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  destination = args.first || source
  source = File.expand_path(find_in_source_paths(source.to_s))
  resulting_destination = create_file destination, nil, config do
    content = File.binread(source)
    content = yield(content) if block
    content
  end
  if config[:mode] == :preserve
    mode = File.stat(source).mode
    chmod(resulting_destination, mode, config)
  end
end
             
            Create a new file relative to the destination root with the given data, which is the return value of a block or a data string.
the relative path to the destination root.
the data to append to the file.
give :verbose => false to not log the status.
create_file "lib/fun_party.rb" do hostname = ask("What is the virtual hostname I should use?") "vhost.name = #{hostname}" end create_file "config/apache.conf", "your apache config"
 
               # File bundler/vendor/thor/lib/thor/actions/create_file.rb, line 22
def create_file(destination, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  data = args.first
  action CreateFile.new(self, destination, block || data.to_s, config)
end
             
            Create a new file relative to the destination root from the given source.
the relative path to the destination root.
the relative path to the source root.
give :verbose => false to not log the status.
give :symbolic => false for hard link.
create_link "config/apache.conf", "/etc/apache.conf"
 
               # File bundler/vendor/thor/lib/thor/actions/create_link.rb, line 17
def create_link(destination, *args)
  config = args.last.is_a?(Hash) ? args.pop : {}
  source = args.first
  action CreateLink.new(self, destination, source, config)
end
             
            Returns the root for this thor class (also aliased as destination root).
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 99
def destination_root
  @destination_stack.last
end
             
            Sets the root for this thor class. Relatives path are added to the directory where the script was invoked and expanded.
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 106
def destination_root=(root)
  @destination_stack ||= []
  @destination_stack[0] = File.expand_path(root || "")
end
             
            Copies recursively the files from source directory to root directory. If any of the files finishes with .tt, it’s considered to be a template and is placed in the destination without the extension .tt. If any empty directory is found, it’s copied and all .empty_directory files are ignored. If any file name is wrapped within % signs, the text within the % signs will be executed as a method and replaced with the returned value. Let’s suppose a doc directory with the following files:
doc/ components/.empty_directory README rdoc.rb.tt %app_name%.rb
When invoked as:
directory "doc"
It will create a doc directory in the destination with the following files (assuming that the `app_name` method returns the value “blog”):
doc/ components/ README rdoc.rb blog.rb
Encoded path note: Since Bundler::Thor internals use Object#respond_to? to check if it can expand %something%, this `something` should be a public method in the class calling directory. If a method is private, Bundler::Thor stack raises PrivateMethodEncodedError.
the relative path to the source root.
the relative path to the destination root.
give :verbose => false to not log the status. If :recursive => false, does not look for paths recursively. If :mode => :preserve, preserve the file mode from the source. If :exclude_pattern => /regexp/, prevents copying files that match that regexp.
directory "doc" directory "doc", "docs", :recursive => false
 
               # File bundler/vendor/thor/lib/thor/actions/directory.rb, line 49
def directory(source, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  destination = args.first || source
  action Directory.new(self, source, destination || source, config, &block)
end
             
            Creates an empty directory.
the relative path to the destination root.
give :verbose => false to not log the status.
empty_directory "doc"
 
               # File bundler/vendor/thor/lib/thor/actions/empty_directory.rb, line 13
def empty_directory(destination, config = {})
  action EmptyDirectory.new(self, destination, config)
end
             
            Receives a file or directory and search for it in the source paths.
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 133
def find_in_source_paths(file)
  possible_files = [file, file + TEMPLATE_EXTNAME]
  relative_root = relative_to_original_destination_root(destination_root, false)
  source_paths.each do |source|
    possible_files.each do |f|
      source_file = File.expand_path(f, File.join(source, relative_root))
      return source_file if File.exist?(source_file)
    end
  end
  message = "Could not find #{file.inspect} in any of your source paths. ".dup
  unless self.class.source_root
    message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. "
  end
  message << if source_paths.empty?
               "Currently you have no source paths."
             else
               "Your current source paths are: \n#{source_paths.join("\n")}"
             end
  raise Error, message
end
             
            Gets the content at the given address and places it at the given relative destination. If a block is given instead of destination, the content of the url is yielded and used as location.
get relies on open-uri, so passing application user input
would provide a command injection attack vector.
the address of the given content.
the relative path to the destination root.
give :verbose => false to not log the status.
get "http://gist.github.com/103208", "doc/README" get "http://gist.github.com/103208" do |content| content.split("\n").first end
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 79
def get(source, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  destination = args.first
  render = if source =~ %r{^https?\://}
    require "open-uri"
    URI.send(:open, source) { |input| input.binmode.read }
  else
    source = File.expand_path(find_in_source_paths(source.to_s))
    open(source) { |input| input.binmode.read }
  end
  destination ||= if block_given?
    block.arity == 1 ? yield(render) : yield
  else
    File.basename(source)
  end
  create_file destination, render, config
end
             
            Run a regular expression replacement on a file.
path of the file to be changed
the regexp or string to be replaced
the replacement, can be also given as a block
give :verbose => false to not log the status.
gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1' gsub_file 'README', /rake/, :green do |match| match << " no more. Use thor!" end
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 264
def gsub_file(path, flag, *args, &block)
  return unless behavior == :invoke
  config = args.last.is_a?(Hash) ? args.pop : {}
  path = File.expand_path(path, destination_root)
  say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
  unless options[:pretend]
    content = File.binread(path)
    content.gsub!(flag, *args, &block)
    File.open(path, "wb") { |file| file.write(content) }
  end
end
             
            Goes to the root and execute the given block.
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 196
def in_root
  inside(@destination_stack.first) { yield }
end
             
            Injects text right after the class definition. Since it depends on #insert_into_file, it’s reversible.
path of the file to be changed
the class to be manipulated
the data to append to the class, can be also given as a block.
give :verbose => false to not log the status.
inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n" inject_into_class "app/controllers/application_controller.rb", ApplicationController do " filter_parameter :password\n" end
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 219
def inject_into_class(path, klass, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  config[:after] = /class #{klass}\n|class #{klass} .*\n/
  insert_into_file(path, *(args << config), &block)
end
             
            Injects text right after the module definition. Since it depends on #insert_into_file, it’s reversible.
path of the file to be changed
the module to be manipulated
the data to append to the class, can be also given as a block.
give :verbose => false to not log the status.
inject_into_module "app/helpers/application_helper.rb", ApplicationHelper, " def help; 'help'; end\n" inject_into_module "app/helpers/application_helper.rb", ApplicationHelper do " def help; 'help'; end\n" end
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 242
def inject_into_module(path, module_name, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  config[:after] = /module #{module_name}\n|module #{module_name} .*\n/
  insert_into_file(path, *(args << config), &block)
end
             
             
               # File bundler/vendor/thor/lib/thor/actions/inject_into_file.rb, line 26
def insert_into_file(destination, *args, &block)
  data = block_given? ? block : args.shift
  config = args.shift || {}
  config[:after] = /\z/ unless config.key?(:before) || config.key?(:after)
  action InjectIntoFile.new(self, destination, data, config)
end
             
            Do something in the root or on a provided subfolder. If a relative path is given it’s referenced from the current root. The full path is yielded to the block you provide. The path is set back to the previous path when the method exits.
the directory to move to.
give :verbose => true to log and use padding.
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 168
def inside(dir = "", config = {}, &block)
  verbose = config.fetch(:verbose, false)
  pretend = options[:pretend]
  say_status :inside, dir, verbose
  shell.padding += 1 if verbose
  @destination_stack.push File.expand_path(dir, destination_root)
  # If the directory doesnt exist and we're not pretending
  if !File.exist?(destination_root) && !pretend
    require "fileutils"
    FileUtils.mkdir_p(destination_root)
  end
  if pretend
    # In pretend mode, just yield down to the block
    block.arity == 1 ? yield(destination_root) : yield
  else
    require "fileutils"
    FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
  end
  @destination_stack.pop
  shell.padding -= 1 if verbose
end
             
            Links the file from the relative source to the relative destination. If the destination is not given it’s assumed to be equal to the source.
the relative path to the source root.
the relative path to the destination root.
give :verbose => false to not log the status.
link_file "README", "doc/README" link_file "doc/README"
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 51
def link_file(source, *args)
  config = args.last.is_a?(Hash) ? args.pop : {}
  destination = args.first || source
  source = File.expand_path(find_in_source_paths(source.to_s))
  create_link destination, source, config
end
             
            Prepend text to a file. Since it depends on #insert_into_file, it’s reversible.
path of the file to be changed
the data to prepend to the file, can be also given as a block.
give :verbose => false to not log the status.
prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"' prepend_to_file 'config/environments/test.rb' do 'config.gem "rspec"' end
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 173
def prepend_to_file(path, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  config[:after] = /\A/
  insert_into_file(path, *(args << config), &block)
end
             
            Returns the given path relative to the absolute root (ie, root where the script started).
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 114
def relative_to_original_destination_root(path, remove_dot = true)
  root = @destination_stack[0]
  if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ''].include?(path[root.size..root.size])
    path = path.dup
    path[0...root.size] = '.'
    remove_dot ? (path[2..-1] || "") : path
  else
    path
  end
end
             
            Removes a file at the given location.
path of the file to be changed
give :verbose => false to not log the status.
remove_file 'README' remove_file 'app/controllers/application_controller.rb'
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 327
def remove_file(path, config = {})
  return unless behavior == :invoke
  path = File.expand_path(path, destination_root)
  say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
  if !options[:pretend] && File.exist?(path)
    require "fileutils"
    ::FileUtils.rm_rf(path)
  end
end
             
            Executes a command returning the contents of the command.
the command to be executed.
give :verbose => false to not log the status, :capture => true to hide to output. Specify :with to append an executable to command execution.
inside('vendor') do run('ln -s ~/edge rails') end
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 244
def run(command, config = {})
  return unless behavior == :invoke
  destination = relative_to_original_destination_root(destination_root, false)
  desc = "#{command} from #{destination.inspect}"
  if config[:with]
    desc = "#{File.basename(config[:with].to_s)} #{desc}"
    command = "#{config[:with]} #{command}"
  end
  say_status :run, desc, config.fetch(:verbose, true)
  return if options[:pretend]
  env_splat = [config[:env]] if config[:env]
  if config[:capture]
    require "open3"
    result, status = Open3.capture2e(*env_splat, command.to_s)
    success = status.success?
  else
    result = system(*env_splat, command.to_s)
    success = result
  end
  abort if !success && config.fetch(:abort_on_failure, self.class.exit_on_failure?)
  result
end
             
            Executes a ruby script (taking into account WIN32 platform quirks).
the command to be executed.
give :verbose => false to not log the status.
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 281
def run_ruby_script(command, config = {})
  return unless behavior == :invoke
  run command, config.merge(:with => Bundler::Thor::Util.ruby_command)
end
             
            Holds source paths in instance so they can be manipulated.
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 127
def source_paths
  @source_paths ||= self.class.source_paths_for_search
end
             
            Gets an ERB template at the relative source, executes it and makes a copy at the relative destination. If the destination is not given it’s assumed to be equal to the source removing .tt from the filename.
the relative path to the source root.
the relative path to the destination root.
give :verbose => false to not log the status.
template "README", "doc/README" template "doc/README"
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 115
def template(source, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "")
  source  = File.expand_path(find_in_source_paths(source.to_s))
  context = config.delete(:context) || instance_eval("binding")
  create_file destination, nil, config do
    match = ERB.version.match(/(\d+\.\d+\.\d+)/)
    capturable_erb = if match && match[1] >= "2.2.0" # Ruby 2.6+
      CapturableERB.new(::File.binread(source), :trim_mode => "-", :eoutvar => "@output_buffer")
    else
      CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer")
    end
    content = capturable_erb.tap do |erb|
      erb.filename = source
    end.result(context)
    content = yield(content) if block
    content
  end
end
             
            Run a thor command. A hash of options can be given and it’s converted to switches.
the command to be invoked
arguments to the command
give :verbose => false to not log the status, :capture => true to hide to output. Other options are given as parameter to Bundler::Thor.
thor :install, "http://gist.github.com/103208" #=> thor install http://gist.github.com/103208 thor :list, :all => true, :substring => 'rails' #=> thor list --all --substring=rails
 
               # File bundler/vendor/thor/lib/thor/actions.rb, line 304
def thor(command, *args)
  config  = args.last.is_a?(Hash) ? args.pop : {}
  verbose = config.key?(:verbose) ? config.delete(:verbose) : true
  pretend = config.key?(:pretend) ? config.delete(:pretend) : false
  capture = config.key?(:capture) ? config.delete(:capture) : false
  args.unshift(command)
  args.push Bundler::Thor::Options.to_switches(config)
  command = args.join(" ").strip
  run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
end
             
            Uncomment all lines matching a given regex. It will leave the space which existed before the comment hash in tact but will remove any spacing between the comment hash and the beginning of the line.
path of the file to be changed
the regexp or string used to decide which lines to uncomment
give :verbose => false to not log the status.
uncomment_lines 'config/initializers/session_store.rb', /active_record/
 
               # File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 291
def uncomment_lines(path, flag, *args)
  flag = flag.respond_to?(:source) ? flag.source : flag
  gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args)
end