Module: Thor::Actions

Defined in:
lib/thor/actions.rb,
lib/thor/actions/get.rb,
lib/thor/actions/template.rb,
lib/thor/actions/copy_file.rb,
lib/thor/actions/directory.rb,
lib/thor/actions/templater.rb,
lib/thor/actions/create_file.rb,
lib/thor/actions/empty_directory.rb,
lib/thor/actions/inject_into_file.rb

Overview

Some actions require that a class method called source root is defined in the class. Remember to always cache the source root value, because Ruby __FILE__ always return the relative path, which may lead to mistakes if you are calling an action inside the “inside(path)” method.

Defined Under Namespace

Classes: CopyFile, CreateFile, Directory, EmptyDirectory, Get, InjectIntoFile, Template, Templater

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#behaviorObject

Returns the value of attribute behavior.



14
15
16
# File 'lib/thor/actions.rb', line 14

def behavior
  @behavior
end

Class Method Details

.included(base) ⇒ Object

On inclusion, add some options to base.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/thor/actions.rb', line 18

def self.included(base) #:nodoc:
  return unless base.respond_to?(:class_option)

  base.class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
                              :desc => "Run but do not make any changes"

  base.class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
                            :desc => "Overwrite files that already exist"

  base.class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
                           :desc => "Skip files that already exist"

  base.class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
                            :desc => "Supress status output"
end

Instance Method Details

#action(instance) ⇒ Object

Wraps an action object and call it accordingly to the thor class behavior.



61
62
63
64
65
66
67
# File 'lib/thor/actions.rb', line 61

def action(instance)
  if behavior == :revoke
    instance.revoke!
  else
    instance.invoke!
  end
end

#append_file(path, data = nil, log_status = true, &block) ⇒ Object

Append text to a file.

Parameters

path<String>

path of the file to be changed

data<String>

the data to append to the file, can be also given as a block.

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Example

append_file 'config/environments/test.rb', 'config.gem "rspec"'


277
278
279
280
281
282
# File 'lib/thor/actions.rb', line 277

def append_file(path, data=nil, log_status=true, &block)
  return unless behavior == :invoke
  path = File.expand_path(path, root)
  say_status :append, relative_to_absolute_root(path), log_status
  File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend]
end

#chmod(path, mode, log_status = true) ⇒ Object

Changes the mode of the given file or directory.

Parameters

mode<Integer>

the file mode

path<String>

the name of the file to change mode

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Example

chmod "script/*", 0755


144
145
146
147
148
149
# File 'lib/thor/actions.rb', line 144

def chmod(path, mode, log_status=true)
  return unless behavior == :invoke
  path = File.expand_path(path, root)
  say_status :chmod, relative_to_absolute_root(path), log_status
  FileUtils.chmod_R(mode, path) unless options[:pretend]
end

#copy_file(source, destination = nil, log_status = true) ⇒ Object

Copies 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.

Parameters

source<String>

the relative path to the source root

destination<String>

the relative path to the destination root

log_status<Boolean>

if false, does not log the status. True by default.

Examples

copy_file "README", "doc/README"

copy_file "doc/README"


20
21
22
# File 'lib/thor/actions/copy_file.rb', line 20

def copy_file(source, destination=nil, log_status=true)
  action CopyFile.new(self, source, destination || source, log_status)
end

#create_file(destination, data = nil, log_status = true, &block) ⇒ Object Also known as: add_file

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.

Parameters

destination<String>

the relative path to the destination root.

data<String|NilClass>

the data to append to the file.

log_status<Boolean>

if false, does not log the status. True by default.

Examples

create_file "lib/fun_party.rb" do
  hostname = ask("What is the virtual hostname I should use?")
  "vhost.name = #{hostname}"
end

create_file "config/apach.conf", "your apache config"


23
24
25
# File 'lib/thor/actions/create_file.rb', line 23

def create_file(destination, data=nil, log_status=true, &block)
  action CreateFile.new(self, destination, block || data.to_s, log_status)
end

#directory(source, destination = nil, recursive = true, log_status = true) ⇒ Object

Copies interactively 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. Remember that file paths can also be encoded, 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 is “blog”):

doc/
  components/
  README
  rdoc.rb
  blog.rb

Parameters

source<String>

the relative path to the source root

destination<String>

the relative path to the destination root

recursive<Boolean>

if the directory must be copied recursively, true by default

log_status<Boolean>

if false, does not log the status. True by default.

Examples

directory "doc"
directory "doc", "docs", false


43
44
45
# File 'lib/thor/actions/directory.rb', line 43

def directory(source, destination=nil, recursive=true, log_status=true)
  action Directory.new(self, source, destination || source, recursive, log_status)
end

#empty_directory(destination, log_status = true) ⇒ Object

Creates an empty directory.

Parameters

destination<String>

the relative path to the destination root

log_status<Boolean>

if false, does not log the status. True by default.

Examples

empty_directory "doc"


16
17
18
# File 'lib/thor/actions/empty_directory.rb', line 16

def empty_directory(destination, log_status=true)
  action EmptyDirectory.new(self, nil, destination, log_status)
end

#get(source, destination = nil, log_status = true, &block) ⇒ Object

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.

Parameters

source<String>

the address of the given content

destination<String>

the relative path to the destination root

log_status<Boolean>

if false, does not log the status. True by default.

Examples

get "http://gist.github.com/103208", "doc/README"

get "http://gist.github.com/103208" do |content|
  content.split("\n").first
end


24
25
26
# File 'lib/thor/actions/get.rb', line 24

def get(source, destination=nil, log_status=true, &block)
  action Get.new(self, source, block || destination, log_status)
end

#gsub_file(path, flag, *args, &block) ⇒ Object

Run a regular expression replacement on a file.

Parameters

path<String>

path of the file to be changed

flag<Regexp|String>

the regexp or string to be replaced

replacement<String>

the replacement, can be also given as a block

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Example

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


251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/thor/actions.rb', line 251

def gsub_file(path, flag, *args, &block)
  return unless behavior == :invoke
  log_status = args.last.is_a?(Symbol) || [ true, false ].include?(args.last) ? args.pop : true

  path = File.expand_path(path, root)
  say_status :gsub, relative_to_absolute_root(path), log_status

  unless options[:pretend]
    content = File.read(path)
    content.gsub!(flag, *args, &block)
    File.open(path, 'wb') { |file| file.write(content) }
  end
end

#in_rootObject

Goes to the root and execute the given block.



128
129
130
# File 'lib/thor/actions.rb', line 128

def in_root
  inside(@root_stack.first) { yield }
end

#initialize(args = [], options = {}, config = {}) ⇒ Object

Extends initializer to add more configuration options.

Configuration

behavior<Symbol>

The actions default behavior. Can be :invoke or :revoke. It also accepts :force, :skip and :pretend to set the behavior and the respective option.

root<String>

The root directory needed for some actions. It’s also known as destination root.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/thor/actions.rb', line 44

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.root = config[:root]
end

#inject_into_file(destination, *args, &block) ⇒ Object

Injects the given content into a file. Different from append_file, prepend_file and gsub_file, this method is reversible. By this reason, the flag can only be strings. gsub_file is your friend if you need to deal with more complex cases.

Parameters

destination<String>

Relative path to the destination root

data<String>

Data to add to the file. Can be given as a block.

flag<String>

Flag of where to add the changes.

log_status<Boolean>

If false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Examples

inject_into_file "config/environment.rb", "config.gem thor", :after => "Rails::Initializer.run do |config|\n"

inject_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


25
26
27
28
29
30
31
32
33
34
# File 'lib/thor/actions/inject_into_file.rb', line 25

def inject_into_file(destination, *args, &block)
  if block_given?
    data, flag = block, args.shift
  else
    data, flag = args.shift, args.shift
  end

  log_status = args.empty? || args.pop
  action InjectIntoFile.new(self, destination, data, flag, log_status)
end

#inside(dir = '', &block) ⇒ Object

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.

Parameters

dir<String>

the directory to move to.



119
120
121
122
123
124
# File 'lib/thor/actions.rb', line 119

def inside(dir='', &block)
  @root_stack.push File.expand_path(dir, root)
  FileUtils.mkdir_p(root) unless File.exist?(root)
  FileUtils.cd(root) { block.arity == 1 ? yield(root) : yield }
  @root_stack.pop
end

#prepend_file(path, data = nil, log_status = true, &block) ⇒ Object

Prepend text to a file.

Parameters

path<String>

path of the file to be changed

data<String>

the data to prepend to the file, can be also given as a block.

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Example

prepend_file 'config/environments/test.rb', 'config.gem "rspec"'


296
297
298
299
300
301
302
303
304
305
306
# File 'lib/thor/actions.rb', line 296

def prepend_file(path, data=nil, log_status=true, &block)
  return unless behavior == :invoke
  path = File.expand_path(path, root)
  say_status :prepend, relative_to_absolute_root(path), log_status

  unless options[:pretend]
    content = data || block.call
    content << File.read(path)
    File.open(path, 'wb') { |file| file.write(content) }
  end
end

#relative_root(remove_dot = true) ⇒ Object

Gets the current root relative to the absolute root.

inside "foo" do
  relative_root #=> "foo"
end


90
91
92
# File 'lib/thor/actions.rb', line 90

def relative_root(remove_dot=true)
  relative_to_absolute_root(root, remove_dot)
end

#relative_to_absolute_root(path, remove_dot = true) ⇒ Object

Returns the given path relative to the absolute root (ie, root where the script started).



97
98
99
100
# File 'lib/thor/actions.rb', line 97

def relative_to_absolute_root(path, remove_dot=true)
  path = path.gsub(@root_stack[0], '.')
  remove_dot ? (path[2..-1] || '') : path
end

#remove_file(path, log_status = true) ⇒ Object

Removes a file at the given location.

Parameters

path<String>

path of the file to be changed

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Example

remove_file 'README'
remove_file 'app/controllers/application_controller.rb'


225
226
227
228
229
230
231
232
# File 'lib/thor/actions.rb', line 225

def remove_file(path, log_status=true)
  return unless behavior == :invoke
  path  = File.expand_path(path, root)
  color = log_status.is_a?(Symbol) ? log_status : :red

  say_status :remove, relative_to_absolute_root(path), log_status
  ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
end

#rootObject Also known as: destination_root

Returns the root for this thor class (also aliased as destination root).



71
72
73
# File 'lib/thor/actions.rb', line 71

def root
  @root_stack.last
end

#root=(root) ⇒ Object

Sets the root for this thor class. Relatives path are added to the directory where the script was invoked and expanded.



79
80
81
82
# File 'lib/thor/actions.rb', line 79

def root=(root)
  @root_stack ||= []
  @root_stack[0] = File.expand_path(root || '')
end

#run(command, log_status = true) ⇒ Object

Executes a command.

Parameters

command<String>

the command to be executed.

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Example

inside('vendor') do
  run('ln -s ~/edge rails')
end


164
165
166
167
168
# File 'lib/thor/actions.rb', line 164

def run(command, log_status=true)
  return unless behavior == :invoke
  say_status :run, "#{command} from #{relative_to_absolute_root(root, false)}", log_status
  `#{command}` unless options[:pretend]
end

#run_ruby_script(command, log_status = true) ⇒ Object

Executes a ruby script (taking into account WIN32 platform quirks).

Parameters

command<String>

the command to be executed.

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.



177
178
179
180
181
# File 'lib/thor/actions.rb', line 177

def run_ruby_script(command, log_status=true)
  return unless behavior == :invoke
  say_status File.basename(Thor::Util.ruby_command), command, log_status
  `#{Thor::Util.ruby_command} #{command}` unless options[:pretend]
end

#source_rootObject

Get the source root in the class. Raises an error if a source root is not specified in the thor class.



105
106
107
108
109
# File 'lib/thor/actions.rb', line 105

def source_root
  self.class.source_root
rescue NoMethodError => e
  raise NoMethodError, "You have to specify the class method source_root in your thor class."
end

#template(source, destination = nil, log_status = true) ⇒ Object

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.

Parameters

source<String>

the relative path to the source root

destination<String>

the relative path to the destination root

log_status<Boolean>

if false, does not log the status. True by default.

Examples

template "README", "doc/README"

template "doc/README"


22
23
24
25
# File 'lib/thor/actions/template.rb', line 22

def template(source, destination=nil, log_status=true)
  destination ||= source.gsub(/.tt$/, '')
  action Template.new(self, source, destination, log_status)
end

#thor(task, *args) ⇒ Object

Run a thor command. A hash of options can be given and it’s converted to switches.

Parameters

task<String>

the task to be invoked

args<Array>

arguments to the task

options<Hash>

a hash with options used on invocation

log_status<Boolean>

if false, does not log the status. True by default. If a symbol is given, uses it as the output color.

Examples

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


201
202
203
204
205
206
207
208
209
210
211
# File 'lib/thor/actions.rb', line 201

def thor(task, *args)
  log_status = args.last.is_a?(Symbol) || [true, false].include?(args.last) ? args.pop : true
  options    = args.last.is_a?(Hash) ? args.pop : {}

  args.unshift task
  args.push Thor::Options.to_switches(options)
  command = args.join(' ').strip

  say_status :thor, command, log_status
  run "thor #{command}", false
end