模块 Bundler::Thor::Actions

常量

警告

将给定的内容注入到文件中。与gsub_file不同,此方法是可逆的。

参数

destination<字符串>

目标根目录的相对路径

data<字符串>

要添加到文件中的数据。可以作为代码块给出。

config<哈希>

提供 :verbose => false 以不记录状态和注入标志(:after 或 :before),或 :force => true 以多次插入相同的内容。

示例

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

属性

behavior[RW]
output_buffer[RW]

公共类方法

new(args = [], options = {}, config = {}) 单击以切换源代码

扩展初始化器以添加更多配置选项。

配置

behavior<符号>

操作的默认行为。可以是 :invoke 或 :revoke。它也接受 :force、:skip 和 :pretend 来设置行为和相应的选项。

destination_root<字符串>

某些操作所需的根目录。

调用父类方法
# 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

公共实例方法

add_file(destination, *args, &block)
别名为:create_file
append_file(path, *args, &block)
别名为:append_to_file
append_to_file(path, *args, &block) 单击以切换源代码

将文本附加到文件。由于它依赖于insert_into_file,因此它是可逆的。

参数

path<字符串>

要更改的文件的路径

data<字符串>

要附加到文件的数据,也可以作为代码块给出。

config<哈希>

提供 :verbose => false 以不记录状态。

示例

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 192
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
也别名为:append_file
apply(path, config = {}) 单击以切换源代码

加载外部文件并在实例绑定中执行它。

参数

path<字符串>

要执行的文件的路径。可以是 Web 地址或源根目录的相对路径。

示例

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

apply "recipes/jquery.rb"
# File bundler/vendor/thor/lib/thor/actions.rb, line 216
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"
    URI.open(path, "Accept" => "application/x-thor-template", &:read)
  else
    File.open(path, &:read)
  end

  instance_eval(contents, path)
  shell.padding -= 1 if verbose
end
chmod(path, mode, config = {}) 单击以切换源代码

更改给定文件或目录的模式。

参数

mode<整数>

文件模式

path<字符串>

要更改模式的文件名

config<哈希>

提供 :verbose => false 以不记录状态。

示例

chmod "script/server", 0755
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 145
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_lines(path, flag, *args) 单击以切换源代码

注释所有与给定正则表达式匹配的行。它将保留行开始之前的空格,并在注释哈希之后插入一个空格。

参数

path<字符串>

要更改的文件的路径

flag<正则表达式|字符串>

用于决定要注释哪些行的正则表达式或字符串

config<哈希>

提供 :verbose => false 以不记录状态。

示例

comment_lines 'config/initializers/session_store.rb', /cookie_store/
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 308
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(source, *args) { |content| ... } 单击以切换源代码

将文件从相对源复制到相对目标。如果未给出目标,则假定它等于源。

参数

source<字符串>

源根目录的相对路径。

destination<字符串>

目标根目录的相对路径。

config<哈希>

提供 :verbose => false 以不记录状态,以及 :mode => :preserve,以保留源文件模式。

示例

copy_file "README", "doc/README"

copy_file "doc/README"
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 20
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_file(destination, *args, &block) 单击以切换源代码

使用给定数据(它是代码块的返回值或数据字符串)创建相对于目标根目录的新文件。

参数

destination<字符串>

目标根目录的相对路径。

data<字符串|NilClass>

要附加到文件的数据。

config<哈希>

提供 :verbose => false 以不记录状态。

示例

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
也别名为:add_file
destination_root() 单击以切换源代码

返回此 thor 类的根目录(也别名为目标根目录)。

# File bundler/vendor/thor/lib/thor/actions.rb, line 99
def destination_root
  @destination_stack.last
end
destination_root=(root) 单击以切换源代码

设置此 thor 类的根目录。相对路径被添加到调用脚本的目录中并展开。

# File bundler/vendor/thor/lib/thor/actions.rb, line 106
def destination_root=(root)
  @destination_stack ||= []
  @destination_stack[0] = File.expand_path(root || "")
end
directory(source, *args, &block) 单击以切换源代码

将文件从源目录递归复制到根目录。如果任何文件以 .tt 结尾,则将其视为模板并放置在没有扩展名 .tt 的目标中。如果找到任何空目录,则将其复制,并且所有 .empty_directory 文件都将被忽略。如果任何文件名都用 % 符号括起来,则 % 符号中的文本将作为方法执行,并替换为返回的值。假设一个 doc 目录包含以下文件

doc/
  components/.empty_directory
  README
  rdoc.rb.tt
  %app_name%.rb

当调用为

directory "doc"

它将在目标中创建一个 doc 目录,其中包含以下文件(假设 `app_name` 方法返回值为 “blog”)

doc/
  components/
  README
  rdoc.rb
  blog.rb

编码路径注意:由于 Bundler::Thor 内部使用 Object#respond_to? 来检查它是否可以展开 %something%,因此 `something` 应该是调用 directory 的类中的公共方法。如果方法是私有的,则 Bundler::Thor 堆栈会引发 PrivateMethodEncodedError。

参数

source<字符串>

源根目录的相对路径。

destination<字符串>

目标根目录的相对路径。

config<哈希>

提供 :verbose => false 以不记录状态。如果 :recursive => false,则不递归查找路径。如果 :mode => :preserve,则保留源文件模式。如果 :exclude_pattern => /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
empty_directory(destination, config = {}) 单击以切换源代码

创建一个空目录。

参数

destination<字符串>

目标根目录的相对路径。

config<哈希>

提供 :verbose => false 以不记录状态。

示例

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
find_in_source_paths(file) 单击以切换源代码

接收文件或目录并在源路径中搜索它。

# 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
get(source, *args) { |render| ... } 单击以切换源代码

获取给定地址的内容并将其放置在给定的相对目标位置。如果给出了代码块而不是目标,则会生成 URL 的内容并将其用作位置。

get 依赖于 open-uri,因此传递应用程序用户输入将提供命令注入攻击向量。

参数

source<字符串>

给定内容的地址。

destination<字符串>

目标根目录的相对路径。

config<哈希>

提供 :verbose => false 以不记录状态,以及 :http_headers => <哈希> 以将标头添加到 HTTP 请求。

示例

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

get "http://gist.github.com/103208", "doc/README", :http_headers => {"Content-Type" => "application/json"}

get "http://gist.github.com/103208" do |content|
  content.split("\n").first
end
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 81
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, config.fetch(:http_headers, {})) { |input| input.binmode.read }
  else
    source = File.expand_path(find_in_source_paths(source.to_s))
    File.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
gsub_file(path, flag, *args, &block) 单击以切换源代码

在文件上运行正则表达式替换。

参数

path<字符串>

要更改的文件的路径

flag<正则表达式|字符串>

要替换的正则表达式或字符串

replacement<字符串>

替换内容,也可以以代码块的形式给出。

config<哈希>

使用 `:verbose => false` 来不记录状态,使用 `:force => true` 来强制替换,而忽略执行器的行为。

示例

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 262
def gsub_file(path, flag, *args, &block)
  config = args.last.is_a?(Hash) ? args.pop : {}

  return unless behavior == :invoke || config.fetch(:force, false)

  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
in_root() { || ... } 点击切换源代码

进入根目录并执行给定的代码块。

# File bundler/vendor/thor/lib/thor/actions.rb, line 200
def in_root
  inside(@destination_stack.first) { yield }
end
inject_into_class(path, klass, *args, &block) 点击切换源代码

在类定义之后立即注入文本。由于它依赖于 insert_into_file,因此是可逆的。

参数

path<字符串>

要更改的文件的路径

klass<String|Class>

要操作的类

data<字符串>

要追加到类的数据,也可以以代码块的形式给出。

config<哈希>

提供 :verbose => false 以不记录状态。

示例

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 216
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
inject_into_file(destination, *args, &block)
inject_into_module(path, module_name, *args, &block) 点击切换源代码

在模块定义之后立即注入文本。由于它依赖于 insert_into_file,因此是可逆的。

参数

path<字符串>

要更改的文件的路径

module_name<String|Class>

要操作的模块

data<字符串>

要追加到类的数据,也可以以代码块的形式给出。

config<哈希>

提供 :verbose => false 以不记录状态。

示例

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 239
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
insert_into_file(destination, *args, &block) 点击切换源代码
# 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
也别名为: inject_into_file
inside(dir = "", config = {}) { |destination_root| ... } 点击切换源代码

在根目录或提供的子文件夹中执行某些操作。如果给出了相对路径,则从当前根目录引用。完整路径会传递给您提供的代码块。当方法退出时,路径将设置回先前的路径。

返回代码块产生的值。

参数

dir<String>

要移动到的目录。

config<哈希>

使用 `:verbose => true` 来记录并使用填充。

# File bundler/vendor/thor/lib/thor/actions.rb, line 170
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 doesn't exist and we're not pretending
  if !File.exist?(destination_root) && !pretend
    require "fileutils"
    FileUtils.mkdir_p(destination_root)
  end

  result = nil
  if pretend
    # In pretend mode, just yield down to the block
    result = block.arity == 1 ? yield(destination_root) : yield
  else
    require "fileutils"
    FileUtils.cd(destination_root) { result = block.arity == 1 ? yield(destination_root) : yield }
  end

  @destination_stack.pop
  shell.padding -= 1 if verbose
  result
end
prepend_file(path, *args, &block)
prepend_to_file(path, *args, &block) 点击切换源代码

将文本前置到文件。由于它依赖于 insert_into_file,因此是可逆的。

参数

path<字符串>

要更改的文件的路径

data<字符串>

要前置到文件的数据,也可以以代码块的形式给出。

config<哈希>

提供 :verbose => false 以不记录状态。

示例

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 170
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
也别名为: prepend_file
relative_to_original_destination_root(path, remove_dot = true) 点击切换源代码

返回相对于绝对根目录(即脚本启动的根目录)的给定路径。

# 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
remove_dir(path, config = {})
别名: remove_file
remove_file(path, config = {}) 点击切换源代码

删除给定位置的文件。

参数

path<字符串>

要更改的文件的路径

config<哈希>

提供 :verbose => false 以不记录状态。

示例

remove_file 'README'
remove_file 'app/controllers/application_controller.rb'
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 325
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) || File.symlink?(path))
    require "fileutils"
    ::FileUtils.rm_rf(path)
  end
end
也别名为: remove_dir
run(command, config = {}) 点击切换源代码

执行命令并返回命令的内容。

参数

command<String>

要执行的命令。

config<哈希>

使用 `:verbose => false` 来不记录状态,`:capture => true` 来隐藏输出。指定 `:with` 来将可执行文件追加到命令执行中。

示例

inside('vendor') do
  run('ln -s ~/edge rails')
end
# File bundler/vendor/thor/lib/thor/actions.rb, line 248
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
run_ruby_script(command, config = {}) 点击切换源代码

执行 Ruby 脚本(考虑 WIN32 平台特性)。

参数

command<String>

要执行的命令。

config<哈希>

提供 :verbose => false 以不记录状态。

# File bundler/vendor/thor/lib/thor/actions.rb, line 285
def run_ruby_script(command, config = {})
  return unless behavior == :invoke
  run command, config.merge(with: Bundler::Thor::Util.ruby_command)
end
source_paths() 点击切换源代码

在实例中保存源路径,以便可以对其进行操作。

# File bundler/vendor/thor/lib/thor/actions.rb, line 127
def source_paths
  @source_paths ||= self.class.source_paths_for_search
end
template(source, *args) { |content| ... } 点击切换源代码

获取相对源位置的 ERB 模板,执行它并在相对目标位置创建一个副本。如果未给出目标,则假定其与源相同,并从文件名中删除 .tt。

参数

source<字符串>

源根目录的相对路径。

destination<字符串>

目标根目录的相对路径。

config<哈希>

提供 :verbose => false 以不记录状态。

示例

template "README", "doc/README"

template "doc/README"
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 117
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
    capturable_erb = CapturableERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer")
    content = capturable_erb.tap do |erb|
      erb.filename = source
    end.result(context)
    content = yield(content) if block
    content
  end
end
thor(command, *args) 点击切换源代码

运行 Thor 命令。可以给出选项的哈希,并将其转换为开关。

参数

command<String>

要调用的命令

args<Array>

命令的参数

config<哈希>

使用 `:verbose => false` 来不记录状态,`:capture => true` 来隐藏输出。其他选项作为参数传递给 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 308
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_lines(path, flag, *args) 点击切换源代码

取消注释与给定正则表达式匹配的所有行。保留注释哈希之前的缩进,并删除哈希和任何紧随其后的空格。

参数

path<字符串>

要更改的文件的路径

flag<正则表达式|字符串>

用于确定要取消注释的行的正则表达式或字符串

config<哈希>

提供 :verbose => false 以不记录状态。

示例

uncomment_lines 'config/initializers/session_store.rb', /active_record/
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 289
def uncomment_lines(path, flag, *args)
  flag = flag.respond_to?(:source) ? flag.source : flag

  gsub_file(path, /^(\s*)#[[:blank:]]?(.*#{flag})/, '\1\2', *args)
end

私有实例方法

capture(*args) { |*args| ... } 点击切换源代码
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 346
def capture(*args)
  with_output_buffer { yield(*args) }
end
concat(string) 点击切换源代码
# File bundler/vendor/thor/lib/thor/actions/file_manipulation.rb, line 342
def concat(string)
  @output_buffer.concat(string)
end