Module: Thor::Actions

Defined in:
lib/thor/actions.rb,
lib/thor/actions/directory.rb,
lib/thor/actions/create_file.rb,
lib/thor/actions/empty_directory.rb,
lib/thor/actions/inject_into_file.rb,
lib/thor/actions/file_manipulation.rb

Defined Under Namespace

Modules: ClassMethods Classes: CreateFile, Directory, EmptyDirectory, InjectIntoFile

Attribute Summary

Method Summary

Attribute Details

- (Object) behavior

Returns the value of attribute behavior



9
10
11
# File 'lib/thor/actions.rb', line 9

def behavior
  @behavior
end

Method Details

+ (Object) included(base)



11
12
13
# File 'lib/thor/actions.rb', line 11

def self.included(base) #:nodoc:
  base.extend ClassMethods
end

- (Object) action(instance)

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



81
82
83
84
85
86
87
# File 'lib/thor/actions.rb', line 81

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

- (Object) append_file(path, *args, &block)

Append text to a file. Since it depends on inject_into_file, it’s reversible.

Parameters

path:path of the file to be changed
data:the data to append to the file, can be also given as a block.
config:give :verbose => false to not log the status.

Example

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

  append_file 'config/environments/test.rb' do
    'config.gem "rspec"'
  end


143
144
145
146
147
# File 'lib/thor/actions/file_manipulation.rb', line 143

def append_file(path, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  config.merge!(:before => /\z/)
  inject_into_file(path, *(args << config), &block)
end

- (Object) apply(path, config = {})

Loads an external file and execute it in the instance binding.

Parameters

path:The path to the file to execute. Can be a web address or a relative path from the source root.

Examples

  apply "http://gist.github.com/103208"

  apply "recipes/jquery.rb"


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

def apply(path, config={})
  verbose = config.fetch(:verbose, true)
  path    = find_in_source_paths(path) unless path =~ /^http\:\/\//

  say_status :apply, path, verbose
  shell.padding += 1 if verbose
  instance_eval(open(path).read)
  shell.padding -= 1 if verbose
end

- (Object) chmod(path, mode, config = {})

Changes the mode of the given file or directory.

Parameters

mode:the file mode
path:the name of the file to change mode
config:give :verbose => false to not log the status.

Example

  chmod "script/*", 0755


100
101
102
103
104
105
# File 'lib/thor/actions/file_manipulation.rb', line 100

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)
  FileUtils.chmod_R(mode, path) unless options[:pretend]
end

- (Object) copy_file(source, destination = nil, config = {}, &block)

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:the relative path to the source root.
destination:the relative path to the destination root.
config:give :verbose => false to not log the status.

Examples

  copy_file "README", "doc/README"

  copy_file "doc/README"


21
22
23
24
25
26
27
28
29
30
# File 'lib/thor/actions/file_manipulation.rb', line 21

def copy_file(source, destination=nil, config={}, &block)
  destination ||= source
  source = File.expand_path(find_in_source_paths(source.to_s))

  create_file destination, nil, config do
    content = File.read(source)
    content = block.call(content) if block
    content
  end
end

- (Object) create_file(destination, data = nil, config = {}, &block) 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:the relative path to the destination root.
data:the data to append to the file.
config:give :verbose => false to not log the status.

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, config={}, &block)
  action CreateFile.new(self, destination, block || data.to_s, config)
end

- (Object) destination_root

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



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

def destination_root
  @destination_stack.last
end

- (Object) destination_root=(root)

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



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

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

- (Object) directory(source, destination = nil, config = {}, &block)

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. 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:the relative path to the source root.
destination:the relative path to the destination root.
config:give :verbose => false to not log the status. If :recursive => false, does not look for paths recursively.

Examples

  directory "doc"
  directory "doc", "docs", :recursive => false


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

def directory(source, destination=nil, config={}, &block)
  action Directory.new(self, source, destination || source, config, &block)
end

- (Object) empty_directory(destination, config = {})

Creates an empty directory.

Parameters

destination:the relative path to the destination root.
config:give :verbose => false to not log the status.

Examples

  empty_directory "doc"


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

def empty_directory(destination, config={})
  action EmptyDirectory.new(self, destination, config)
end

- (Object) find_in_source_paths(file)

Receives a file or directory and search for it in the source paths.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/thor/actions.rb', line 119

def find_in_source_paths(file)
  relative_root = relative_to_original_destination_root(destination_root, false)

  source_paths.each do |source|
    source_file = File.expand_path(file, File.join(source, relative_root))
    return source_file if File.exists?(source_file)
  end

  if source_paths.empty?
    raise Error, "You don't have any source path defined for class #{self.class.name}. To fix this, " <<
                 "you can define a source_root in your class."
  else
    raise Error, "Could not find #{file.inspect} in source paths."
  end
end

- (Object) get(source, destination = nil, config = {}, &block)

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:the address of the given content.
destination:the relative path to the destination root.
config:give :verbose => false to not log the status.

Examples

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

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


49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/thor/actions/file_manipulation.rb', line 49

def get(source, destination=nil, config={}, &block)
  source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^http\:\/\//
  render = open(source).read

  destination ||= if block_given?
    block.arity == 1 ? block.call(render) : block.call
  else
    File.basename(source)
  end

  create_file destination, render, config
end

- (Object) gsub_file(path, flag, *args, &block)

Run a regular expression replacement on a file.

Parameters

path:path of the file to be changed
flag:the regexp or string to be replaced
replacement:the replacement, can be also given as a block
config:give :verbose => false to not log the status.

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


188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/thor/actions/file_manipulation.rb', line 188

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.read(path)
    content.gsub!(flag, *args, &block)
    File.open(path, 'wb') { |file| file.write(content) }
  end
end

- (Object) in_root

Goes to the root and execute the given block.



160
161
162
# File 'lib/thor/actions.rb', line 160

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

- (Object) inject_into_class(path, klass, *args, &block)

Injects text right after the class definition. Since it depends on inject_into_file, it’s reversible.

Parameters

path:path of the file to be changed
klass:the class to be manipulated
data:the data to append to the class, can be also given as a block.
config:give :verbose => false to not log the status.

Examples

  inject_into_class "app/controllers/application_controller.rb", "  filter_parameter :password\n"

  inject_into_class "app/controllers/application_controller.rb", ApplicationController do
    "  filter_parameter :password\n"
  end


166
167
168
169
170
# File 'lib/thor/actions/file_manipulation.rb', line 166

def inject_into_class(path, klass, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  config.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
  inject_into_file(path, *(args << config), &block)
end

- (Object) inject_into_file(destination, *args, &block)

Injects the given content into a file. Different from gsub_file, this method is reversible.

Parameters

destination:Relative path to the destination root
data:Data to add to the file. Can be given as a block.
config:give :verbose => false to not log the status and the flag for injection (:after or :before).

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


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

def inject_into_file(destination, *args, &block)
  if block_given?
    data, config = block, args.shift
  else
    data, config = args.shift, args.shift
  end
  action InjectIntoFile.new(self, destination, data, config)
end

- (Object) inside(dir = '', config = {}, &block)

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:the directory to move to.
config:give :verbose => true to log and use padding.


144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/thor/actions.rb', line 144

def inside(dir='', config={}, &block)
  verbose = config.fetch(:verbose, false)

  say_status :inside, dir, verbose
  shell.padding += 1 if verbose
  @destination_stack.push File.expand_path(dir, destination_root)

  FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
  FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }

  @destination_stack.pop
  shell.padding -= 1 if verbose
end

- (Object) prepend_file(path, *args, &block)

Prepend text to a file. Since it depends on inject_into_file, it’s reversible.

Parameters

path:path of the file to be changed
data:the data to prepend to the file, can be also given as a block.
config:give :verbose => false to not log the status.

Example

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

  prepend_file 'config/environments/test.rb' do
    'config.gem "rspec"'
  end


122
123
124
125
126
# File 'lib/thor/actions/file_manipulation.rb', line 122

def prepend_file(path, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}
  config.merge!(:after => /\A/)
  inject_into_file(path, *(args << config), &block)
end

- (Object) relative_to_original_destination_root(path, remove_dot = true)

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



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

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

- (Object) remove_file(path, config = {}) Also known as: remove_dir

Removes a file at the given location.

Parameters

path:path of the file to be changed
config:give :verbose => false to not log the status.

Example

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


213
214
215
216
217
218
219
# File 'lib/thor/actions/file_manipulation.rb', line 213

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)
  ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
end

- (Object) run(command, config = {})

Executes a command.

Parameters

command:the command to be executed.
config:give :verbose => false to not log the status. Specify :with to append an executable to command executation.

Example

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


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

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)
  system(command) unless options[:pretend]
end

- (Object) run_ruby_script(command, config = {})

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

Parameters

command:the command to be executed.
config:give :verbose => false to not log the status.


220
221
222
223
# File 'lib/thor/actions.rb', line 220

def run_ruby_script(command, config={})
  return unless behavior == :invoke
  run "#{command}", config.merge(:with => Thor::Util.ruby_command)
end

- (Object) source_paths

Holds source paths in instance so they can be manipulated.



113
114
115
# File 'lib/thor/actions.rb', line 113

def source_paths
  @source_paths ||= self.class.source_paths_for_search
end

- (Object) template(source, destination = nil, config = {}, &block)

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:the relative path to the source root.
destination:the relative path to the destination root.
config:give :verbose => false to not log the status.

Examples

  template "README", "doc/README"

  template "doc/README"


77
78
79
80
81
82
83
84
85
86
87
# File 'lib/thor/actions/file_manipulation.rb', line 77

def template(source, destination=nil, config={}, &block)
  destination ||= source
  source  = File.expand_path(find_in_source_paths(source.to_s))
  context = instance_eval('binding')

  create_file destination, nil, config do
    content = ERB.new(::File.read(source), nil, '-').result(context)
    content = block.call(content) if block
    content
  end
end

- (Object) thor(task, *args)

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

Parameters

task:the task to be invoked
args:arguments to the task
config:give :verbose => false to not log the status. Other options are given as parameter to Thor.

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


242
243
244
245
246
247
248
249
250
251
# File 'lib/thor/actions.rb', line 242

def thor(task, *args)
  config  = args.last.is_a?(Hash) ? args.pop : {}
  verbose = config.key?(:verbose) ? config.delete(:verbose) : true

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

  run command, :with => :thor, :verbose => verbose
end