From d6a590a7107eabd9c3ab067c60bef904da62f174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 16 Jul 2009 11:17:19 +0200 Subject: Modified rake tasks to use new app generator structure and updated Thor version. --- railties/lib/generators/actions.rb | 11 +- railties/lib/generators/rails/app/app_generator.rb | 5 +- .../lib/generators/rails/metal/metal_generator.rb | 2 +- .../generators/rails/plugin/plugin_generator.rb | 4 +- railties/lib/tasks/framework.rake | 68 ++- railties/lib/vendor/thor-0.11.1/CHANGELOG.rdoc | 75 --- railties/lib/vendor/thor-0.11.1/LICENSE | 20 - railties/lib/vendor/thor-0.11.1/README.markdown | 247 ---------- railties/lib/vendor/thor-0.11.1/bin/rake2thor | 87 ---- railties/lib/vendor/thor-0.11.1/bin/thor | 7 - railties/lib/vendor/thor-0.11.1/lib/thor.rb | 231 --------- .../lib/vendor/thor-0.11.1/lib/thor/actions.rb | 242 ---------- .../thor-0.11.1/lib/thor/actions/create_file.rb | 102 ---- .../thor-0.11.1/lib/thor/actions/directory.rb | 87 ---- .../lib/thor/actions/empty_directory.rb | 133 ------ .../lib/thor/actions/file_manipulation.rb | 194 -------- .../lib/thor/actions/inject_into_file.rb | 78 ---- railties/lib/vendor/thor-0.11.1/lib/thor/base.rb | 515 --------------------- .../thor/core_ext/hash_with_indifferent_access.rb | 75 --- .../thor-0.11.1/lib/thor/core_ext/ordered_hash.rb | 102 ---- railties/lib/vendor/thor-0.11.1/lib/thor/error.rb | 27 -- railties/lib/vendor/thor-0.11.1/lib/thor/group.rb | 240 ---------- .../lib/vendor/thor-0.11.1/lib/thor/invocation.rb | 192 -------- railties/lib/vendor/thor-0.11.1/lib/thor/parser.rb | 4 - .../vendor/thor-0.11.1/lib/thor/parser/argument.rb | 67 --- .../thor-0.11.1/lib/thor/parser/arguments.rb | 145 ------ .../vendor/thor-0.11.1/lib/thor/parser/option.rb | 132 ------ .../vendor/thor-0.11.1/lib/thor/parser/options.rb | 142 ------ railties/lib/vendor/thor-0.11.1/lib/thor/runner.rb | 295 ------------ railties/lib/vendor/thor-0.11.1/lib/thor/shell.rb | 72 --- .../lib/vendor/thor-0.11.1/lib/thor/shell/basic.rb | 221 --------- .../lib/vendor/thor-0.11.1/lib/thor/shell/color.rb | 106 ----- railties/lib/vendor/thor-0.11.1/lib/thor/task.rb | 108 ----- railties/lib/vendor/thor-0.11.1/lib/thor/tasks.rb | 4 - .../vendor/thor-0.11.1/lib/thor/tasks/install.rb | 35 -- .../vendor/thor-0.11.1/lib/thor/tasks/package.rb | 31 -- .../lib/vendor/thor-0.11.1/lib/thor/tasks/spec.rb | 70 --- railties/lib/vendor/thor-0.11.1/lib/thor/util.rb | 229 --------- railties/lib/vendor/thor-0.11.2/CHANGELOG.rdoc | 75 +++ railties/lib/vendor/thor-0.11.2/LICENSE | 20 + railties/lib/vendor/thor-0.11.2/README.markdown | 247 ++++++++++ railties/lib/vendor/thor-0.11.2/bin/rake2thor | 87 ++++ railties/lib/vendor/thor-0.11.2/bin/thor | 7 + railties/lib/vendor/thor-0.11.2/lib/thor.rb | 231 +++++++++ .../lib/vendor/thor-0.11.2/lib/thor/actions.rb | 240 ++++++++++ .../thor-0.11.2/lib/thor/actions/create_file.rb | 102 ++++ .../thor-0.11.2/lib/thor/actions/directory.rb | 87 ++++ .../lib/thor/actions/empty_directory.rb | 133 ++++++ .../lib/thor/actions/file_manipulation.rb | 194 ++++++++ .../lib/thor/actions/inject_into_file.rb | 78 ++++ railties/lib/vendor/thor-0.11.2/lib/thor/base.rb | 515 +++++++++++++++++++++ .../thor/core_ext/hash_with_indifferent_access.rb | 75 +++ .../thor-0.11.2/lib/thor/core_ext/ordered_hash.rb | 102 ++++ railties/lib/vendor/thor-0.11.2/lib/thor/error.rb | 27 ++ railties/lib/vendor/thor-0.11.2/lib/thor/group.rb | 262 +++++++++++ .../lib/vendor/thor-0.11.2/lib/thor/invocation.rb | 172 +++++++ railties/lib/vendor/thor-0.11.2/lib/thor/parser.rb | 4 + .../vendor/thor-0.11.2/lib/thor/parser/argument.rb | 67 +++ .../thor-0.11.2/lib/thor/parser/arguments.rb | 145 ++++++ .../vendor/thor-0.11.2/lib/thor/parser/option.rb | 132 ++++++ .../vendor/thor-0.11.2/lib/thor/parser/options.rb | 142 ++++++ railties/lib/vendor/thor-0.11.2/lib/thor/runner.rb | 295 ++++++++++++ railties/lib/vendor/thor-0.11.2/lib/thor/shell.rb | 72 +++ .../lib/vendor/thor-0.11.2/lib/thor/shell/basic.rb | 221 +++++++++ .../lib/vendor/thor-0.11.2/lib/thor/shell/color.rb | 106 +++++ railties/lib/vendor/thor-0.11.2/lib/thor/task.rb | 108 +++++ railties/lib/vendor/thor-0.11.2/lib/thor/tasks.rb | 4 + .../vendor/thor-0.11.2/lib/thor/tasks/install.rb | 35 ++ .../vendor/thor-0.11.2/lib/thor/tasks/package.rb | 31 ++ .../lib/vendor/thor-0.11.2/lib/thor/tasks/spec.rb | 70 +++ railties/lib/vendor/thor-0.11.2/lib/thor/util.rb | 229 +++++++++ railties/lib/vendor/thor.rb | 4 +- railties/test/generators/actions_test.rb | 13 + 73 files changed, 4371 insertions(+), 4366 deletions(-) delete mode 100644 railties/lib/vendor/thor-0.11.1/CHANGELOG.rdoc delete mode 100644 railties/lib/vendor/thor-0.11.1/LICENSE delete mode 100644 railties/lib/vendor/thor-0.11.1/README.markdown delete mode 100755 railties/lib/vendor/thor-0.11.1/bin/rake2thor delete mode 100755 railties/lib/vendor/thor-0.11.1/bin/thor delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/actions.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/actions/create_file.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/actions/directory.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/actions/empty_directory.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/actions/file_manipulation.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/actions/inject_into_file.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/base.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/hash_with_indifferent_access.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/ordered_hash.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/error.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/group.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/invocation.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/parser.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/parser/argument.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/parser/arguments.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/parser/option.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/parser/options.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/runner.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/shell.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/shell/basic.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/shell/color.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/task.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/tasks.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/tasks/install.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/tasks/package.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/tasks/spec.rb delete mode 100644 railties/lib/vendor/thor-0.11.1/lib/thor/util.rb create mode 100644 railties/lib/vendor/thor-0.11.2/CHANGELOG.rdoc create mode 100644 railties/lib/vendor/thor-0.11.2/LICENSE create mode 100644 railties/lib/vendor/thor-0.11.2/README.markdown create mode 100755 railties/lib/vendor/thor-0.11.2/bin/rake2thor create mode 100755 railties/lib/vendor/thor-0.11.2/bin/thor create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/actions.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/actions/create_file.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/actions/directory.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/actions/empty_directory.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/actions/file_manipulation.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/actions/inject_into_file.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/base.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/hash_with_indifferent_access.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/ordered_hash.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/error.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/group.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/invocation.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/parser.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/parser/argument.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/parser/arguments.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/parser/option.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/parser/options.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/runner.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/shell.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/shell/basic.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/shell/color.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/task.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/tasks.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/tasks/install.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/tasks/package.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/tasks/spec.rb create mode 100644 railties/lib/vendor/thor-0.11.2/lib/thor/util.rb (limited to 'railties') diff --git a/railties/lib/generators/actions.rb b/railties/lib/generators/actions.rb index 81db0b7c37..795d420229 100644 --- a/railties/lib/generators/actions.rb +++ b/railties/lib/generators/actions.rb @@ -16,13 +16,14 @@ module Rails # # apply "recipes/jquery.rb" # - def apply(path) - path = find_in_source_paths(path) unless path =~ /^http\:\/\// + def apply(path, options={}) + verbose = options.fetch(:verbose, true) + path = find_in_source_paths(path) unless path =~ /^http\:\/\// - log :apply, path - shell.padding += 1 + log :apply, path, verbose + shell.padding += 1 if verbose instance_eval(open(path).read) - shell.padding -= 1 + shell.padding -= 1 if verbose end # Install a plugin. You must provide either a Subversion url or Git url. diff --git a/railties/lib/generators/rails/app/app_generator.rb b/railties/lib/generators/rails/app/app_generator.rb index eaeb49903a..0c9bbeb847 100644 --- a/railties/lib/generators/rails/app/app_generator.rb +++ b/railties/lib/generators/rails/app/app_generator.rb @@ -66,7 +66,6 @@ module Rails::Generators empty_directory "config" inside "config" do - copy_file "boot.rb" copy_file "routes.rb" template "environment.rb" @@ -76,6 +75,10 @@ module Rails::Generators end end + def create_boot_file + copy_file "config/boot.rb" + end + def create_activerecord_files return if options[:skip_activerecord] template "config/databases/#{options[:database]}.yml", "config/database.yml" diff --git a/railties/lib/generators/rails/metal/metal_generator.rb b/railties/lib/generators/rails/metal/metal_generator.rb index d814b6c38b..fe4f945cad 100644 --- a/railties/lib/generators/rails/metal/metal_generator.rb +++ b/railties/lib/generators/rails/metal/metal_generator.rb @@ -3,7 +3,7 @@ module Rails class MetalGenerator < NamedBase check_class_collision - def create_file + def create_metal_file template "metal.rb", "app/metal/#{file_name}.rb" end end diff --git a/railties/lib/generators/rails/plugin/plugin_generator.rb b/railties/lib/generators/rails/plugin/plugin_generator.rb index dcdc125867..ee785caf7d 100644 --- a/railties/lib/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/generators/rails/plugin/plugin_generator.rb @@ -21,13 +21,13 @@ module Rails end hook_for :generator do |instance, generator| - instance.inside_with_padding instance.send(:plugin_dir) do + instance.inside instance.send(:plugin_dir), :verbose => true do instance.invoke generator, [ instance.name ], :namespace => false end end hook_for :test_framework do |instance, test_framework| - instance.inside_with_padding instance.send(:plugin_dir) do + instance.inside instance.send(:plugin_dir), :verbose => true do instance.invoke test_framework end end diff --git a/railties/lib/tasks/framework.rake b/railties/lib/tasks/framework.rake index b6f2f2bc18..72cba5ce8b 100644 --- a/railties/lib/tasks/framework.rake +++ b/railties/lib/tasks/framework.rake @@ -78,51 +78,48 @@ namespace :rails do end desc "Update both configs, scripts and public/javascripts from Rails" - task :update => [ "update:scripts", "update:javascripts", "update:configs", "update:application_controller" ] + task :update => [ "update:configs", "update:javascripts", "update:scripts", "update:application_controller" ] desc "Applies the template supplied by LOCATION=/path/to/template" task :template do - require 'rails_generator/generators/applications/app/template_runner' template = ENV["LOCATION"] template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} - Rails::TemplateRunner.new(template) + + require 'generators' + generator = Rails::Generators::Base.new [], {}, :destination_root => RAILS_ROOT + generator.apply template, :verbose => false end namespace :update do - desc "Add new scripts to the application script/ directory" - task :scripts do - local_base = "script" - edge_base = "#{File.dirname(__FILE__)}/../../bin" - - local = Dir["#{local_base}/**/*"].reject { |path| File.directory?(path) } - edge = Dir["#{edge_base}/**/*"].reject { |path| File.directory?(path) } - - edge.each do |script| - base_name = script[(edge_base.length+1)..-1] - next if base_name == "rails" - next if local.detect { |path| base_name == path[(local_base.length+1)..-1] } - if !File.directory?("#{local_base}/#{File.dirname(base_name)}") - mkdir_p "#{local_base}/#{File.dirname(base_name)}" - end - install script, "#{local_base}/#{base_name}", :mode => 0755 - end - end + def invoke_from_app_generator(method) + require 'generators' + require 'generators/rails/app/app_generator' - desc "Update your javascripts from your current rails install" - task :javascripts do - require 'railties_path' - project_dir = RAILS_ROOT + '/public/javascripts/' - scripts = Dir[RAILTIES_PATH + '/html/javascripts/*.js'] - scripts.reject!{|s| File.basename(s) == 'application.js'} if File.exist?(project_dir + 'application.js') - FileUtils.cp(scripts, project_dir) + generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true }, + :destination_root => RAILS_ROOT + generator.invoke(method) end desc "Update config/boot.rb from your current rails install" task :configs do - require 'railties_path' - FileUtils.cp(RAILTIES_PATH + '/environments/boot.rb', RAILS_ROOT + '/config/boot.rb') + invoke_from_app_generator :create_boot_file + end + + desc "Update Prototype javascripts from your current rails install" + task :javascripts do + invoke_from_app_generator :create_prototype_files + end + + desc "Generate dispatcher files in RAILS_ROOT/public" + task :generate_dispatchers do + invoke_from_app_generator :create_dispatch_files end - + + desc "Add new scripts to the application script/ directory" + task :scripts do + invoke_from_app_generator :create_script_files + end + desc "Rename application.rb to application_controller.rb" task :application_controller do old_style = RAILS_ROOT + '/app/controllers/application.rb' @@ -132,14 +129,5 @@ namespace :rails do puts "#{old_style} has been renamed to #{new_style}, update your SCM as necessary" end end - - desc "Generate dispatcher files in RAILS_ROOT/public" - task :generate_dispatchers do - require 'railties_path' - FileUtils.cp(RAILTIES_PATH + '/dispatches/config.ru', RAILS_ROOT + '/config.ru') - FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.fcgi', RAILS_ROOT + '/public/dispatch.fcgi') - FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.rb') - FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.cgi') - end end end diff --git a/railties/lib/vendor/thor-0.11.1/CHANGELOG.rdoc b/railties/lib/vendor/thor-0.11.1/CHANGELOG.rdoc deleted file mode 100644 index 544dde8c02..0000000000 --- a/railties/lib/vendor/thor-0.11.1/CHANGELOG.rdoc +++ /dev/null @@ -1,75 +0,0 @@ -== TODO - -* Improve spec coverage for Thor::Runner -* Improve help output to list shorthand switches, too - -== Current - -* BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore - since it wrong behavior to the invocation system. - -* thor help now show information about any class/task. All those calls are - possible: - - thor help describe - thor help describe:amazing - - Or even with default namespaces: - - thor help :spec - -* Thor::Runner now invokes the default task if none is supplied: - - thor describe # invokes the default task, usually help - -* Thor::Runner now works with mappings: - - thor describe -h - -* Added some documentation and code refactoring. - -== 0.9.8, released 2008-10-20 - -* Fixed some tiny issues that were introduced lately. - -== 0.9.7, released 2008-10-13 - -* Setting global method options on the initialize method works as expected: - All other tasks will accept these global options in addition to their own. -* Added 'group' notion to Thor task sets (class Thor); by default all tasks - are in the 'standard' group. Running 'thor -T' will only show the standard - tasks - adding --all will show all tasks. You can also filter on a specific - group using the --group option: thor -T --group advanced - -== 0.9.6, released 2008-09-13 - -* Generic improvements - -== 0.9.5, released 2008-08-27 - -* Improve Windows compatibility -* Update (incorrect) README and task.thor sample file -* Options hash is now frozen (once returned) -* Allow magic predicates on options object. For instance: `options.force?` -* Add support for :numeric type -* BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f]) -* Allow specifying optional args with default values: method_options(:user => "mislav") -* Don't write options for nil or false values. This allows, for example, turning color off when running specs. -* Exit with the status of the spec command to help CI stuff out some. - -== 0.9.4, released 2008-08-13 - -* Try to add Windows compatibility. -* BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore -* Allow options at the beginning of the argument list as well as the end. -* Make options available with symbol keys in addition to string keys. -* Allow true to be passed to Thor#method_options to denote a boolean option. -* If loading a thor file fails, don't give up, just print a warning and keep going. -* Make sure that we re-raise errors if they happened further down the pipe than we care about. -* Only delete the old file on updating when the installation of the new one is a success -* Make it Ruby 1.8.5 compatible. -* Don't raise an error if a boolean switch is defined multiple times. -* Thor::Options now doesn't parse through things that look like options but aren't. -* Add URI detection to install task, and make sure we don't append ".thor" to URIs -* Add rake2thor to the gem binfiles. -* Make sure local Thorfiles override system-wide ones. diff --git a/railties/lib/vendor/thor-0.11.1/LICENSE b/railties/lib/vendor/thor-0.11.1/LICENSE deleted file mode 100644 index 98722da459..0000000000 --- a/railties/lib/vendor/thor-0.11.1/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2008 Yehuda Katz - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/railties/lib/vendor/thor-0.11.1/README.markdown b/railties/lib/vendor/thor-0.11.1/README.markdown deleted file mode 100644 index a1d7259775..0000000000 --- a/railties/lib/vendor/thor-0.11.1/README.markdown +++ /dev/null @@ -1,247 +0,0 @@ -thor -==== - -Map options to a class. Simply create a class with the appropriate annotations -and have options automatically map to functions and parameters. - -Example: - - class App < Thor # [1] - map "-L" => :list # [2] - - desc "install APP_NAME", "install one of the available apps" # [3] - method_options :force => :boolean, :alias => :string # [4] - def install(name) - user_alias = options[:alias] - if options.force? - # do something - end - # other code - end - - desc "list [SEARCH]", "list all of the available apps, limited by SEARCH" - def list(search="") - # list everything - end - end - -Thor automatically maps commands as such: - - thor app:install myname --force - -That gets converted to: - - App.new.install("myname") - # with {'force' => true} as options hash - -1. Inherit from Thor to turn a class into an option mapper -2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list -3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description -4. Provide any additional options that will be available the instance method options. - -Types for `method_options` --------------------------- - -
-
:boolean
-
is parsed as --option or --option=true
-
:string
-
is parsed as --option=VALUE
-
:numeric
-
is parsed as --option=N
-
:array
-
is parsed as --option=one two three
-
:hash
-
is parsed as --option=key:value key:value key:value
-
- -Besides, method_option allows a default value to be given, examples: - - method_options :force => false - #=> Creates a boolean option with default value false - - method_options :alias => "bar" - #=> Creates a string option with default value "bar" - - method_options :threshold => 3.0 - #=> Creates a numeric option with default value 3.0 - -You can also supply :option => :required to mark an option as required. The -type is assumed to be string. If you want a required hash with default values -as option, you can use `method_option` which uses a more declarative style: - - method_option :attributes, :type => :hash, :default => {}, :required => true - -All arguments can be set to nil (except required arguments), by suppling a no or -skip variant. For example: - - thor app name --no-attributes - -In previous versions, aliases for options were created automatically, but now -they should be explicit. You can supply aliases in both short and declarative -styles: - - method_options %w( force -f ) => :boolean - -Or: - - method_option :force, :type => :boolean, :aliases => "-f" - -You can supply as many aliases as you want. - -NOTE: Type :optional available in Thor 0.9.0 was deprecated. Use :string or :boolean instead. - -Namespaces ----------- - -By default, your Thor tasks are invoked using Ruby namespace. In the example -above, tasks are invoked as: - - thor app:install name --force - -However, you could namespace your class as: - - module Sinatra - class App < Thor - # tasks - end - end - -And then you should invoke your tasks as: - - thor sinatra:app:install name --force - -If desired, you can change the namespace: - - module Sinatra - class App < Thor - namespace :myapp - # tasks - end - end - -And then your tasks hould be invoked as: - - thor myapp:install name --force - -Invocations ------------ - -Thor comes with a invocation-dependency system as well which allows a task to be -invoked only once. For example: - - class Counter < Thor - desc "one", "Prints 1, 2, 3" - def one - puts 1 - invoke :two - invoke :three - end - - desc "two", "Prints 2, 3" - def two - puts 2 - invoke :three - end - - desc "three", "Prints 3" - def three - puts 3 - end - end - -When invoking the task one: - - thor counter:one - -The output is "1 2 3", which means that the three task was invoked only once. -You can even invoke tasks from another class, so be sure to check the -documentation. - -Thor::Group ------------ - -Thor has a special class called Thor::Group. The main difference to Thor class -is that it invokes all tasks at once. The example above could be rewritten in -Thor::Group as this: - - class Counter < Thor::Group - desc "Prints 1, 2, 3" - - def one - puts 1 - end - - def two - puts 2 - end - - def three - puts 3 - end - end - -When invoked: - - thor counter - -It prints "1 2 3" as well. Notice you should described (desc) only the class -and not each task anymore. Thor::Group is a great tool to create generators, -since you can define several steps which are invoked in the order they are -defined (Thor::Group is the tool use in generators in Rails 3.0). - -Besides, Thor::Group can parse arguments and options as Thor tasks: - - class Counter < Thor::Group - # number will be available as attr_accessor - argument :number, :type => :numeric, :desc => "The number to start counting" - desc "Prints the 'number' given upto 'number+2'" - - def one - puts number + 0 - end - - def two - puts number + 1 - end - - def three - puts number + 2 - end - end - -The counter above expects one parameter and has the folling outputs: - - thor counter 5 - # Prints "5 6 7" - - thor counter 11 - # Prints "11 12 13" - -You can also give options to Thor::Group, but instead of using `method_option` and -`method_options`, you should use `class_option` and `class_options`. Both argument -and class_options methods are available to Thor class as well. - -Actions -------- - -Thor comes with several actions which helps with script and generator tasks. You -might be familiar with them since some came from Rails Templates. They are: `say`, -`ask`, `yes?`, `no?`, `add_file`, `remove_file`, `copy_file`, `template`, -`directory`, `inside`, `run`, `inject_into_file` and a couple more. - -To use them, you just need to include Thor::Actions in your Thor classes: - - class App < Thor - include Thor::Actions - # tasks - end - -Some actions like copy file requires that a class method called source_root is -defined in your class. This is the directory where your templates should be -placed. Be sure to check the documentation. - -License -------- - -See MIT LICENSE. diff --git a/railties/lib/vendor/thor-0.11.1/bin/rake2thor b/railties/lib/vendor/thor-0.11.1/bin/rake2thor deleted file mode 100755 index 50c7410d80..0000000000 --- a/railties/lib/vendor/thor-0.11.1/bin/rake2thor +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'ruby2ruby' -require 'parse_tree' -if Ruby2Ruby::VERSION >= "1.2.0" - require 'parse_tree_extensions' -end -require 'rake' - -input = ARGV[0] || 'Rakefile' -output = ARGV[1] || 'Thorfile' - -$requires = [] - -module Kernel - def require_with_record(file) - $requires << file if caller[1] =~ /rake2thor:/ - require_without_record file - end - alias_method :require_without_record, :require - alias_method :require, :require_with_record -end - -load input - -@private_methods = [] - -def file_task_name(name) - "compile_" + name.gsub('/', '_slash_').gsub('.', '_dot_').gsub(/\W/, '_') -end - -def method_for_task(task) - file_task = task.is_a?(Rake::FileTask) - comment = task.instance_variable_get('@comment') - prereqs = task.instance_variable_get('@prerequisites').select(&Rake::Task.method(:task_defined?)) - actions = task.instance_variable_get('@actions') - name = task.name.gsub(/^([^:]+:)+/, '') - name = file_task_name(name) if file_task - meth = '' - - meth << "desc #{name.inspect}, #{comment.inspect}\n" if comment - meth << "def #{name}\n" - - meth << prereqs.map do |pre| - pre = pre.to_s - pre = file_task_name(pre) if Rake::Task[pre].is_a?(Rake::FileTask) - ' ' + pre - end.join("\n") - - meth << "\n\n" unless prereqs.empty? || actions.empty? - - meth << actions.map do |act| - act = act.to_ruby - unless act.gsub!(/^proc \{ \|(\w+)\|\n/, - " \\1 = Struct.new(:name).new(#{name.inspect}) # A crude mock Rake::Task object\n") - act.gsub!(/^proc \{\n/, '') - end - act.gsub(/\n\}$/, '') - end.join("\n") - - meth << "\nend" - - if file_task - @private_methods << meth - return - end - - meth -end - -body = Rake::Task.tasks.map(&method(:method_for_task)).compact.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n") - -unless @private_methods.empty? - body << "\n\n private\n\n" - body << @private_methods.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n") -end - -requires = $requires.map { |r| "require #{r.inspect}" }.join("\n") - -File.open(output, 'w') { |f| f.write(<:: name of the defaut task - # - def default_task(meth=nil) - case meth - when :none - @default_task = 'help' - when nil - @default_task ||= from_superclass(:default_task, 'help') - else - @default_task = meth.to_s - end - end - - # Defines the usage and the description of the next task. - # - # ==== Parameters - # usage - # description - # - def desc(usage, description, options={}) - if options[:for] - task = find_and_refresh_task(options[:for]) - task.usage = usage if usage - task.description = description if description - else - @usage, @desc = usage, description - end - end - - # Maps an input to a task. If you define: - # - # map "-T" => "list" - # - # Running: - # - # thor -T - # - # Will invoke the list task. - # - # ==== Parameters - # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given task. - # - def map(mappings=nil) - @map ||= from_superclass(:map, {}) - - if mappings - mappings.each do |key, value| - if key.respond_to?(:each) - key.each {|subkey| @map[subkey] = value} - else - @map[key] = value - end - end - end - - @map - end - - # Declares the options for the next task to be declared. - # - # ==== Parameters - # Hash[Symbol => Object]:: The hash key is the name of the option and the value - # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric - # or :required (string). If you give a value, the type of the value is used. - # - def method_options(options=nil) - @method_options ||= {} - build_options(options, @method_options) if options - @method_options - end - - # Adds an option to the set of class options. If :for is given as option, - # it allows you to change the options from a previous defined task. - # - # def previous_task - # # magic - # end - # - # method_options :foo => :bar, :for => :previous_task - # - # def next_task - # # magic - # end - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :default - Default value for this argument. It cannot be required and have default values. - # :aliases - Aliases for this option. - # :type - The type of the argument, can be :string, :hash, :array, :numeric, :boolean or :default. - # Default accepts arguments as booleans (--switch) or as strings (--switch=VALUE). - # :group - The group for this options. Use by class options to output options in different levels. - # :banner - String to show on usage notes. - # - def method_option(name, options={}) - scope = if options[:for] - find_and_refresh_task(options[:for]).options - else - method_options - end - - build_option(name, options, scope) - end - - # Parses the task and options from the given args, instantiate the class - # and invoke the task. This method is used when the arguments must be parsed - # from an array. If you are inside Ruby and want to use a Thor class, you - # can simply initialize it: - # - # script = MyScript.new(args, options, config) - # script.invoke(:task, first_arg, second_arg, third_arg) - # - def start(given_args=ARGV, config={}) - super do - meth = normalize_task_name(given_args.shift) - task = all_tasks[meth] - - if task - args, opts = Thor::Options.split(given_args) - config.merge!(:task_options => task.options) - else - args, opts = given_args, {} - end - - task ||= Task.dynamic(meth) - trailing = args[Range.new(arguments.size, -1)] - new(args, opts, config).invoke(task, trailing || []) - end - end - - # Prints help information. If a task name is given, it shows information - # only about the specific task. - # - # ==== Parameters - # meth:: An optional task name to print usage information about. - # - # ==== Options - # namespace:: When true, shows the namespace in the output before the usage. - # skip_inherited:: When true, does not show tasks from superclass. - # - def help(shell, meth=nil, options={}) - meth, options = nil, meth if meth.is_a?(Hash) - - if meth - task = all_tasks[meth] - raise UndefinedTaskError, "task '#{meth}' could not be found in namespace '#{self.namespace}'" unless task - - shell.say "Usage:" - shell.say " #{banner(task, options[:namespace])}" - shell.say - class_options_help(shell, "Class") - shell.say task.description - else - list = (options[:short] ? tasks : all_tasks).map do |_, task| - [ banner(task, options[:namespace]), task.short_description || '' ] - end - - if options[:short] - shell.print_table(list, :emphasize_last => true) - else - shell.say "Tasks:" - shell.print_table(list, :ident => 2, :emphasize_last => true) - shell.say - - class_options_help(shell, "Class") - end - end - end - - protected - - # The banner for this class. You can customize it if you are invoking the - # thor class by another means which is not the Thor::Runner. It receives - # the task that is going to be invoked and if the namespace should be - # displayed. - # - def banner(task, namespace=true) #:nodoc: - task.formatted_usage(self, namespace) - end - - def baseclass #:nodoc: - Thor - end - - def valid_task?(meth) #:nodoc: - @usage && @desc - end - - def create_task(meth) #:nodoc: - tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options) - @usage, @desc, @method_options = nil - end - - def initialize_added #:nodoc: - class_options.merge!(method_options) - @method_options = nil - end - - # Receives a task name (can be nil), and try to get a map from it. - # If a map can't be found use the sent name or the default task. - # - def normalize_task_name(meth) #:nodoc: - mapping = map[meth.to_s] - meth = mapping || meth || default_task - meth.to_s.gsub('-','_') # treat foo-bar > foo_bar - end - end - - include Thor::Base - - map HELP_MAPPINGS => :help - - desc "help [TASK]", "Describe available tasks or one specific task" - def help(task=nil) - self.class.help(shell, task, :namespace => task && task.include?(?:)) - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/actions.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/actions.rb deleted file mode 100644 index ff0592ea1b..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/actions.rb +++ /dev/null @@ -1,242 +0,0 @@ -require 'fileutils' - -Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action| - require action -end - -class Thor - module Actions - attr_accessor :behavior - - # On inclusion, add some options to base. - # - def self.included(base) #:nodoc: - base.extend ClassMethods - 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 - - module ClassMethods - # Hold source paths for one Thor instance. source_paths_for_search is the - # method responsible to gather source_paths from this current class, - # inherited paths and the source root. - # - def source_paths - @source_paths ||= [] - end - - # Returns the source paths in the following order: - # - # 1) This class source paths - # 2) Source root - # 3) Parents source paths - # - def source_paths_for_search - @source_paths_for_search ||= begin - paths = [] - paths += self.source_paths - paths << self.source_root if self.respond_to?(:source_root) - paths += from_superclass(:source_paths, []) - paths - end - end - end - - # Extends initializer to add more configuration options. - # - # ==== Configuration - # behavior:: The actions default behavior. Can be :invoke or :revoke. - # It also accepts :force, :skip and :pretend to set the behavior - # and the respective option. - # - # destination_root:: The root directory needed for some actions. It's also known - # as destination root. - # - 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 - - # Wraps an action object and call it accordingly to the thor class behavior. - # - def action(instance) - if behavior == :revoke - instance.revoke! - else - instance.invoke! - end - end - - # Returns the root for this thor class (also aliased as destination root). - # - 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. - # - def destination_root=(root) - @destination_stack ||= [] - @destination_stack[0] = File.expand_path(root || '') - end - - # Returns the given path relative to the absolute root (ie, root where - # the script started). - # - def relative_to_original_destination_root(path, remove_dot=true) - path = path.gsub(@destination_stack[0], '.') - remove_dot ? (path[2..-1] || '') : path - end - - # Receives a file or directory and search for it in the source paths. - # - def find_in_source_paths(file) - relative_root = relative_to_original_destination_root(destination_root, false) - paths = self.class.source_paths_for_search - - 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 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 - - # 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. - # - def inside(dir='', &block) - @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 - end - - # Same as inside, but log status and use padding. - # - def inside_with_padding(dir='', config={}, &block) - say_status :inside, dir, config.fetch(:verbose, true) - shell.padding += 1 - inside(dir, &block) - shell.padding -= 1 - end - - # Goes to the root and execute the given block. - # - def in_root - inside(@destination_stack.first) { yield } - end - - # Executes a command. - # - # ==== Parameters - # command:: the command to be executed. - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # inside('vendor') do - # run('ln -s ~/edge rails') - # end - # - def run(command, config={}) - return unless behavior == :invoke - description = "#{command.inspect} from #{relative_to_original_destination_root(destination_root, false)}" - say_status :run, description, config.fetch(:verbose, true) - `#{command}` unless options[:pretend] - end - - # 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. - # - def run_ruby_script(command, config={}) - return unless behavior == :invoke - say_status File.basename(Thor::Util.ruby_command), command, config.fetch(:verbose, true) - `#{Thor::Util.ruby_command} #{command}` unless options[:pretend] - end - - # 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 - # options:: 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 - # - 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 - - say_status :thor, command, verbose - run "thor #{command}", :verbose => false - end - - protected - - # Allow current root to be shared between invocations. - # - def _shared_configuration #:nodoc: - super.merge!(:destination_root => self.destination_root) - end - - def _cleanup_options_and_set(options, key) #:nodoc: - case options - when Array - %w(--force -f --skip -s).each { |i| options.delete(i) } - options << "--#{key}" - when Hash - [:force, :skip, "force", "skip"].each { |i| options.delete(i) } - options.merge!(key => true) - end - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/create_file.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/actions/create_file.rb deleted file mode 100644 index 8f6badee27..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/create_file.rb +++ /dev/null @@ -1,102 +0,0 @@ -require 'thor/actions/empty_directory' - -class Thor - module Actions - - # 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" - # - def create_file(destination, data=nil, config={}, &block) - action CreateFile.new(self, destination, block || data.to_s, config) - end - alias :add_file :create_file - - # AddFile is a subset of Template, which instead of rendering a file with - # ERB, it gets the content from the user. - # - class CreateFile < EmptyDirectory #:nodoc: - attr_reader :data - - def initialize(base, destination, data, config={}) - @data = data - super(base, destination, config) - end - - # Checks if the content of the file at the destination is identical to the rendered result. - # - # ==== Returns - # Boolean:: true if it is identical, false otherwise. - # - def identical? - exists? && File.read(destination) == render - end - - # Holds the content to be added to the file. - # - def render - @render ||= if data.is_a?(Proc) - data.call - else - data - end - end - - def invoke! - invoke_with_conflict_check do - FileUtils.mkdir_p(File.dirname(destination)) - File.open(destination, 'w'){ |f| f.write render } - end - end - - protected - - # Now on conflict we check if the file is identical or not. - # - def on_conflict_behavior(&block) - if identical? - say_status :identical, :blue - else - options = base.options.merge(config) - force_or_skip_or_conflict(options[:force], options[:skip], &block) - end - end - - # If force is true, run the action, otherwise check if it's not being - # skipped. If both are false, show the file_collision menu, if the menu - # returns true, force it, otherwise skip. - # - def force_or_skip_or_conflict(force, skip, &block) - if force - say_status :force, :yellow - block.call unless pretend? - elsif skip - say_status :skip, :yellow - else - say_status :conflict, :red - force_or_skip_or_conflict(force_on_collision?, true, &block) - end - end - - # Shows the file collision menu to the user and gets the result. - # - def force_on_collision? - base.shell.file_collision(destination){ render } - end - - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/directory.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/actions/directory.rb deleted file mode 100644 index e33639f4e5..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/directory.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'thor/actions/empty_directory' - -class Thor - module Actions - - # 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:: 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 - # - def directory(source, destination=nil, config={}) - action Directory.new(self, source, destination || source, config) - end - - class Directory < EmptyDirectory #:nodoc: - attr_reader :source - - def initialize(base, source, destination=nil, config={}) - @source = File.expand_path(base.find_in_source_paths(source.to_s)) - super(base, destination, { :recursive => true }.merge(config)) - end - - def invoke! - base.empty_directory given_destination, config - execute! - end - - def revoke! - execute! - end - - protected - - def execute! - lookup = config[:recursive] ? File.join(source, '**') : source - lookup = File.join(lookup, '{*,.[a-z]*}') - - Dir[lookup].each do |file_source| - next if File.directory?(file_source) - file_destination = File.join(given_destination, file_source.gsub(source, '.')) - - case file_source - when /\.empty_directory$/ - base.empty_directory(File.dirname(file_destination), config) - when /\.tt$/ - base.template(file_source, file_destination[0..-4], config) - else - base.copy_file(file_source, file_destination, config) - end - end - end - - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/empty_directory.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/actions/empty_directory.rb deleted file mode 100644 index 03c1fe4af1..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/empty_directory.rb +++ /dev/null @@ -1,133 +0,0 @@ -class Thor - module Actions - - # 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" - # - def empty_directory(destination, config={}) - action EmptyDirectory.new(self, destination, config) - end - - # Class which holds create directory logic. This is the base class for - # other actions like create_file and directory. - # - # This implementation is based in Templater actions, created by Jonas Nicklas - # and Michael S. Klishin under MIT LICENSE. - # - class EmptyDirectory #:nodoc: - attr_reader :base, :destination, :given_destination, :relative_destination, :config - - # Initializes given the source and destination. - # - # ==== Parameters - # base:: A Thor::Base instance - # source:: Relative path to the source of this file - # destination:: Relative path to the destination of this file - # config:: give :verbose => false to not log the status. - # - def initialize(base, destination, config={}) - @base, @config = base, { :verbose => true }.merge(config) - self.destination = destination - end - - # Checks if the destination file already exists. - # - # ==== Returns - # Boolean:: true if the file exists, false otherwise. - # - def exists? - ::File.exists?(destination) - end - - def invoke! - invoke_with_conflict_check do - ::FileUtils.mkdir_p(destination) - end - end - - def revoke! - say_status :remove, :red - ::FileUtils.rm_rf(destination) if !pretend? && exists? - end - - protected - - # Shortcut for pretend. - # - def pretend? - base.options[:pretend] - end - - # Sets the absolute destination value from a relative destination value. - # It also stores the given and relative destination. Let's suppose our - # script is being executed on "dest", it sets the destination root to - # "dest". The destination, given_destination and relative_destination - # are related in the following way: - # - # inside "bar" do - # empty_directory "baz" - # end - # - # destination #=> dest/bar/baz - # relative_destination #=> bar/baz - # given_destination #=> baz - # - def destination=(destination) - if destination - @given_destination = convert_encoded_instructions(destination.to_s) - @destination = ::File.expand_path(@given_destination, base.destination_root) - @relative_destination = base.relative_to_original_destination_root(@destination) - end - end - - # Filenames in the encoded form are converted. If you have a file: - # - # %class_name%.rb - # - # It gets the class name from the base and replace it: - # - # user.rb - # - def convert_encoded_instructions(filename) - filename.gsub(/%(.*?)%/) do |string| - instruction = $1.strip - base.respond_to?(instruction) ? base.send(instruction) : string - end - end - - # Receives a hash of options and just execute the block if some - # conditions are met. - # - def invoke_with_conflict_check(&block) - if exists? - on_conflict_behavior(&block) - else - say_status :create, :green - block.call unless pretend? - end - - destination - end - - # What to do when the destination file already exists. - # - def on_conflict_behavior(&block) - say_status :exist, :blue - end - - # Shortcut to say_status shell method. - # - def say_status(status, color) - base.shell.say_status status, relative_destination, color if config[:verbose] - end - - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/file_manipulation.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/actions/file_manipulation.rb deleted file mode 100644 index 5a39840404..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/file_manipulation.rb +++ /dev/null @@ -1,194 +0,0 @@ -require 'erb' -require 'open-uri' - -class Thor - module Actions - - # 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" - # - def copy_file(source, destination=nil, config={}) - destination ||= source - source = File.expand_path(find_in_source_paths(source.to_s)) - - create_file destination, nil, config do - File.read(source) - end - 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. - # - # ==== 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 - # - 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 - - # 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" - # - def template(source, destination=nil, config={}) - destination ||= source - source = File.expand_path(find_in_source_paths(source.to_s)) - context = instance_eval('binding') - - create_file destination, nil, config do - ERB.new(::File.read(source), nil, '-').result(context) - end - end - - # 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 - # - 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 - - # Prepend text to a file. - # - # ==== 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"' - # - def prepend_file(path, data=nil, config={}, &block) - return unless behavior == :invoke - path = File.expand_path(path, destination_root) - say_status :prepend, relative_to_original_destination_root(path), config.fetch(:verbose, true) - - unless options[:pretend] - content = data || block.call - content << File.read(path) - File.open(path, 'wb') { |file| file.write(content) } - end - end - - # Append text to a file. - # - # ==== 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"' - # - def append_file(path, data=nil, config={}, &block) - return unless behavior == :invoke - path = File.expand_path(path, destination_root) - say_status :append, relative_to_original_destination_root(path), config.fetch(:verbose, true) - File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend] - end - - # 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 - # - 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 - - # 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' - # - 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 - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/inject_into_file.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/actions/inject_into_file.rb deleted file mode 100644 index 089bd894e4..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/actions/inject_into_file.rb +++ /dev/null @@ -1,78 +0,0 @@ -require 'thor/actions/empty_directory' - -class Thor - module Actions - - # 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:: 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 - # - def inject_into_file(destination, *args, &block) - if block_given? - data, config = block, args.shift - else - data, config = args.shift, args.shift - end - - log_status = args.empty? || args.pop - action InjectIntoFile.new(self, destination, data, config) - end - - class InjectIntoFile < EmptyDirectory - attr_reader :flag, :replacement - - def initialize(base, destination, data, config) - super(base, destination, { :verbose => true }.merge(config)) - - data = data.call if data.is_a?(Proc) - - @replacement = if @config.key?(:after) - @flag = @config.delete(:after) - @flag + data - else - @flag = @config.delete(:before) - data + @flag - end - end - - def invoke! - say_status :inject, config[:verbose] - replace!(flag, replacement) - end - - def revoke! - say_status :deinject, config[:verbose] - replace!(replacement, flag) - end - - protected - - # Adds the content to the file. - # - def replace!(regexp, string) - unless base.options[:pretend] - content = File.read(destination) - content.gsub!(regexp, string) - File.open(destination, 'wb') { |file| file.write(content) } - end - end - - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/base.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/base.rb deleted file mode 100644 index caf298dda8..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/base.rb +++ /dev/null @@ -1,515 +0,0 @@ -require 'thor/core_ext/hash_with_indifferent_access' -require 'thor/core_ext/ordered_hash' -require 'thor/error' -require 'thor/shell' -require 'thor/invocation' -require 'thor/parser' -require 'thor/task' -require 'thor/util' - -class Thor - HELP_MAPPINGS = %w(-h -? --help -D) - THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root) - - module Base - attr_accessor :options - - # It receives arguments in an Array and two hashes, one for options and - # other for configuration. - # - # Notice that it does not check if all required arguments were supplied. - # It should be done by the parser. - # - # ==== Parameters - # args:: An array of objects. The objects are applied to their - # respective accessors declared with argument. - # - # options:: An options hash that will be available as self.options. - # The hash given is converted to a hash with indifferent - # access, magic predicates (options.skip?) and then frozen. - # - # config:: Configuration for this Thor class. - # - def initialize(args=[], options={}, config={}) - Thor::Arguments.parse(self.class.arguments, args).each do |key, value| - send("#{key}=", value) - end - - parse_options = self.class.class_options - - if options.is_a?(Array) - task_options = config.delete(:task_options) # hook for start - parse_options = parse_options.merge(task_options) if task_options - array_options, hash_options = options, {} - else - array_options, hash_options = [], options - end - - options = Thor::Options.parse(parse_options, array_options) - self.options = Thor::CoreExt::HashWithIndifferentAccess.new(options).merge!(hash_options) - self.options.freeze - end - - class << self - def included(base) #:nodoc: - base.send :extend, ClassMethods - base.send :include, Invocation - base.send :include, Shell - end - - # Returns the classes that inherits from Thor or Thor::Group. - # - # ==== Returns - # Array[Class] - # - def subclasses - @subclasses ||= [] - end - - # Returns the files where the subclasses are kept. - # - # ==== Returns - # Hash[path => Class] - # - def subclass_files - @subclass_files ||= Hash.new{ |h,k| h[k] = [] } - end - - # Whenever a class inherits from Thor or Thor::Group, we should track the - # class and the file on Thor::Base. This is the method responsable for it. - # Also adds the source root to the source paths if the klass respond to it. - # - def register_klass_file(klass) #:nodoc: - file = caller[1].match(/(.*):\d+/)[1] - Thor::Base.subclasses << klass unless Thor::Base.subclasses.include?(klass) - - file_subclasses = Thor::Base.subclass_files[File.expand_path(file)] - file_subclasses << klass unless file_subclasses.include?(klass) - end - end - - module ClassMethods - # Adds an argument to the class and creates an attr_accessor for it. - # - # Arguments are different from options in several aspects. The first one - # is how they are parsed from the command line, arguments are retrieved - # from position: - # - # thor task NAME - # - # Instead of: - # - # thor task --name=NAME - # - # Besides, arguments are used inside your code as an accessor (self.argument), - # while options are all kept in a hash (self.options). - # - # Finally, arguments cannot have type :default or :boolean but can be - # optional (supplying :optional => :true or :required => false), although - # you cannot have a required argument after a non-required argument. If you - # try it, an error is raised. - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :optional - If the argument is optional or not. - # :type - The type of the argument, can be :string, :hash, :array, :numeric. - # :default - Default value for this argument. It cannot be required and have default values. - # :banner - String to show on usage notes. - # - # ==== Errors - # ArgumentError:: Raised if you supply a required argument after a non required one. - # - def argument(name, options={}) - is_thor_reserved_word?(name, :argument) - no_tasks { attr_accessor name } - - required = if options.key?(:optional) - !options[:optional] - elsif options.key?(:required) - options[:required] - else - options[:default].nil? - end - - remove_argument name - - arguments.each do |argument| - next if argument.required? - raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " << - "the non-required argument #{argument.human_name.inspect}." - end if required - - arguments << Thor::Argument.new(name, options[:desc], required, options[:type], - options[:default], options[:banner]) - end - - # Returns this class arguments, looking up in the ancestors chain. - # - # ==== Returns - # Array[Thor::Argument] - # - def arguments - @arguments ||= from_superclass(:arguments, []) - end - - # Adds a bunch of options to the set of class options. - # - # class_options :foo => false, :bar => :required, :baz => :string - # - # If you prefer more detailed declaration, check class_option. - # - # ==== Parameters - # Hash[Symbol => Object] - # - def class_options(options=nil) - @class_options ||= from_superclass(:class_options, {}) - build_options(options, @class_options) if options - @class_options - end - - # Adds an option to the set of class options - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :default - Default value for this argument. - # :group - The group for this options. Use by class options to output options in different levels. - # :aliases - Aliases for this option. - # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. - # :banner - String to show on usage notes. - # - def class_option(name, options={}) - build_option(name, options, class_options) - end - - # Removes a previous defined argument. If :undefine is given, undefine - # accessors as well. - # - # ==== Paremeters - # names:: Arguments to be removed - # - # ==== Examples - # - # remove_argument :foo - # remove_argument :foo, :bar, :baz, :undefine => true - # - def remove_argument(*names) - options = names.last.is_a?(Hash) ? names.pop : {} - - names.each do |name| - arguments.delete_if { |a| a.name == name.to_s } - undef_method name, "#{name}=" if options[:undefine] - end - end - - # Removes a previous defined class option. - # - # ==== Paremeters - # names:: Class options to be removed - # - # ==== Examples - # - # remove_class_option :foo - # remove_class_option :foo, :bar, :baz - # - def remove_class_option(*names) - names.each do |name| - class_options.delete(name) - end - end - - # Defines the group. This is used when thor list is invoked so you can specify - # that only tasks from a pre-defined group will be shown. Defaults to standard. - # - # ==== Parameters - # name - # - def group(name=nil) - case name - when nil - @group ||= from_superclass(:group, 'standard') - else - @group = name.to_s - end - end - - # Returns the tasks for this Thor class. - # - # ==== Returns - # OrderedHash:: An ordered hash with this class tasks. - # - def tasks - @tasks ||= Thor::CoreExt::OrderedHash.new - end - - # Returns the tasks for this Thor class and all subclasses. - # - # ==== Returns - # OrderedHash - # - def all_tasks - @all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new) - @all_tasks.merge(tasks) - end - - # Removes a given task from this Thor class. This is usually done if you - # are inheriting from another class and don't want it to be available - # anymore. - # - # By default it only remove the mapping to the task. But you can supply - # :undefine => true to undefine the method from the class as well. - # - # ==== Parameters - # name:: The name of the task to be removed - # options:: You can give :undefine => true if you want tasks the method - # to be undefined from the class as well. - # - def remove_task(*names) - options = names.last.is_a?(Hash) ? names.pop : {} - - names.each do |name| - tasks.delete(name.to_s) - all_tasks.delete(name.to_s) - undef_method name if options[:undefine] - end - end - - # All methods defined inside the given block are not added as tasks. - # - # So you can do: - # - # class MyScript < Thor - # no_tasks do - # def this_is_not_a_task - # end - # end - # end - # - # You can also add the method and remove it from the task list: - # - # class MyScript < Thor - # def this_is_not_a_task - # end - # remove_task :this_is_not_a_task - # end - # - def no_tasks - @no_tasks = true - yield - @no_tasks = false - end - - # Sets the namespace for the Thor or Thor::Group class. By default the - # namespace is retrieved from the class name. If your Thor class is named - # Scripts::MyScript, the help method, for example, will be called as: - # - # thor scripts:my_script -h - # - # If you change the namespace: - # - # namespace :my_scripts - # - # You change how your tasks are invoked: - # - # thor my_scripts -h - # - # Finally, if you change your namespace to default: - # - # namespace :default - # - # Your tasks can be invoked with a shortcut. Instead of: - # - # thor :my_task - # - def namespace(name=nil) - case name - when nil - @namespace ||= Thor::Util.constant_to_namespace(self, false) - else - @namespace = name.to_s - end - end - - # Default way to start generators from the command line. - # - def start(given_args=ARGV, config={}) #:nodoc: - config[:shell] ||= Thor::Base.shell.new - yield - rescue Thor::Error => e - if given_args.include?("--debug") - raise e - else - config[:shell].error e.message - end - end - - protected - - # Prints the class options per group. If an option does not belong to - # any group, it uses the ungrouped name value. This method provide to - # hooks to add extra options, one of them if the third argument called - # extra_group that should be a hash in the format :group => Array[Options]. - # - # The second is by returning a lamda used to print values. The lambda - # requires two options: the group name and the array of options. - # - def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc: - groups = {} - - class_options.each do |_, value| - groups[value.group] ||= [] - groups[value.group] << value - end - - printer = proc do |group_name, options| - list = [] - padding = options.collect{ |o| o.aliases.size }.max.to_i * 4 - - options.each do |option| - list << [ option.usage(padding), option.description || "" ] - list << [ "", "Default: #{option.default}" ] if option.show_default? - end - - unless list.empty? - if group_name - shell.say "#{group_name} options:" - else - shell.say "Options:" - end - - shell.print_table(list, :emphasize_last => true, :ident => 2) - shell.say "" - end - end - - # Deal with default group - global_options = groups.delete(nil) || [] - printer.call(ungrouped_name, global_options) if global_options - - # Print all others - groups = extra_group.merge(groups) if extra_group - groups.each(&printer) - printer - end - - # Raises an error if the word given is a Thor reserved word. - # - def is_thor_reserved_word?(word, type) - return false unless THOR_RESERVED_WORDS.include?(word.to_s) - raise "'#{word}' is a Thor reserved word and cannot be defined as #{type}" - end - - # Build an option and adds it to the given scope. - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described in both class_option and method_option. - # - def build_option(name, options, scope) - scope[name] = Thor::Option.new(name, options[:desc], options[:required], - options[:type], options[:default], options[:banner], - options[:group], options[:aliases]) - end - - # Receives a hash of options, parse them and add to the scope. This is a - # fast way to set a bunch of options: - # - # build_options :foo => true, :bar => :required, :baz => :string - # - # ==== Parameters - # Hash[Symbol => Object] - # - def build_options(options, scope) - options.each do |key, value| - scope[key] = Thor::Option.parse(key, value) - end - end - - # Finds a task with the given name. If the task belongs to the current - # class, just return it, otherwise dup it and add the fresh copy to the - # current task hash. - # - def find_and_refresh_task(name) - task = if task = tasks[name.to_s] - task - elsif task = all_tasks[name.to_s] - tasks[name.to_s] = task.clone - else - raise ArgumentError, "You supplied :for => #{name.inspect}, but the task #{name.inspect} could not be found." - end - end - - # Everytime someone inherits from a Thor class, register the klass - # and file into baseclass. - # - def inherited(klass) - Thor::Base.register_klass_file(klass) - end - - # Fire this callback whenever a method is added. Added methods are - # tracked as tasks if the requirements set by valid_task? are valid. - # - def method_added(meth) - meth = meth.to_s - - if meth == "initialize" - initialize_added - return - end - - # Return if it's not a public instance method - return unless public_instance_methods.include?(meth) || - public_instance_methods.include?(meth.to_sym) - - # Return if @no_tasks is enabled or it's not a valid task - return if @no_tasks || !valid_task?(meth) - - is_thor_reserved_word?(meth, :task) - Thor::Base.register_klass_file(self) - create_task(meth) - end - - # Retrieves a value from superclass. If it reaches the baseclass, - # returns nil. - # - def from_superclass(method, default=nil) - if self == baseclass || !superclass.respond_to?(method, true) - default - else - value = superclass.send(method) - value.dup if value - end - end - - # SIGNATURE: Sets the baseclass. This is where the superclass lookup - # finishes. - def baseclass #:nodoc: - end - - # SIGNATURE: Defines if a given method is a valid_task?. This method is - # called before a new method is added to the class. - def valid_task?(meth) #:nodoc: - true # unless otherwise given - end - - # SIGNATURE: Creates a new task if valid_task? is true. This method is - # called when a new method is added to the class. - def create_task(meth) #:nodoc: - end - - # SIGNATURE: Defines behavior when the initialize method is added to the - # class. - def initialize_added #:nodoc: - end - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/hash_with_indifferent_access.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/hash_with_indifferent_access.rb deleted file mode 100644 index 3213961fe4..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/hash_with_indifferent_access.rb +++ /dev/null @@ -1,75 +0,0 @@ -class Thor - module CoreExt - - # A hash with indifferent access and magic predicates. - # - # hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true - # - # hash[:foo] #=> 'bar' - # hash['foo'] #=> 'bar' - # hash.foo? #=> true - # - class HashWithIndifferentAccess < ::Hash - - def initialize(hash={}) - super() - hash.each do |key, value| - self[convert_key(key)] = value - end - end - - def [](key) - super(convert_key(key)) - end - - def []=(key, value) - super(convert_key(key), value) - end - - def delete(key) - super(convert_key(key)) - end - - def values_at(*indices) - indices.collect { |key| self[convert_key(key)] } - end - - def merge(other) - dup.merge!(other) - end - - def merge!(other) - other.each do |key, value| - self[convert_key(key)] = value - end - self - end - - protected - - def convert_key(key) - key.is_a?(Symbol) ? key.to_s : key - end - - # Magic predicates. For instance: - # - # options.force? # => !!options['force'] - # options.shebang # => "/usr/lib/local/ruby" - # options.test_framework?(:rspec) # => options[:test_framework] == :rspec - # - def method_missing(method, *args, &block) - method = method.to_s - if method =~ /^(\w+)\?$/ - if args.empty? - !!self[$1] - else - self[$1] == args.first - end - else - self[method] - end - end - - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/ordered_hash.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/ordered_hash.rb deleted file mode 100644 index 5e4ad5609f..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/core_ext/ordered_hash.rb +++ /dev/null @@ -1,102 +0,0 @@ -require 'forwardable' - -class Thor #:nodoc: - module CoreExt #:nodoc: - - if RUBY_VERSION >= '1.9' - class OrderedHash < ::Hash - end - else - # This class is based on the Ruby 1.9 ordered hashes. - # - # It keeps the semantics and most of the efficiency of normal hashes - # while also keeping track of the order in which elements were set. - # - class OrderedHash #:nodoc: - include Enumerable - - Node = Struct.new(:key, :value, :next, :prev) - - def initialize - @hash = {} - end - - def [](key) - @hash[key] && @hash[key].value - end - - def []=(key, value) - if node = @hash[key] - node.value = value - else - node = Node.new(key, value) - - if @first.nil? - @first = @last = node - else - node.prev = @last - @last.next = node - @last = node - end - end - - @hash[key] = node - value - end - - def delete(key) - if node = @hash[key] - prev_node = node.prev - next_node = node.next - - next_node.prev = prev_node if next_node - prev_node.next = next_node if prev_node - - @first = next_node if @first == node - @last = prev_node if @last == node - - value = node.value - end - - @hash.delete(key) - value - end - - def keys - self.map { |k, v| k } - end - - def values - self.map { |k, v| v } - end - - def each - return unless @first - yield [@first.key, @first.value] - node = @first - yield [node.key, node.value] while node = node.next - self - end - - def merge(other) - hash = self.class.new - - self.each do |key, value| - hash[key] = value - end - - other.each do |key, value| - hash[key] = value - end - - hash - end - - def empty? - @hash.empty? - end - end - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/error.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/error.rb deleted file mode 100644 index c846e9ce74..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/error.rb +++ /dev/null @@ -1,27 +0,0 @@ -class Thor - # Thor::Error is raised when it's caused by the user invoking the task and - # only errors that inherit from it are rescued. - # - # So, for example, if the developer declares a required argument after an - # option, it should raise an ::ArgumentError and not ::Thor::ArgumentError, - # because it was caused by the developer and not the "final user". - # - class Error < StandardError #:nodoc: - end - - # Raised when a task was not found. - # - class UndefinedTaskError < Error #:nodoc: - end - - # Raised when a task was found, but not invoked properly. - # - class InvocationError < Error #:nodoc: - end - - class RequiredArgumentMissingError < InvocationError #:nodoc: - end - - class MalformattedArgumentError < InvocationError #:nodoc: - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/group.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/group.rb deleted file mode 100644 index 63267934c7..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/group.rb +++ /dev/null @@ -1,240 +0,0 @@ -# Thor has a special class called Thor::Group. The main difference to Thor class -# is that it invokes all tasks at once. It also include some methods that allows -# invocations to be done at the class method, which are not available to Thor -# tasks. -# -class Thor::Group - class << self - # The descrition for this Thor::Group. If none is provided, but a source root - # exists, tries to find the USAGE one folder above it, otherwise searches - # in the superclass. - # - # ==== Parameters - # description:: The description for this Thor::Group. - # - def desc(description=nil) - case description - when nil - @desc ||= from_superclass(:desc, nil) - else - @desc = description - end - end - - # Start works differently in Thor::Group, it simply invokes all tasks - # inside the class. - # - def start(given_args=ARGV, config={}) - super do - if Thor::HELP_MAPPINGS.include?(given_args.first) - help(config[:shell]) - return - end - - args, opts = Thor::Options.split(given_args) - new(args, opts, config).invoke - end - end - - # Prints help information. - # - # ==== Options - # short:: When true, shows only usage. - # - def help(shell, options={}) - if options[:short] - shell.say banner - else - shell.say "Usage:" - shell.say " #{banner}" - shell.say - class_options_help(shell) - shell.say self.desc if self.desc - end - end - - # Stores invocations for this class merging with superclass values. - # - def invocations #:nodoc: - @invocations ||= from_superclass(:invocations, {}) - end - - # Stores invocation blocks used on invoke_from_option. - # - def invocation_blocks #:nodoc: - @invocation_blocks ||= from_superclass(:invocation_blocks, {}) - end - - # Invoke the given namespace or class given. It adds an instance - # method that will invoke the klass and task. You can give a block to - # configure how it will be invoked. - # - # The namespace/class given will have its options showed on the help - # usage. Check invoke_from_option for more information. - # - def invoke(*names, &block) - options = names.last.is_a?(Hash) ? names.pop : {} - verbose = options.fetch(:verbose, :white) - - names.each do |name| - invocations[name] = false - invocation_blocks[name] = block if block_given? - - class_eval <<-METHOD, __FILE__, __LINE__ - def _invoke_#{name.to_s.gsub(/\W/, '_')} - klass, task = self.class.prepare_for_invocation(nil, #{name.inspect}) - - if klass - say_status :invoke, #{name.inspect}, #{verbose.inspect} - block = self.class.invocation_blocks[#{name.inspect}] - invoke_with_padding klass, task, &block - else - say_status :error, %(#{name.inspect} [not found]), :red - end - end - METHOD - end - end - - # Invoke a thor class based on the value supplied by the user to the - # given option named "name". A class option must be created before this - # method is invoked for each name given. - # - # ==== Examples - # - # class GemGenerator < Thor::Group - # class_option :test_framework, :type => :string - # invoke_from_option :test_framework - # end - # - # ==== Boolean options - # - # In some cases, you want to invoke a thor class if some option is true or - # false. This is automatically handled by invoke_from_option. Then the - # option name is used to invoke the generator. - # - # ==== Preparing for invocation - # - # In some cases you want to customize how a specified hook is going to be - # invoked. You can do that by overwriting the class method - # prepare_for_invocation. The class method must necessarily return a klass - # and an optional task. - # - # ==== Custom invocations - # - # You can also supply a block to customize how the option is giong to be - # invoked. The block receives two parameters, an instance of the current - # class and the klass to be invoked. - # - def invoke_from_option(*names, &block) - options = names.last.is_a?(Hash) ? names.pop : {} - verbose = options.fetch(:verbose, :white) - - names.each do |name| - unless class_options.key?(name) - raise ArgumentError, "You have to define the option #{name.inspect} " << - "before setting invoke_from_option." - end - - invocations[name] = true - invocation_blocks[name] = block if block_given? - - class_eval <<-METHOD, __FILE__, __LINE__ - def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')} - return unless options[#{name.inspect}] - - value = options[#{name.inspect}] - value = #{name.inspect} if TrueClass === value - klass, task = self.class.prepare_for_invocation(#{name.inspect}, value) - - if klass - say_status :invoke, value, #{verbose.inspect} - block = self.class.invocation_blocks[#{name.inspect}] - invoke_with_padding klass, task, &block - else - say_status :error, %(\#{value} [not found]), :red - end - end - METHOD - end - end - - # Remove a previously added invocation. - # - # ==== Examples - # - # remove_invocation :test_framework - # - def remove_invocation(*names) - names.each do |name| - remove_task(name) - remove_class_option(name) - invocations.delete(name) - invocation_blocks.delete(name) - end - end - - # Overwrite class options help to allow invoked generators options to be - # shown recursively when invoking a generator. - # - def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc: - group_options = {} - - get_options_from_invocations(group_options, class_options) do |klass| - klass.send(:get_options_from_invocations, group_options, class_options) - end - - group_options.merge!(extra_group) if extra_group - super(shell, ungrouped_name, group_options) - end - - # Get invocations array and merge options from invocations. Those - # options are added to group_options hash. Options that already exists - # in base_options are not added twice. - # - def get_options_from_invocations(group_options, base_options) #:nodoc: - invocations.each do |name, from_option| - value = if from_option - option = class_options[name] - option.type == :boolean ? name : option.default - else - name - end - next unless value - - klass, task = prepare_for_invocation(name, value) - next unless klass && klass.respond_to?(:class_options) - - value = value.to_s - human_name = value.respond_to?(:classify) ? value.classify : value - - group_options[human_name] ||= [] - group_options[human_name] += klass.class_options.values.select do |option| - base_options[option.name.to_sym].nil? && option.group.nil? && - !group_options.values.flatten.any? { |i| i.name == option.name } - end - - yield klass if block_given? - end - end - - protected - - # The banner for this class. You can customize it if you are invoking the - # thor class by another means which is not the Thor::Runner. - # - def banner #:nodoc: - "#{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}" - end - - def baseclass #:nodoc: - Thor::Group - end - - def create_task(meth) #:nodoc: - tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil) - end - end - - include Thor::Base -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/invocation.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/invocation.rb deleted file mode 100644 index 4e8a7e578d..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/invocation.rb +++ /dev/null @@ -1,192 +0,0 @@ -class Thor - module Invocation - def self.included(base) #:nodoc: - base.extend ClassMethods - end - - module ClassMethods - # Prepare for class methods invocations. This method must return a klass to - # have the invoked class options showed in help messages in generators. - # - def prepare_for_invocation(key, name) #:nodoc: - case name - when Symbol, String - Thor::Util.namespace_to_thor_class(name.to_s, false) - else - name - end - end - end - - # Make initializer aware of invocations and the initializer proc. - # - def initialize(args=[], options={}, config={}, &block) #:nodoc: - @_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] } - @_initializer = [ args, options, config ] - super - end - - # Receives a name and invokes it. The name can be a string (either "task" or - # "namespace:task"), a Thor::Task, a Class or a Thor instance. If the task - # cannot be guessed by name, it can also be supplied as second argument. - # - # You can also supply the arguments, options and configuration values for - # the task to be invoked, if none is given, the same values used to - # initialize the invoker are used to initialize the invoked. - # - # ==== Examples - # - # class A < Thor - # def foo - # invoke :bar - # invoke "b:hello", ["José"] - # end - # - # def bar - # invoke "b:hello", ["José"] - # end - # end - # - # class B < Thor - # def hello(name) - # puts "hello #{name}" - # end - # end - # - # You can notice that the method "foo" above invokes two tasks: "bar", - # which belongs to the same class and "hello" which belongs to the class B. - # - # By using an invocation system you ensure that a task is invoked only once. - # In the example above, invoking "foo" will invoke "b:hello" just once, even - # if it's invoked later by "bar" method. - # - # When class A invokes class B, all arguments used on A initialization are - # supplied to B. This allows lazy parse of options. Let's suppose you have - # some rspec tasks: - # - # class Rspec < Thor::Group - # class_option :mock_framework, :type => :string, :default => :rr - # - # def invoke_mock_framework - # invoke "rspec:#{options[:mock_framework]}" - # end - # end - # - # As you noticed, it invokes the given mock framework, which might have its - # own options: - # - # class Rspec::RR < Thor::Group - # class_option :style, :type => :string, :default => :mock - # end - # - # Since it's not rspec concern to parse mock framework options, when RR - # is invoked all options are parsed again, so RR can extract only the options - # that it's going to use. - # - # If you want Rspec::RR to be initialized with its own set of options, you - # have to do that explicitely: - # - # invoke "rspec:rr", [], :style => :foo - # - # Besides giving an instance, you can also give a class to invoke: - # - # invoke Rspec::RR, [], :style => :foo - # - def invoke(name=nil, task=nil, args=nil, opts=nil, config=nil) - task, args, opts, config = nil, task, args, opts if task.nil? || task.is_a?(Array) - args, opts, config = nil, args, opts if args.is_a?(Hash) - - object, task = _prepare_for_invocation(name, task) - if object.is_a?(Class) - klass = object - - stored_args, stored_opts, stored_config = @_initializer - args ||= stored_args.dup - opts ||= stored_opts.dup - - config ||= {} - config = stored_config.merge(_shared_configuration).merge!(config) - instance = klass.new(args, opts, config) - else - klass, instance = object.class, object - end - - method_args = [] - current = @_invocations[klass] - - iterator = proc do |_, task| - unless current.include?(task.name) - current << task.name - task.run(instance, method_args) - end - end - - if task - args ||= [] - method_args = args[Range.new(klass.arguments.size, -1)] || [] - iterator.call(nil, task) - else - klass.all_tasks.map(&iterator) - end - end - - # Shortcut for invoke with padding and status handling. Used internally by - # class options invoke and invoke_from_option. - # - def invoke_with_padding(klass, task=nil, *args, &block) - shell.padding += 1 - - result = if block_given? - if block.arity == 2 - block.call(self, klass) - else - block.call(self, klass, task) - end - else - invoke klass, task, *args - end - - shell.padding -= 1 - result - end - - protected - - # Configuration values that are shared between invocations. - # - def _shared_configuration - { :invocations => @_invocations } - end - - # Prepare for invocation in the instance level. In this case, we have to - # take into account that a just a task name from the current class was - # given or even a Thor::Task object. - # - def _prepare_for_invocation(name, sent_task=nil) #:nodoc: - if name.is_a?(Thor::Task) - task = name - elsif task = self.class.all_tasks[name.to_s] - object = self - else - object, task = self.class.prepare_for_invocation(nil, name) - task ||= sent_task - end - - # If the object was not set, use self and use the name as task. - object, task = self, name unless object - return object, _validate_klass_and_task(object, task) - end - - # Check if the object given is a Thor class object and get a task object - # for it. - # - def _validate_klass_and_task(object, task) #:nodoc: - klass = object.is_a?(Class) ? object : object.class - raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base - - task ||= klass.default_task if klass <= Thor - task = klass.all_tasks[task.to_s] || Task.dynamic(task) if task && !task.is_a?(Thor::Task) - task - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/parser.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/parser.rb deleted file mode 100644 index 57a3f6e1a5..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/parser.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'thor/parser/argument' -require 'thor/parser/arguments' -require 'thor/parser/option' -require 'thor/parser/options' diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/argument.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/parser/argument.rb deleted file mode 100644 index 2d7f4dbafb..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/argument.rb +++ /dev/null @@ -1,67 +0,0 @@ -class Thor - class Argument - VALID_TYPES = [ :numeric, :hash, :array, :string ] - - attr_reader :name, :description, :required, :type, :default, :banner - alias :human_name :name - - def initialize(name, description=nil, required=true, type=:string, default=nil, banner=nil) - class_name = self.class.name.split("::").last - - raise ArgumentError, "#{class_name} name can't be nil." if name.nil? - raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) - - @name = name.to_s - @description = description - @required = required || false - @type = (type || :string).to_sym - @default = default - @banner = banner || default_banner - - validate! # Trigger specific validations - end - - def usage - required? ? banner : "[#{banner}]" - end - - def required? - required - end - - def show_default? - case default - when Array, String, Hash - !default.empty? - else - default - end - end - - protected - - def validate! - raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? - end - - def valid_type?(type) - VALID_TYPES.include?(type.to_sym) - end - - def default_banner - case type - when :boolean - nil - when :string, :default - human_name.upcase - when :numeric - "N" - when :hash - "key:value" - when :array - "one two three" - end - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/arguments.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/parser/arguments.rb deleted file mode 100644 index 9a2262d6f7..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/arguments.rb +++ /dev/null @@ -1,145 +0,0 @@ -class Thor - class Arguments - NUMERIC = /(\d*\.\d+|\d+)/ - - # Receives an array of args and returns two arrays, one with arguments - # and one with switches. - # - def self.split(args) - arguments = [] - - args.each do |item| - break if item =~ /^-/ - arguments << item - end - - return arguments, args[Range.new(arguments.size, -1)] - end - - def self.parse(base, args) - new(base).parse(args) - end - - # Takes an array of Thor::Argument objects. - # - def initialize(arguments=[]) - @assigns, @non_assigned_required = {}, [] - @switches = arguments - - arguments.each do |argument| - if argument.default - @assigns[argument.human_name] = argument.default - elsif argument.required? - @non_assigned_required << argument - end - end - end - - def parse(args) - @pile = args.dup - - @switches.each do |argument| - break unless peek - @non_assigned_required.delete(argument) - @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name) - end - - check_requirement! - @assigns - end - - private - - def peek - @pile.first - end - - def shift - @pile.shift - end - - def unshift(arg) - unless arg.kind_of?(Array) - @pile.unshift(arg) - else - @pile = arg + @pile - end - end - - def current_is_value? - peek && peek.to_s !~ /^-/ - end - - # Runs through the argument array getting strings that contains ":" and - # mark it as a hash: - # - # [ "name:string", "age:integer" ] - # - # Becomes: - # - # { "name" => "string", "age" => "integer" } - # - def parse_hash(name) - return shift if peek.is_a?(Hash) - hash = {} - - while current_is_value? && peek.include?(?:) - key, value = shift.split(':') - hash[key] = value - end - hash - end - - # Runs through the argument array getting all strings until no string is - # found or a switch is found. - # - # ["a", "b", "c"] - # - # And returns it as an array: - # - # ["a", "b", "c"] - # - def parse_array(name) - return shift if peek.is_a?(Array) - array = [] - - while current_is_value? - array << shift - end - array - end - - # Check if the peel is numeric ofrmat and return a Float or Integer. - # Otherwise raises an error. - # - def parse_numeric(name) - return shift if peek.is_a?(Numeric) - - unless peek =~ NUMERIC && $& == peek - raise MalformattedArgumentError, "expected numeric value for '#{name}'; got #{peek.inspect}" - end - - $&.index('.') ? shift.to_f : shift.to_i - end - - # Parse string, i.e., just return the current value in the pile. - # - def parse_string(name) - shift - end - - # Raises an error if @non_assigned_required array is not empty. - # - def check_requirement! - unless @non_assigned_required.empty? - names = @non_assigned_required.map do |o| - o.respond_to?(:switch_name) ? o.switch_name : o.human_name - end.join("', '") - - class_name = self.class.name.split('::').last.downcase - raise RequiredArgumentMissingError, "no value provided for required #{class_name} '#{names}'" - end - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/option.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/parser/option.rb deleted file mode 100644 index 5c43f6b18f..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/option.rb +++ /dev/null @@ -1,132 +0,0 @@ -class Thor - class Option < Argument - attr_reader :aliases, :group - - VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] - - def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, group=nil, aliases=nil) - super(name, description, required, type, default, banner) - @aliases = [*aliases].compact - @group = group.to_s.capitalize if group - end - - # This parse quick options given as method_options. It makes several - # assumptions, but you can be more specific using the option method. - # - # parse :foo => "bar" - # #=> Option foo with default value bar - # - # parse [:foo, :baz] => "bar" - # #=> Option foo with default value bar and alias :baz - # - # parse :foo => :required - # #=> Required option foo without default value - # - # parse :foo => 2 - # #=> Option foo with default value 2 and type numeric - # - # parse :foo => :numeric - # #=> Option foo without default value and type numeric - # - # parse :foo => true - # #=> Option foo with default value true and type boolean - # - # The valid types are :boolean, :numeric, :hash, :array and :string. If none - # is given a default type is assumed. This default type accepts arguments as - # string (--foo=value) or booleans (just --foo). - # - # By default all options are optional, unless :required is given. - # - def self.parse(key, value) - if key.is_a?(Array) - name, *aliases = key - else - name, aliases = key, [] - end - - name = name.to_s - default = value - - type = case value - when Symbol - default = nil - - if VALID_TYPES.include?(value) - value - elsif required = (value == :required) - :string - elsif value == :optional - # TODO Remove this warning in the future. - warn "Optional type is deprecated. Choose :boolean or :string instead. Assumed to be :boolean." - :boolean - end - when TrueClass, FalseClass - :boolean - when Numeric - :numeric - when Hash, Array, String - value.class.name.downcase.to_sym - end - - self.new(name.to_s, nil, required, type, default, nil, nil, aliases) - end - - def switch_name - @switch_name ||= dasherized? ? name : dasherize(name) - end - - def human_name - @human_name ||= dasherized? ? undasherize(name) : name - end - - def usage(padding=0) - sample = if banner && !banner.to_s.empty? - "#{switch_name}=#{banner}" - else - switch_name - end - - sample = "[#{sample}]" unless required? - - if aliases.empty? - (" " * padding) << sample - else - "#{aliases.join(', ')}, #{sample}" - end - end - - # Allow some type predicates as: boolean?, string? and etc. - # - def method_missing(method, *args, &block) - given = method.to_s.sub(/\?$/, '').to_sym - if valid_type?(given) - self.type == given - else - super - end - end - - protected - - def validate! - raise ArgumentError, "An option cannot be boolean and required." if boolean? && required? - end - - def valid_type?(type) - VALID_TYPES.include?(type.to_sym) - end - - def dasherized? - name.index('-') == 0 - end - - def undasherize(str) - str.sub(/^-{1,2}/, '') - end - - def dasherize(str) - (str.length > 1 ? "--" : "-") + str.gsub('_', '-') - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/options.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/parser/options.rb deleted file mode 100644 index 01c86b7b27..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/parser/options.rb +++ /dev/null @@ -1,142 +0,0 @@ -class Thor - # This is a modified version of Daniel Berger's Getopt::Long class, licensed - # under Ruby's license. - # - class Options < Arguments - LONG_RE = /^(--\w+[-\w+]*)$/ - SHORT_RE = /^(-[a-z])$/i - EQ_RE = /^(--\w+[-\w+]*|-[a-z])=(.*)$/i - SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args - SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i - - # Receives a hash and makes it switches. - # - def self.to_switches(options) - options.map do |key, value| - case value - when true - "--#{key}" - when Array - "--#{key} #{value.map{ |v| v.inspect }.join(' ')}" - when Hash - "--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}" - when nil, false - "" - else - "--#{key} #{value.inspect}" - end - end.join(" ") - end - - # Takes a hash of Thor::Option objects. - # - def initialize(options={}) - options = options.values - super(options) - @shorts, @switches = {}, {} - - options.each do |option| - @switches[option.switch_name] = option - - option.aliases.each do |short| - @shorts[short.to_s] ||= option.switch_name - end - end - end - - def parse(args) - @pile = args.dup - - while peek - if current_is_switch? - case shift - when SHORT_SQ_RE - unshift($1.split('').map { |f| "-#{f}" }) - next - when EQ_RE, SHORT_NUM - unshift($2) - switch = $1 - when LONG_RE, SHORT_RE - switch = $1 - end - - switch = normalize_switch(switch) - next unless option = switch_option(switch) - - @assigns[option.human_name] = parse_peek(switch, option) - else - shift - end - end - - check_requirement! - @assigns - end - - protected - - # Returns true if the current value in peek is a registered switch. - # - def current_is_switch? - case peek - when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM - switch?($1) - when SHORT_SQ_RE - $1.split('').any? { |f| switch?("-#{f}") } - end - end - - def switch?(arg) - switch_option(arg) || @shorts.key?(arg) - end - - def switch_option(arg) - if match = no_or_skip?(arg) - @switches[arg] || @switches["--#{match}"] - else - @switches[arg] - end - end - - def no_or_skip?(arg) - arg =~ /^--(no|skip)-([-\w]+)$/ - $2 - end - - # Check if the given argument is actually a shortcut. - # - def normalize_switch(arg) - @shorts.key?(arg) ? @shorts[arg] : arg - end - - # Parse boolean values which can be given as --foo=true, --foo or --no-foo. - # - def parse_boolean(switch) - if current_is_value? - ["true", "TRUE", "t", "T", true].include?(shift) - else - @switches.key?(switch) || !no_or_skip?(switch) - end - end - - # Parse the value at the peek analyzing if it requires an input or not. - # - def parse_peek(switch, option) - unless current_is_value? - if option.boolean? - # No problem for boolean types - elsif no_or_skip?(switch) - return nil # User set value to nil - elsif option.string? && !option.required? - return option.human_name # Return the option name - else - raise MalformattedArgumentError, "no value provided for option '#{switch}'" - end - end - - @non_assigned_required.delete(option) - send(:"parse_#{option.type}", switch) - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/runner.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/runner.rb deleted file mode 100644 index 330de38449..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/runner.rb +++ /dev/null @@ -1,295 +0,0 @@ -require 'fileutils' -require 'open-uri' -require 'yaml' -require 'digest/md5' -require 'pathname' - -class Thor::Runner < Thor - map "-T" => :list, "-i" => :install, "-u" => :update - - # Override Thor#help so it can give information about any class and any method. - # - def help(meth=nil) - if meth && !self.respond_to?(meth) - initialize_thorfiles(meth) - klass, task = Thor::Util.namespace_to_thor_class(meth) - klass.start(["-h", task].compact, :shell => self.shell) # send mapping -h because it works with Thor::Group too - else - super - end - end - - # If a task is not found on Thor::Runner, method missing is invoked and - # Thor::Runner is then responsable for finding the task in all classes. - # - def method_missing(meth, *args) - meth = meth.to_s - initialize_thorfiles(meth) - klass, task = Thor::Util.namespace_to_thor_class(meth) - args.unshift(task) if task - klass.start(args, :shell => shell) - end - - desc "install NAME", "Install a Thor file into your system tasks, optionally named for future updates" - method_options :as => :string, :relative => :boolean - def install(name) - initialize_thorfiles - - # If a directory name is provided as the argument, look for a 'main.thor' - # task in said directory. - begin - if File.directory?(File.expand_path(name)) - base, package = File.join(name, "main.thor"), :directory - contents = open(base).read - else - base, package = name, :file - contents = open(name).read - end - rescue OpenURI::HTTPError - raise Error, "Error opening URI '#{name}'" - rescue Errno::ENOENT - raise Error, "Error opening file '#{name}'" - end - - say "Your Thorfile contains:" - say contents - - return false if no?("Do you wish to continue [y/N]?") - - as = options["as"] || begin - first_line = contents.split("\n")[0] - (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil - end - - unless as - basename = File.basename(name) - as = ask("Please specify a name for #{name} in the system repository [#{basename}]:") - as = basename if as.empty? - end - - location = if options[:relative] || name =~ /^http:\/\// - name - else - File.expand_path(name) - end - - thor_yaml[as] = { - :filename => Digest::MD5.hexdigest(name + as), - :location => location, - :namespaces => Thor::Util.namespaces_in_contents(contents, base) - } - - save_yaml(thor_yaml) - say "Storing thor file in your system repository" - destination = File.join(thor_root, thor_yaml[as][:filename]) - - if package == :file - File.open(destination, "w") { |f| f.puts contents } - else - FileUtils.cp_r(name, destination) - end - - thor_yaml[as][:filename] # Indicate success - end - - desc "uninstall NAME", "Uninstall a named Thor module" - def uninstall(name) - raise Error, "Can't find module '#{name}'" unless thor_yaml[name] - say "Uninstalling #{name}." - FileUtils.rm_rf(File.join(thor_root, "#{thor_yaml[name][:filename]}")) - - thor_yaml.delete(name) - save_yaml(thor_yaml) - - puts "Done." - end - - desc "update NAME", "Update a Thor file from its original location" - def update(name) - raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location] - - say "Updating '#{name}' from #{thor_yaml[name][:location]}" - - old_filename = thor_yaml[name][:filename] - self.options = self.options.merge("as" => name) - filename = install(thor_yaml[name][:location]) - - unless filename == old_filename - File.delete(File.join(thor_root, old_filename)) - end - end - - desc "installed", "List the installed Thor modules and tasks" - method_options :internal => :boolean - def installed - initialize_thorfiles(nil, true) - - klasses = Thor::Base.subclasses - klasses -= [Thor, Thor::Runner] unless options["internal"] - - display_klasses(true, klasses) - end - - desc "list [SEARCH]", - "List the available thor tasks (--substring means SEARCH anywhere in the namespace)" - method_options :substring => :boolean, :group => :string, :all => :boolean - def list(search="") - initialize_thorfiles - - search = ".*#{search}" if options["substring"] - search = /^#{search}.*/i - group = options[:group] || "standard" - - klasses = Thor::Base.subclasses.select do |k| - (options[:all] || k.group == group) && k.namespace =~ search - end - - display_klasses(false, klasses) - end - - private - - def thor_root - Thor::Util.thor_root - end - - def thor_yaml - @thor_yaml ||= begin - yaml_file = File.join(thor_root, "thor.yml") - yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file) - yaml || {} - end - end - - # Save the yaml file. If none exists in thor root, creates one. - # - def save_yaml(yaml) - yaml_file = File.join(thor_root, "thor.yml") - - unless File.exists?(yaml_file) - FileUtils.mkdir_p(thor_root) - yaml_file = File.join(thor_root, "thor.yml") - FileUtils.touch(yaml_file) - end - - File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml } - end - - # Load the thorfiles. If relevant_to is supplied, looks for specific files - # in the thor_root instead of loading them all. - # - # By default, it also traverses the current path until find Thor files, as - # described in thorfiles. This look up can be skipped by suppliying - # skip_lookup true. - # - def initialize_thorfiles(relevant_to=nil, skip_lookup=false) - thorfiles(relevant_to, skip_lookup).each do |f| - Thor::Util.load_thorfile(f) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f)) - end - end - - # Finds Thorfiles by traversing from your current directory down to the root - # directory of your system. If at any time we find a Thor file, we stop. - # - # We also ensure that system-wide Thorfiles are loaded first, so local - # Thorfiles can override them. - # - # ==== Example - # - # If we start at /Users/wycats/dev/thor ... - # - # 1. /Users/wycats/dev/thor - # 2. /Users/wycats/dev - # 3. /Users/wycats <-- we find a Thorfile here, so we stop - # - # Suppose we start at c:\Documents and Settings\james\dev\thor ... - # - # 1. c:\Documents and Settings\james\dev\thor - # 2. c:\Documents and Settings\james\dev - # 3. c:\Documents and Settings\james - # 4. c:\Documents and Settings - # 5. c:\ <-- no Thorfiles found! - # - def thorfiles(relevant_to=nil, skip_lookup=false) - # Deal with deprecated thor when :namespaces: is available as constants - save_yaml(thor_yaml) if Thor::Util.convert_constants_to_namespaces(thor_yaml) - - thorfiles = [] - - unless skip_lookup - Pathname.pwd.ascend do |path| - thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten - break unless thorfiles.empty? - end - end - - files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob) - files += thorfiles - files -= ["#{thor_root}/thor.yml"] - - files.map! do |file| - File.directory?(file) ? File.join(file, "main.thor") : file - end - end - - # Load thorfiles relevant to the given method. If you provide "foo:bar" it - # will load all thor files in the thor.yaml that has "foo" e "foo:bar" - # namespaces registered. - # - def thorfiles_relevant_to(meth) - lookup = [ meth, meth.split(":")[0...-1].join(":") ] - - files = thor_yaml.select do |k, v| - v[:namespaces] && !(v[:namespaces] & lookup).empty? - end - - files.map { |k, v| File.join(thor_root, "#{v[:filename]}") } - end - - # Display information about the given klasses. If with_module is given, - # it shows a table with information extracted from the yaml file. - # - def display_klasses(with_modules=false, klasses=Thor.subclasses) - klasses -= [Thor, Thor::Runner] unless with_modules - raise Error, "No Thor tasks available" if klasses.empty? - - if with_modules && !thor_yaml.empty? - info = [] - labels = ["Modules", "Namespaces"] - - info << labels - info << [ "-" * labels[0].size, "-" * labels[1].size ] - - thor_yaml.each do |name, hash| - info << [ name, hash[:namespaces].join(", ") ] - end - - print_table info - say "" - end - - unless klasses.empty? - klasses.each { |k| display_tasks(k) } - else - say "\033[1;34mNo Thor tasks available\033[0m" - end - end - - # Display tasks from the given Thor class. - # - def display_tasks(klass) - unless klass.tasks.empty? - base = klass.namespace - - if base == "default" - say "\033[1;35m#{base}\033[0m" - else - say "\033[1;34m#{base}\033[0m" - end - say "-" * base.length - - klass.help(shell, :short => true, :namespace => true) - say - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/shell.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/shell.rb deleted file mode 100644 index 7ed4a24bfb..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/shell.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'thor/shell/color' - -class Thor - module Base - # Returns the shell used in all Thor classes. Default to color one. - # - def self.shell - @shell ||= Thor::Shell::Color - end - - # Sets the shell used in all Thor classes. - # - def self.shell=(klass) - @shell = klass - end - end - - module Shell - SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_list, :print_table] - - # Add shell to initialize config values. - # - # ==== Configuration - # shell:: An instance of the shell to be used. - # - # ==== Examples - # - # class MyScript < Thor - # argument :first, :type => :numeric - # end - # - # MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new - # - def initialize(args=[], options={}, config={}) - super - self.shell = config[:shell] - self.shell.base ||= self if self.shell.respond_to?(:base) - end - - # Holds the shell for the given Thor instance. If no shell is given, - # it gets a default shell from Thor::Base.shell. - # - def shell - @shell ||= Thor::Base.shell.new - end - - # Sets the shell for this thor class. - # - def shell=(shell) - @shell = shell - end - - # Common methods that are delegated to the shell. - # - SHELL_DELEGATED_METHODS.each do |method| - module_eval <<-METHOD, __FILE__, __LINE__ - def #{method}(*args) - shell.#{method}(*args) - end - METHOD - end - - protected - - # Allow shell to be shared between invocations. - # - def _shared_configuration - super.merge!(:shell => self.shell) - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/shell/basic.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/shell/basic.rb deleted file mode 100644 index 6f1a2ade07..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/shell/basic.rb +++ /dev/null @@ -1,221 +0,0 @@ -require 'tempfile' - -class Thor - module Shell - class Basic - attr_accessor :base, :padding - - # Initialize base and padding to nil. - # - def initialize #:nodoc: - @base, @padding = nil, 0 - end - - # Do not allow padding to be less than zero. - # - def padding=(value) #:nodoc: - @padding = [0, value].max - end - - # Ask something to the user and receives a response. - # - # ==== Example - # ask("What is your name?") - # - def ask(statement, color=nil) - say("#{statement} ", color) - $stdin.gets.strip - end - - # Say (print) something to the user. If the sentence ends with a whitespace - # or tab character, a new line is not appended (print + flush). Otherwise - # are passed straight to puts (behavior got from Highline). - # - # ==== Example - # say("I know you knew that.") - # - def say(message="", color=nil, force_new_line=false) - message = message.to_s - new_line = force_new_line || !(message[-1, 1] == " " || message[-1, 1] == "\t") - message = set_color(message, color) if color - - if new_line - $stdout.puts(message) - else - $stdout.print(message) - $stdout.flush - end - end - - # Say a status with the given color and appends the message. Since this - # method is used frequently by actions, it allows nil or false to be given - # in log_status, avoiding the message from being shown. If a Symbol is - # given in log_status, it's used as the color. - # - def say_status(status, message, log_status=true) #:nodoc: - return if quiet? || log_status == false - spaces = " " * (padding + 1) - color = log_status.is_a?(Symbol) ? log_status : :green - - status = status.to_s.rjust(12) - status = set_color status, color, true if color - say "#{status}#{spaces}#{message}", nil, true - end - - # Make a question the to user and returns true if the user replies "y" or - # "yes". - # - def yes?(statement, color=nil) - ask(statement, color) =~ is?(:yes) - end - - # Make a question the to user and returns true if the user replies "n" or - # "no". - # - def no?(statement, color=nil) - !yes?(statement, color) - end - - # Prints a list of items. - # - # ==== Parameters - # list - # mode:: Can be :rows or :inline. Defaults to :rows. - # - def print_list(list, mode=:rows) - return if list.empty? - - content = case mode - when :inline - last = list.pop - "#{list.join(", ")}, and #{last}" - else # rows - list.join("\n") - end - - $stdout.puts content - end - - # Prints a table. - # - # ==== Parameters - # Array[Array[String, String, ...]] - # - # ==== Options - # ident:: Ident the first column by ident value. - # emphasize_last:: When true, add a different behavior to the last column. - # - def print_table(table, options={}) - return if table.empty? - - formats = [] - 0.upto(table.first.length - 2) do |i| - maxima = table.max{ |a,b| a[i].size <=> b[i].size }[i].size - formats << "%-#{maxima + 2}s" - end - - formats[0] = formats[0].insert(0, " " * options[:ident]) if options[:ident] - formats << "%s" - - if options[:emphasize_last] - table.each do |row| - next if row[-1].empty? - row[-1] = "# #{row[-1]}" - end - end - - table.each do |row| - row.each_with_index do |column, i| - $stdout.print formats[i] % column.to_s - end - $stdout.puts - end - end - - # Deals with file collision and returns true if the file should be - # overwriten and false otherwise. If a block is given, it uses the block - # response as the content for the diff. - # - # ==== Parameters - # destination:: the destination file to solve conflicts - # block:: an optional proc that returns the value to be used in diff - # - def file_collision(destination) - return true if @always_force - options = block_given? ? "[Ynaqdh]" : "[Ynaqh]" - - while true - answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}] - - case answer - when is?(:yes), is?(:force) - return true - when is?(:no), is?(:skip) - return false - when is?(:always) - return @always_force = true - when is?(:quit) - say 'Aborting...' - raise SystemExit - when is?(:diff) - show_diff(destination, yield) if block_given? - say 'Retrying...' - else - say file_collision_help - end - end - end - - # Called if something goes wrong during the execution. This is used by Thor - # internally and should not be used inside your scripts. If someone went - # wrong, you can always raise an exception. If you raise a Thor::Error, it - # will be rescued and wrapped in the method below. - # - def error(statement) #:nodoc: - $stderr.puts statement - end - - protected - - def set_color(string, color, bold=false) - string - end - - def is?(value) - value = value.to_s - - if value.size == 1 - /\A#{value}\z/i - else - /\A(#{value}|#{value[0,1]})\z/i - end - end - - def file_collision_help -< e - parse_argument_error(instance, e, caller) - rescue NoMethodError => e - parse_no_method_error(instance, e) - end - - # Returns the formatted usage. If a class is given, the class arguments are - # injected in the usage. - # - def formatted_usage(klass=nil, namespace=false) - formatted = '' - formatted << "#{klass.namespace.gsub(/^default/,'')}:" if klass && namespace - formatted << formatted_arguments(klass) - formatted << " #{formatted_options}" - formatted.strip! - formatted - end - - # Injects the class arguments into the task usage. - # - def formatted_arguments(klass) - if klass && !klass.arguments.empty? - usage.to_s.gsub(/^#{name}/) do |match| - match << " " << klass.arguments.map{ |a| a.usage }.join(' ') - end - else - usage.to_s - end - end - - # Returns the options usage for this task. - # - def formatted_options - @formatted_options ||= options.map{ |_, o| o.usage }.sort.join(" ") - end - - protected - - # Given a target, checks if this class name is not a private/protected method. - # - def public_method?(instance) - collection = instance.private_methods + instance.protected_methods - !(collection).include?(name.to_s) && !(collection).include?(name.to_sym) # For Ruby 1.9 - end - - # Clean everything that comes from the Thor gempath and remove the caller. - # - def sans_backtrace(backtrace, caller) - dirname = /^#{Regexp.escape(File.dirname(__FILE__))}/ - saned = backtrace.reject { |frame| frame =~ dirname } - saned -= caller - end - - def parse_argument_error(instance, e, caller) - backtrace = sans_backtrace(e.backtrace, caller) - - if backtrace.empty? && e.message =~ /wrong number of arguments/ - if instance.is_a?(Thor::Group) - raise e, "'#{name}' was called incorrectly. Are you sure it has arity equals to 0?" - else - raise InvocationError, "'#{name}' was called incorrectly. Call as " << - "'#{formatted_usage(instance.class, true)}'" - end - else - raise e - end - end - - def parse_no_method_error(instance, e) - if e.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ - raise UndefinedTaskError, "The #{instance.class.namespace} namespace " << - "doesn't have a '#{name}' task" - else - raise e - end - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/tasks.rb deleted file mode 100644 index d1a7b1c673..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks.rb +++ /dev/null @@ -1,4 +0,0 @@ -# This only loads all tasks inside tasks. -Dir[File.join(File.dirname(__FILE__), "tasks", "*.rb")].each do |task| - require task -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/install.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/install.rb deleted file mode 100644 index 6b20ff1634..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/install.rb +++ /dev/null @@ -1,35 +0,0 @@ -class Thor - # Creates an install task. - # - # ==== Parameters - # spec - # - # ==== Options - # :dir - The directory where the package is hold before installation. Defaults to ./pkg. - # - def self.install_task(spec, options={}) - package_task(spec, options) - tasks['install'] = Thor::InstallTask.new(spec, options) - end - - class InstallTask < Task - attr_accessor :spec, :config - - def initialize(gemspec, config={}) - super(:install, "Install the gem", "install", {}) - @spec = gemspec - @config = { :dir => File.join(Dir.pwd, "pkg") }.merge(config) - end - - def run(instance, args=[]) - null, sudo, gem = RUBY_PLATFORM =~ /mswin|mingw/ ? ['NUL', '', 'gem.bat'] : - ['/dev/null', 'sudo', 'gem'] - - old_stderr, $stderr = $stderr.dup, File.open(null, "w") - instance.invoke(:package) - $stderr = old_stderr - - system %{#{sudo} #{Gem.ruby} -S #{gem} install #{config[:dir]}/#{spec.name}-#{spec.version} --no-rdoc --no-ri --no-update-sources} - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/package.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/package.rb deleted file mode 100644 index 603d61b4ab..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/package.rb +++ /dev/null @@ -1,31 +0,0 @@ -require "fileutils" - -class Thor - # Creates a package task. - # - # ==== Parameters - # spec - # - # ==== Options - # :dir - The package directory. Defaults to ./pkg. - # - def self.package_task(spec, options={}) - tasks['package'] = Thor::PackageTask.new(spec, options) - end - - class PackageTask < Task - attr_accessor :spec, :config - - def initialize(gemspec, config={}) - super(:package, "Build a gem package", "package", {}) - @spec = gemspec - @config = {:dir => File.join(Dir.pwd, "pkg")}.merge(config) - end - - def run(instance, args=[]) - FileUtils.mkdir_p(config[:dir]) - Gem::Builder.new(spec).build - FileUtils.mv(spec.file_name, File.join(config[:dir], spec.file_name)) - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/spec.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/spec.rb deleted file mode 100644 index c7d00968e8..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/tasks/spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -require "fileutils" - -class Thor - # Creates a spec task. - # - # ==== Parameters - # files - Array of files to spec - # - # ==== Options - # :name - The name of the task. It can be rcov or spec. Spec is the default. - # :rcov - A hash with rcov specific options. - # :rcov_dir - Where rcov reports should be printed. - # :verbose - Sets the default value for verbose, although it can be specified - # also through the command line. - # - # All other options are added to rspec. - # - def self.spec_task(files, options={}) - name = (options.delete(:name) || 'spec').to_s - tasks[name] = Thor::SpecTask.new(name, files, options) - end - - class SpecTask < Task - attr_accessor :name, :files, :rcov_dir, :rcov_config, :spec_config - - def initialize(name, files, config={}) - options = { :verbose => Thor::Option.parse(:verbose, config.delete(:verbose) || false) } - super(name, "#{name.capitalize} task", name, options) - - @name = name - @files = files.map{ |f| %["#{f}"] }.join(" ") - @rcov_dir = config.delete(:rdoc_dir) || File.join(Dir.pwd, 'coverage') - @rcov_config = config.delete(:rcov) || {} - @spec_config = { :format => 'specdoc', :color => true }.merge(config) - end - - def run(instance, args=[]) - rcov_opts = Thor::Options.to_switches(rcov_config) - spec_opts = Thor::Options.to_switches(spec_config) - - require 'rbconfig' - cmd = RbConfig::CONFIG['ruby_install_name'] << " " - - if rcov? - FileUtils.rm_rf(rcov_dir) - cmd << "-S #{where('rcov')} -o #{rcov_dir} #{rcov_opts} " - end - - cmd << [where('spec'), rcov? ? " -- " : nil, files, spec_opts].join(" ") - - puts cmd if instance.options.verbose? - system(cmd) - exit($?.exitstatus) - end - - private - - def rcov? - name == "rcov" - end - - def where(file) - ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| - file_with_path = File.join(path, file) - next unless File.exist?(file_with_path) && File.executable?(file_with_path) - return File.expand_path(file_with_path) - end - end - end -end diff --git a/railties/lib/vendor/thor-0.11.1/lib/thor/util.rb b/railties/lib/vendor/thor-0.11.1/lib/thor/util.rb deleted file mode 100644 index 26db24aadb..0000000000 --- a/railties/lib/vendor/thor-0.11.1/lib/thor/util.rb +++ /dev/null @@ -1,229 +0,0 @@ -require 'rbconfig' - -class Thor - module Sandbox; end - - # This module holds several utilities: - # - # 1) Methods to convert thor namespaces to constants and vice-versa. - # - # Thor::Utils.constant_to_namespace(Foo::Bar::Baz) #=> "foo:bar:baz" - # Thor::Utils.namespace_to_constant("foo:bar:baz") #=> Foo::Bar::Baz - # - # 2) Loading thor files and sandboxing: - # - # Thor::Utils.load_thorfile("~/.thor/foo") - # - module Util - - # Receives a namespace and search for it in the Thor::Base subclasses. - # - # ==== Parameters - # namespace:: The namespace to search for. - # - def self.find_by_namespace(namespace) - namespace = 'default' if namespace.empty? - - Thor::Base.subclasses.find do |klass| - klass.namespace == namespace - end - end - - # Receives a constant and converts it to a Thor namespace. Since Thor tasks - # can be added to a sandbox, this method is also responsable for removing - # the sandbox namespace. - # - # This method should not be used in general because it's used to deal with - # older versions of Thor. On current versions, if you need to get the - # namespace from a class, just call namespace on it. - # - # ==== Parameters - # constant:: The constant to be converted to the thor path. - # - # ==== Returns - # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz" - # - def self.constant_to_namespace(constant, remove_default=true) - constant = constant.to_s.gsub(/^Thor::Sandbox::/, "") - constant = snake_case(constant).squeeze(":") - constant.gsub!(/^default/, '') if remove_default - constant - end - - # Given the contents, evaluate it inside the sandbox and returns the thor - # classes defined in the sandbox. - # - # ==== Parameters - # contents - # - # ==== Returns - # Array[Object] - # - def self.namespaces_in_contents(contents, file=__FILE__) - old_constants = Thor::Base.subclasses.dup - Thor::Base.subclasses.clear - - load_thorfile(file, contents) - - new_constants = Thor::Base.subclasses.dup - Thor::Base.subclasses.replace(old_constants) - - new_constants.map!{ |c| c.namespace } - new_constants.compact! - new_constants - end - - # Receives a string and convert it to snake case. SnakeCase returns snake_case. - # - # ==== Parameters - # String - # - # ==== Returns - # String - # - def self.snake_case(str) - return str.downcase if str =~ /^[A-Z_]+$/ - str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/ - return $+.downcase - end - - # Receives a namespace and tries to retrieve a Thor or Thor::Group class - # from it. It first searches for a class using the all the given namespace, - # if it's not found, removes the highest entry and searches for the class - # again. If found, returns the highest entry as the class name. - # - # ==== Examples - # - # class Foo::Bar < Thor - # def baz - # end - # end - # - # class Baz::Foo < Thor::Group - # end - # - # Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default task - # Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil - # Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz" - # - # ==== Parameters - # namespace - # - # ==== Errors - # Thor::Error:: raised if the namespace cannot be found. - # - # Thor::Error:: raised if the namespace evals to a class which does not - # inherit from Thor or Thor::Group. - # - def self.namespace_to_thor_class(namespace, raise_if_nil=true) - klass, task_name = Thor::Util.find_by_namespace(namespace), nil - - if klass.nil? && namespace.include?(?:) - namespace = namespace.split(":") - task_name = namespace.pop - klass = Thor::Util.find_by_namespace(namespace.join(":")) - end - - raise Error, "could not find Thor class or task '#{namespace}'" if raise_if_nil && klass.nil? - - return klass, task_name - end - - # Receives a path and load the thor file in the path. The file is evaluated - # inside the sandbox to avoid namespacing conflicts. - # - def self.load_thorfile(path, content=nil) - content ||= File.read(path) - - begin - Thor::Sandbox.class_eval(content, path) - rescue Exception => e - $stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}" - end - end - - # Receives a yaml (hash) and updates all constants entries to namespace. - # This was added to deal with deprecated versions of Thor. - # - # TODO Deprecate this method in the future. - # - # ==== Returns - # TrueClass|FalseClass:: Returns true if any change to the yaml file was made. - # - def self.convert_constants_to_namespaces(yaml) - yaml_changed = false - - yaml.each do |k, v| - next unless v[:constants] && v[:namespaces].nil? - yaml_changed = true - yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.constant_to_namespace(c)} - end - - yaml_changed - end - - def self.user_home - @@user_home ||= if ENV["HOME"] - ENV["HOME"] - elsif ENV["USERPROFILE"] - ENV["USERPROFILE"] - elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"] - File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"]) - elsif ENV["APPDATA"] - ENV["APPDATA"] - else - begin - File.expand_path("~") - rescue - if File::ALT_SEPARATOR - "C:/" - else - "/" - end - end - end - end - - # Returns the root where thor files are located, dependending on the OS. - # - def self.thor_root - File.join(user_home, ".thor") - end - - # Returns the files in the thor root. On Windows thor_root will be something - # like this: - # - # C:\Documents and Settings\james\.thor - # - # If we don't #gsub the \ character, Dir.glob will fail. - # - def self.thor_root_glob - files = Dir["#{thor_root.gsub(/\\/, '/')}/*"] - - files.map! do |file| - File.directory?(file) ? File.join(file, "main.thor") : file - end - end - - # Where to look for Thor files. - # - def self.globs_for(path) - ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] - end - - # Return the path to the ruby interpreter taking into account multiple - # installations and windows extensions. - # - def self.ruby_command #:nodoc: - @ruby_command ||= begin - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - ruby << Config::CONFIG['EXEEXT'] - - # escape string in case path to ruby executable contain spaces. - ruby.sub!(/.*\s.*/m, '"\&"') - ruby - end - end - - end -end diff --git a/railties/lib/vendor/thor-0.11.2/CHANGELOG.rdoc b/railties/lib/vendor/thor-0.11.2/CHANGELOG.rdoc new file mode 100644 index 0000000000..544dde8c02 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/CHANGELOG.rdoc @@ -0,0 +1,75 @@ +== TODO + +* Improve spec coverage for Thor::Runner +* Improve help output to list shorthand switches, too + +== Current + +* BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore + since it wrong behavior to the invocation system. + +* thor help now show information about any class/task. All those calls are + possible: + + thor help describe + thor help describe:amazing + + Or even with default namespaces: + + thor help :spec + +* Thor::Runner now invokes the default task if none is supplied: + + thor describe # invokes the default task, usually help + +* Thor::Runner now works with mappings: + + thor describe -h + +* Added some documentation and code refactoring. + +== 0.9.8, released 2008-10-20 + +* Fixed some tiny issues that were introduced lately. + +== 0.9.7, released 2008-10-13 + +* Setting global method options on the initialize method works as expected: + All other tasks will accept these global options in addition to their own. +* Added 'group' notion to Thor task sets (class Thor); by default all tasks + are in the 'standard' group. Running 'thor -T' will only show the standard + tasks - adding --all will show all tasks. You can also filter on a specific + group using the --group option: thor -T --group advanced + +== 0.9.6, released 2008-09-13 + +* Generic improvements + +== 0.9.5, released 2008-08-27 + +* Improve Windows compatibility +* Update (incorrect) README and task.thor sample file +* Options hash is now frozen (once returned) +* Allow magic predicates on options object. For instance: `options.force?` +* Add support for :numeric type +* BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f]) +* Allow specifying optional args with default values: method_options(:user => "mislav") +* Don't write options for nil or false values. This allows, for example, turning color off when running specs. +* Exit with the status of the spec command to help CI stuff out some. + +== 0.9.4, released 2008-08-13 + +* Try to add Windows compatibility. +* BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore +* Allow options at the beginning of the argument list as well as the end. +* Make options available with symbol keys in addition to string keys. +* Allow true to be passed to Thor#method_options to denote a boolean option. +* If loading a thor file fails, don't give up, just print a warning and keep going. +* Make sure that we re-raise errors if they happened further down the pipe than we care about. +* Only delete the old file on updating when the installation of the new one is a success +* Make it Ruby 1.8.5 compatible. +* Don't raise an error if a boolean switch is defined multiple times. +* Thor::Options now doesn't parse through things that look like options but aren't. +* Add URI detection to install task, and make sure we don't append ".thor" to URIs +* Add rake2thor to the gem binfiles. +* Make sure local Thorfiles override system-wide ones. diff --git a/railties/lib/vendor/thor-0.11.2/LICENSE b/railties/lib/vendor/thor-0.11.2/LICENSE new file mode 100644 index 0000000000..98722da459 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2008 Yehuda Katz + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/railties/lib/vendor/thor-0.11.2/README.markdown b/railties/lib/vendor/thor-0.11.2/README.markdown new file mode 100644 index 0000000000..a1d7259775 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/README.markdown @@ -0,0 +1,247 @@ +thor +==== + +Map options to a class. Simply create a class with the appropriate annotations +and have options automatically map to functions and parameters. + +Example: + + class App < Thor # [1] + map "-L" => :list # [2] + + desc "install APP_NAME", "install one of the available apps" # [3] + method_options :force => :boolean, :alias => :string # [4] + def install(name) + user_alias = options[:alias] + if options.force? + # do something + end + # other code + end + + desc "list [SEARCH]", "list all of the available apps, limited by SEARCH" + def list(search="") + # list everything + end + end + +Thor automatically maps commands as such: + + thor app:install myname --force + +That gets converted to: + + App.new.install("myname") + # with {'force' => true} as options hash + +1. Inherit from Thor to turn a class into an option mapper +2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list +3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description +4. Provide any additional options that will be available the instance method options. + +Types for `method_options` +-------------------------- + +
+
:boolean
+
is parsed as --option or --option=true
+
:string
+
is parsed as --option=VALUE
+
:numeric
+
is parsed as --option=N
+
:array
+
is parsed as --option=one two three
+
:hash
+
is parsed as --option=key:value key:value key:value
+
+ +Besides, method_option allows a default value to be given, examples: + + method_options :force => false + #=> Creates a boolean option with default value false + + method_options :alias => "bar" + #=> Creates a string option with default value "bar" + + method_options :threshold => 3.0 + #=> Creates a numeric option with default value 3.0 + +You can also supply :option => :required to mark an option as required. The +type is assumed to be string. If you want a required hash with default values +as option, you can use `method_option` which uses a more declarative style: + + method_option :attributes, :type => :hash, :default => {}, :required => true + +All arguments can be set to nil (except required arguments), by suppling a no or +skip variant. For example: + + thor app name --no-attributes + +In previous versions, aliases for options were created automatically, but now +they should be explicit. You can supply aliases in both short and declarative +styles: + + method_options %w( force -f ) => :boolean + +Or: + + method_option :force, :type => :boolean, :aliases => "-f" + +You can supply as many aliases as you want. + +NOTE: Type :optional available in Thor 0.9.0 was deprecated. Use :string or :boolean instead. + +Namespaces +---------- + +By default, your Thor tasks are invoked using Ruby namespace. In the example +above, tasks are invoked as: + + thor app:install name --force + +However, you could namespace your class as: + + module Sinatra + class App < Thor + # tasks + end + end + +And then you should invoke your tasks as: + + thor sinatra:app:install name --force + +If desired, you can change the namespace: + + module Sinatra + class App < Thor + namespace :myapp + # tasks + end + end + +And then your tasks hould be invoked as: + + thor myapp:install name --force + +Invocations +----------- + +Thor comes with a invocation-dependency system as well which allows a task to be +invoked only once. For example: + + class Counter < Thor + desc "one", "Prints 1, 2, 3" + def one + puts 1 + invoke :two + invoke :three + end + + desc "two", "Prints 2, 3" + def two + puts 2 + invoke :three + end + + desc "three", "Prints 3" + def three + puts 3 + end + end + +When invoking the task one: + + thor counter:one + +The output is "1 2 3", which means that the three task was invoked only once. +You can even invoke tasks from another class, so be sure to check the +documentation. + +Thor::Group +----------- + +Thor has a special class called Thor::Group. The main difference to Thor class +is that it invokes all tasks at once. The example above could be rewritten in +Thor::Group as this: + + class Counter < Thor::Group + desc "Prints 1, 2, 3" + + def one + puts 1 + end + + def two + puts 2 + end + + def three + puts 3 + end + end + +When invoked: + + thor counter + +It prints "1 2 3" as well. Notice you should described (desc) only the class +and not each task anymore. Thor::Group is a great tool to create generators, +since you can define several steps which are invoked in the order they are +defined (Thor::Group is the tool use in generators in Rails 3.0). + +Besides, Thor::Group can parse arguments and options as Thor tasks: + + class Counter < Thor::Group + # number will be available as attr_accessor + argument :number, :type => :numeric, :desc => "The number to start counting" + desc "Prints the 'number' given upto 'number+2'" + + def one + puts number + 0 + end + + def two + puts number + 1 + end + + def three + puts number + 2 + end + end + +The counter above expects one parameter and has the folling outputs: + + thor counter 5 + # Prints "5 6 7" + + thor counter 11 + # Prints "11 12 13" + +You can also give options to Thor::Group, but instead of using `method_option` and +`method_options`, you should use `class_option` and `class_options`. Both argument +and class_options methods are available to Thor class as well. + +Actions +------- + +Thor comes with several actions which helps with script and generator tasks. You +might be familiar with them since some came from Rails Templates. They are: `say`, +`ask`, `yes?`, `no?`, `add_file`, `remove_file`, `copy_file`, `template`, +`directory`, `inside`, `run`, `inject_into_file` and a couple more. + +To use them, you just need to include Thor::Actions in your Thor classes: + + class App < Thor + include Thor::Actions + # tasks + end + +Some actions like copy file requires that a class method called source_root is +defined in your class. This is the directory where your templates should be +placed. Be sure to check the documentation. + +License +------- + +See MIT LICENSE. diff --git a/railties/lib/vendor/thor-0.11.2/bin/rake2thor b/railties/lib/vendor/thor-0.11.2/bin/rake2thor new file mode 100755 index 0000000000..50c7410d80 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/bin/rake2thor @@ -0,0 +1,87 @@ +#!/usr/bin/env ruby + +require 'rubygems' +require 'ruby2ruby' +require 'parse_tree' +if Ruby2Ruby::VERSION >= "1.2.0" + require 'parse_tree_extensions' +end +require 'rake' + +input = ARGV[0] || 'Rakefile' +output = ARGV[1] || 'Thorfile' + +$requires = [] + +module Kernel + def require_with_record(file) + $requires << file if caller[1] =~ /rake2thor:/ + require_without_record file + end + alias_method :require_without_record, :require + alias_method :require, :require_with_record +end + +load input + +@private_methods = [] + +def file_task_name(name) + "compile_" + name.gsub('/', '_slash_').gsub('.', '_dot_').gsub(/\W/, '_') +end + +def method_for_task(task) + file_task = task.is_a?(Rake::FileTask) + comment = task.instance_variable_get('@comment') + prereqs = task.instance_variable_get('@prerequisites').select(&Rake::Task.method(:task_defined?)) + actions = task.instance_variable_get('@actions') + name = task.name.gsub(/^([^:]+:)+/, '') + name = file_task_name(name) if file_task + meth = '' + + meth << "desc #{name.inspect}, #{comment.inspect}\n" if comment + meth << "def #{name}\n" + + meth << prereqs.map do |pre| + pre = pre.to_s + pre = file_task_name(pre) if Rake::Task[pre].is_a?(Rake::FileTask) + ' ' + pre + end.join("\n") + + meth << "\n\n" unless prereqs.empty? || actions.empty? + + meth << actions.map do |act| + act = act.to_ruby + unless act.gsub!(/^proc \{ \|(\w+)\|\n/, + " \\1 = Struct.new(:name).new(#{name.inspect}) # A crude mock Rake::Task object\n") + act.gsub!(/^proc \{\n/, '') + end + act.gsub(/\n\}$/, '') + end.join("\n") + + meth << "\nend" + + if file_task + @private_methods << meth + return + end + + meth +end + +body = Rake::Task.tasks.map(&method(:method_for_task)).compact.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n") + +unless @private_methods.empty? + body << "\n\n private\n\n" + body << @private_methods.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n") +end + +requires = $requires.map { |r| "require #{r.inspect}" }.join("\n") + +File.open(output, 'w') { |f| f.write(<:: name of the defaut task + # + def default_task(meth=nil) + case meth + when :none + @default_task = 'help' + when nil + @default_task ||= from_superclass(:default_task, 'help') + else + @default_task = meth.to_s + end + end + + # Defines the usage and the description of the next task. + # + # ==== Parameters + # usage + # description + # + def desc(usage, description, options={}) + if options[:for] + task = find_and_refresh_task(options[:for]) + task.usage = usage if usage + task.description = description if description + else + @usage, @desc = usage, description + end + end + + # Maps an input to a task. If you define: + # + # map "-T" => "list" + # + # Running: + # + # thor -T + # + # Will invoke the list task. + # + # ==== Parameters + # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given task. + # + def map(mappings=nil) + @map ||= from_superclass(:map, {}) + + if mappings + mappings.each do |key, value| + if key.respond_to?(:each) + key.each {|subkey| @map[subkey] = value} + else + @map[key] = value + end + end + end + + @map + end + + # Declares the options for the next task to be declared. + # + # ==== Parameters + # Hash[Symbol => Object]:: The hash key is the name of the option and the value + # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric + # or :required (string). If you give a value, the type of the value is used. + # + def method_options(options=nil) + @method_options ||= {} + build_options(options, @method_options) if options + @method_options + end + + # Adds an option to the set of class options. If :for is given as option, + # it allows you to change the options from a previous defined task. + # + # def previous_task + # # magic + # end + # + # method_options :foo => :bar, :for => :previous_task + # + # def next_task + # # magic + # end + # + # ==== Parameters + # name:: The name of the argument. + # options:: Described below. + # + # ==== Options + # :desc - Description for the argument. + # :required - If the argument is required or not. + # :default - Default value for this argument. It cannot be required and have default values. + # :aliases - Aliases for this option. + # :type - The type of the argument, can be :string, :hash, :array, :numeric, :boolean or :default. + # Default accepts arguments as booleans (--switch) or as strings (--switch=VALUE). + # :group - The group for this options. Use by class options to output options in different levels. + # :banner - String to show on usage notes. + # + def method_option(name, options={}) + scope = if options[:for] + find_and_refresh_task(options[:for]).options + else + method_options + end + + build_option(name, options, scope) + end + + # Parses the task and options from the given args, instantiate the class + # and invoke the task. This method is used when the arguments must be parsed + # from an array. If you are inside Ruby and want to use a Thor class, you + # can simply initialize it: + # + # script = MyScript.new(args, options, config) + # script.invoke(:task, first_arg, second_arg, third_arg) + # + def start(given_args=ARGV, config={}) + super do + meth = normalize_task_name(given_args.shift) + task = all_tasks[meth] + + if task + args, opts = Thor::Options.split(given_args) + config.merge!(:task_options => task.options) + else + args, opts = given_args, {} + end + + task ||= Task.dynamic(meth) + trailing = args[Range.new(arguments.size, -1)] + new(args, opts, config).invoke(task, trailing || []) + end + end + + # Prints help information. If a task name is given, it shows information + # only about the specific task. + # + # ==== Parameters + # meth:: An optional task name to print usage information about. + # + # ==== Options + # namespace:: When true, shows the namespace in the output before the usage. + # skip_inherited:: When true, does not show tasks from superclass. + # + def help(shell, meth=nil, options={}) + meth, options = nil, meth if meth.is_a?(Hash) + + if meth + task = all_tasks[meth] + raise UndefinedTaskError, "task '#{meth}' could not be found in namespace '#{self.namespace}'" unless task + + shell.say "Usage:" + shell.say " #{banner(task, options[:namespace])}" + shell.say + class_options_help(shell, "Class") + shell.say task.description + else + list = (options[:short] ? tasks : all_tasks).map do |_, task| + [ banner(task, options[:namespace]), task.short_description || '' ] + end + + if options[:short] + shell.print_table(list, :emphasize_last => true) + else + shell.say "Tasks:" + shell.print_table(list, :ident => 2, :emphasize_last => true) + shell.say + + class_options_help(shell, "Class") + end + end + end + + protected + + # The banner for this class. You can customize it if you are invoking the + # thor class by another means which is not the Thor::Runner. It receives + # the task that is going to be invoked and if the namespace should be + # displayed. + # + def banner(task, namespace=true) #:nodoc: + task.formatted_usage(self, namespace) + end + + def baseclass #:nodoc: + Thor + end + + def valid_task?(meth) #:nodoc: + @usage && @desc + end + + def create_task(meth) #:nodoc: + tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options) + @usage, @desc, @method_options = nil + end + + def initialize_added #:nodoc: + class_options.merge!(method_options) + @method_options = nil + end + + # Receives a task name (can be nil), and try to get a map from it. + # If a map can't be found use the sent name or the default task. + # + def normalize_task_name(meth) #:nodoc: + mapping = map[meth.to_s] + meth = mapping || meth || default_task + meth.to_s.gsub('-','_') # treat foo-bar > foo_bar + end + end + + include Thor::Base + + map HELP_MAPPINGS => :help + + desc "help [TASK]", "Describe available tasks or one specific task" + def help(task=nil) + self.class.help(shell, task, :namespace => task && task.include?(?:)) + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/actions.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/actions.rb new file mode 100644 index 0000000000..f7b271dbe1 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/actions.rb @@ -0,0 +1,240 @@ +require 'fileutils' + +Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action| + require action +end + +class Thor + module Actions + attr_accessor :behavior + + # On inclusion, add some options to base. + # + def self.included(base) #:nodoc: + base.extend ClassMethods + 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 + + module ClassMethods + # Hold source paths for one Thor instance. source_paths_for_search is the + # method responsible to gather source_paths from this current class, + # inherited paths and the source root. + # + def source_paths + @source_paths ||= [] + end + + # Returns the source paths in the following order: + # + # 1) This class source paths + # 2) Source root + # 3) Parents source paths + # + def source_paths_for_search + @source_paths_for_search ||= begin + paths = [] + paths += self.source_paths + paths << self.source_root if self.respond_to?(:source_root) + paths += from_superclass(:source_paths, []) + paths + end + end + end + + # Extends initializer to add more configuration options. + # + # ==== Configuration + # behavior:: The actions default behavior. Can be :invoke or :revoke. + # It also accepts :force, :skip and :pretend to set the behavior + # and the respective option. + # + # destination_root:: The root directory needed for some actions. It's also known + # as destination root. + # + 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 + + # Wraps an action object and call it accordingly to the thor class behavior. + # + def action(instance) + if behavior == :revoke + instance.revoke! + else + instance.invoke! + end + end + + # Returns the root for this thor class (also aliased as destination root). + # + 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. + # + def destination_root=(root) + @destination_stack ||= [] + @destination_stack[0] = File.expand_path(root || '') + end + + # Returns the given path relative to the absolute root (ie, root where + # the script started). + # + def relative_to_original_destination_root(path, remove_dot=true) + path = path.gsub(@destination_stack[0], '.') + remove_dot ? (path[2..-1] || '') : path + end + + # Receives a file or directory and search for it in the source paths. + # + def find_in_source_paths(file) + relative_root = relative_to_original_destination_root(destination_root, false) + paths = self.class.source_paths_for_search + + 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 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 + + # 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. + # + 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 + + # Goes to the root and execute the given block. + # + def in_root + inside(@destination_stack.first) { yield } + end + + # Executes a command. + # + # ==== Parameters + # command:: the command to be executed. + # config:: give :verbose => false to not log the status. + # + # ==== Example + # + # inside('vendor') do + # run('ln -s ~/edge rails') + # end + # + def run(command, config={}) + return unless behavior == :invoke + say_status :run, command, config.fetch(:verbose, true) + `#{command}` unless options[:pretend] + end + + # 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. + # + def run_ruby_script(command, config={}) + return unless behavior == :invoke + say_status File.basename(Thor::Util.ruby_command), command, config.fetch(:verbose, true) + `#{Thor::Util.ruby_command} #{command}` unless options[:pretend] + end + + # 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 + # + 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 + + say_status :thor, command, verbose + run "thor #{command}", :verbose => false + end + + protected + + # Allow current root to be shared between invocations. + # + def _shared_configuration #:nodoc: + super.merge!(:destination_root => self.destination_root) + end + + def _cleanup_options_and_set(options, key) #:nodoc: + case options + when Array + %w(--force -f --skip -s).each { |i| options.delete(i) } + options << "--#{key}" + when Hash + [:force, :skip, "force", "skip"].each { |i| options.delete(i) } + options.merge!(key => true) + end + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/actions/create_file.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/create_file.rb new file mode 100644 index 0000000000..8f6badee27 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/create_file.rb @@ -0,0 +1,102 @@ +require 'thor/actions/empty_directory' + +class Thor + module Actions + + # 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" + # + def create_file(destination, data=nil, config={}, &block) + action CreateFile.new(self, destination, block || data.to_s, config) + end + alias :add_file :create_file + + # AddFile is a subset of Template, which instead of rendering a file with + # ERB, it gets the content from the user. + # + class CreateFile < EmptyDirectory #:nodoc: + attr_reader :data + + def initialize(base, destination, data, config={}) + @data = data + super(base, destination, config) + end + + # Checks if the content of the file at the destination is identical to the rendered result. + # + # ==== Returns + # Boolean:: true if it is identical, false otherwise. + # + def identical? + exists? && File.read(destination) == render + end + + # Holds the content to be added to the file. + # + def render + @render ||= if data.is_a?(Proc) + data.call + else + data + end + end + + def invoke! + invoke_with_conflict_check do + FileUtils.mkdir_p(File.dirname(destination)) + File.open(destination, 'w'){ |f| f.write render } + end + end + + protected + + # Now on conflict we check if the file is identical or not. + # + def on_conflict_behavior(&block) + if identical? + say_status :identical, :blue + else + options = base.options.merge(config) + force_or_skip_or_conflict(options[:force], options[:skip], &block) + end + end + + # If force is true, run the action, otherwise check if it's not being + # skipped. If both are false, show the file_collision menu, if the menu + # returns true, force it, otherwise skip. + # + def force_or_skip_or_conflict(force, skip, &block) + if force + say_status :force, :yellow + block.call unless pretend? + elsif skip + say_status :skip, :yellow + else + say_status :conflict, :red + force_or_skip_or_conflict(force_on_collision?, true, &block) + end + end + + # Shows the file collision menu to the user and gets the result. + # + def force_on_collision? + base.shell.file_collision(destination){ render } + end + + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/actions/directory.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/directory.rb new file mode 100644 index 0000000000..e33639f4e5 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/directory.rb @@ -0,0 +1,87 @@ +require 'thor/actions/empty_directory' + +class Thor + module Actions + + # 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:: 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 + # + def directory(source, destination=nil, config={}) + action Directory.new(self, source, destination || source, config) + end + + class Directory < EmptyDirectory #:nodoc: + attr_reader :source + + def initialize(base, source, destination=nil, config={}) + @source = File.expand_path(base.find_in_source_paths(source.to_s)) + super(base, destination, { :recursive => true }.merge(config)) + end + + def invoke! + base.empty_directory given_destination, config + execute! + end + + def revoke! + execute! + end + + protected + + def execute! + lookup = config[:recursive] ? File.join(source, '**') : source + lookup = File.join(lookup, '{*,.[a-z]*}') + + Dir[lookup].each do |file_source| + next if File.directory?(file_source) + file_destination = File.join(given_destination, file_source.gsub(source, '.')) + + case file_source + when /\.empty_directory$/ + base.empty_directory(File.dirname(file_destination), config) + when /\.tt$/ + base.template(file_source, file_destination[0..-4], config) + else + base.copy_file(file_source, file_destination, config) + end + end + end + + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/actions/empty_directory.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/empty_directory.rb new file mode 100644 index 0000000000..03c1fe4af1 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/empty_directory.rb @@ -0,0 +1,133 @@ +class Thor + module Actions + + # 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" + # + def empty_directory(destination, config={}) + action EmptyDirectory.new(self, destination, config) + end + + # Class which holds create directory logic. This is the base class for + # other actions like create_file and directory. + # + # This implementation is based in Templater actions, created by Jonas Nicklas + # and Michael S. Klishin under MIT LICENSE. + # + class EmptyDirectory #:nodoc: + attr_reader :base, :destination, :given_destination, :relative_destination, :config + + # Initializes given the source and destination. + # + # ==== Parameters + # base:: A Thor::Base instance + # source:: Relative path to the source of this file + # destination:: Relative path to the destination of this file + # config:: give :verbose => false to not log the status. + # + def initialize(base, destination, config={}) + @base, @config = base, { :verbose => true }.merge(config) + self.destination = destination + end + + # Checks if the destination file already exists. + # + # ==== Returns + # Boolean:: true if the file exists, false otherwise. + # + def exists? + ::File.exists?(destination) + end + + def invoke! + invoke_with_conflict_check do + ::FileUtils.mkdir_p(destination) + end + end + + def revoke! + say_status :remove, :red + ::FileUtils.rm_rf(destination) if !pretend? && exists? + end + + protected + + # Shortcut for pretend. + # + def pretend? + base.options[:pretend] + end + + # Sets the absolute destination value from a relative destination value. + # It also stores the given and relative destination. Let's suppose our + # script is being executed on "dest", it sets the destination root to + # "dest". The destination, given_destination and relative_destination + # are related in the following way: + # + # inside "bar" do + # empty_directory "baz" + # end + # + # destination #=> dest/bar/baz + # relative_destination #=> bar/baz + # given_destination #=> baz + # + def destination=(destination) + if destination + @given_destination = convert_encoded_instructions(destination.to_s) + @destination = ::File.expand_path(@given_destination, base.destination_root) + @relative_destination = base.relative_to_original_destination_root(@destination) + end + end + + # Filenames in the encoded form are converted. If you have a file: + # + # %class_name%.rb + # + # It gets the class name from the base and replace it: + # + # user.rb + # + def convert_encoded_instructions(filename) + filename.gsub(/%(.*?)%/) do |string| + instruction = $1.strip + base.respond_to?(instruction) ? base.send(instruction) : string + end + end + + # Receives a hash of options and just execute the block if some + # conditions are met. + # + def invoke_with_conflict_check(&block) + if exists? + on_conflict_behavior(&block) + else + say_status :create, :green + block.call unless pretend? + end + + destination + end + + # What to do when the destination file already exists. + # + def on_conflict_behavior(&block) + say_status :exist, :blue + end + + # Shortcut to say_status shell method. + # + def say_status(status, color) + base.shell.say_status status, relative_destination, color if config[:verbose] + end + + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/actions/file_manipulation.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/file_manipulation.rb new file mode 100644 index 0000000000..5a39840404 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/file_manipulation.rb @@ -0,0 +1,194 @@ +require 'erb' +require 'open-uri' + +class Thor + module Actions + + # 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" + # + def copy_file(source, destination=nil, config={}) + destination ||= source + source = File.expand_path(find_in_source_paths(source.to_s)) + + create_file destination, nil, config do + File.read(source) + end + 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. + # + # ==== 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 + # + 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 + + # 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" + # + def template(source, destination=nil, config={}) + destination ||= source + source = File.expand_path(find_in_source_paths(source.to_s)) + context = instance_eval('binding') + + create_file destination, nil, config do + ERB.new(::File.read(source), nil, '-').result(context) + end + end + + # 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 + # + 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 + + # Prepend text to a file. + # + # ==== 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"' + # + def prepend_file(path, data=nil, config={}, &block) + return unless behavior == :invoke + path = File.expand_path(path, destination_root) + say_status :prepend, relative_to_original_destination_root(path), config.fetch(:verbose, true) + + unless options[:pretend] + content = data || block.call + content << File.read(path) + File.open(path, 'wb') { |file| file.write(content) } + end + end + + # Append text to a file. + # + # ==== 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"' + # + def append_file(path, data=nil, config={}, &block) + return unless behavior == :invoke + path = File.expand_path(path, destination_root) + say_status :append, relative_to_original_destination_root(path), config.fetch(:verbose, true) + File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend] + end + + # 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 + # + 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 + + # 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' + # + 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 + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/actions/inject_into_file.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/inject_into_file.rb new file mode 100644 index 0000000000..089bd894e4 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/actions/inject_into_file.rb @@ -0,0 +1,78 @@ +require 'thor/actions/empty_directory' + +class Thor + module Actions + + # 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:: 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 + # + def inject_into_file(destination, *args, &block) + if block_given? + data, config = block, args.shift + else + data, config = args.shift, args.shift + end + + log_status = args.empty? || args.pop + action InjectIntoFile.new(self, destination, data, config) + end + + class InjectIntoFile < EmptyDirectory + attr_reader :flag, :replacement + + def initialize(base, destination, data, config) + super(base, destination, { :verbose => true }.merge(config)) + + data = data.call if data.is_a?(Proc) + + @replacement = if @config.key?(:after) + @flag = @config.delete(:after) + @flag + data + else + @flag = @config.delete(:before) + data + @flag + end + end + + def invoke! + say_status :inject, config[:verbose] + replace!(flag, replacement) + end + + def revoke! + say_status :deinject, config[:verbose] + replace!(replacement, flag) + end + + protected + + # Adds the content to the file. + # + def replace!(regexp, string) + unless base.options[:pretend] + content = File.read(destination) + content.gsub!(regexp, string) + File.open(destination, 'wb') { |file| file.write(content) } + end + end + + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/base.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/base.rb new file mode 100644 index 0000000000..caf298dda8 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/base.rb @@ -0,0 +1,515 @@ +require 'thor/core_ext/hash_with_indifferent_access' +require 'thor/core_ext/ordered_hash' +require 'thor/error' +require 'thor/shell' +require 'thor/invocation' +require 'thor/parser' +require 'thor/task' +require 'thor/util' + +class Thor + HELP_MAPPINGS = %w(-h -? --help -D) + THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root) + + module Base + attr_accessor :options + + # It receives arguments in an Array and two hashes, one for options and + # other for configuration. + # + # Notice that it does not check if all required arguments were supplied. + # It should be done by the parser. + # + # ==== Parameters + # args:: An array of objects. The objects are applied to their + # respective accessors declared with argument. + # + # options:: An options hash that will be available as self.options. + # The hash given is converted to a hash with indifferent + # access, magic predicates (options.skip?) and then frozen. + # + # config:: Configuration for this Thor class. + # + def initialize(args=[], options={}, config={}) + Thor::Arguments.parse(self.class.arguments, args).each do |key, value| + send("#{key}=", value) + end + + parse_options = self.class.class_options + + if options.is_a?(Array) + task_options = config.delete(:task_options) # hook for start + parse_options = parse_options.merge(task_options) if task_options + array_options, hash_options = options, {} + else + array_options, hash_options = [], options + end + + options = Thor::Options.parse(parse_options, array_options) + self.options = Thor::CoreExt::HashWithIndifferentAccess.new(options).merge!(hash_options) + self.options.freeze + end + + class << self + def included(base) #:nodoc: + base.send :extend, ClassMethods + base.send :include, Invocation + base.send :include, Shell + end + + # Returns the classes that inherits from Thor or Thor::Group. + # + # ==== Returns + # Array[Class] + # + def subclasses + @subclasses ||= [] + end + + # Returns the files where the subclasses are kept. + # + # ==== Returns + # Hash[path => Class] + # + def subclass_files + @subclass_files ||= Hash.new{ |h,k| h[k] = [] } + end + + # Whenever a class inherits from Thor or Thor::Group, we should track the + # class and the file on Thor::Base. This is the method responsable for it. + # Also adds the source root to the source paths if the klass respond to it. + # + def register_klass_file(klass) #:nodoc: + file = caller[1].match(/(.*):\d+/)[1] + Thor::Base.subclasses << klass unless Thor::Base.subclasses.include?(klass) + + file_subclasses = Thor::Base.subclass_files[File.expand_path(file)] + file_subclasses << klass unless file_subclasses.include?(klass) + end + end + + module ClassMethods + # Adds an argument to the class and creates an attr_accessor for it. + # + # Arguments are different from options in several aspects. The first one + # is how they are parsed from the command line, arguments are retrieved + # from position: + # + # thor task NAME + # + # Instead of: + # + # thor task --name=NAME + # + # Besides, arguments are used inside your code as an accessor (self.argument), + # while options are all kept in a hash (self.options). + # + # Finally, arguments cannot have type :default or :boolean but can be + # optional (supplying :optional => :true or :required => false), although + # you cannot have a required argument after a non-required argument. If you + # try it, an error is raised. + # + # ==== Parameters + # name:: The name of the argument. + # options:: Described below. + # + # ==== Options + # :desc - Description for the argument. + # :required - If the argument is required or not. + # :optional - If the argument is optional or not. + # :type - The type of the argument, can be :string, :hash, :array, :numeric. + # :default - Default value for this argument. It cannot be required and have default values. + # :banner - String to show on usage notes. + # + # ==== Errors + # ArgumentError:: Raised if you supply a required argument after a non required one. + # + def argument(name, options={}) + is_thor_reserved_word?(name, :argument) + no_tasks { attr_accessor name } + + required = if options.key?(:optional) + !options[:optional] + elsif options.key?(:required) + options[:required] + else + options[:default].nil? + end + + remove_argument name + + arguments.each do |argument| + next if argument.required? + raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " << + "the non-required argument #{argument.human_name.inspect}." + end if required + + arguments << Thor::Argument.new(name, options[:desc], required, options[:type], + options[:default], options[:banner]) + end + + # Returns this class arguments, looking up in the ancestors chain. + # + # ==== Returns + # Array[Thor::Argument] + # + def arguments + @arguments ||= from_superclass(:arguments, []) + end + + # Adds a bunch of options to the set of class options. + # + # class_options :foo => false, :bar => :required, :baz => :string + # + # If you prefer more detailed declaration, check class_option. + # + # ==== Parameters + # Hash[Symbol => Object] + # + def class_options(options=nil) + @class_options ||= from_superclass(:class_options, {}) + build_options(options, @class_options) if options + @class_options + end + + # Adds an option to the set of class options + # + # ==== Parameters + # name:: The name of the argument. + # options:: Described below. + # + # ==== Options + # :desc - Description for the argument. + # :required - If the argument is required or not. + # :default - Default value for this argument. + # :group - The group for this options. Use by class options to output options in different levels. + # :aliases - Aliases for this option. + # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. + # :banner - String to show on usage notes. + # + def class_option(name, options={}) + build_option(name, options, class_options) + end + + # Removes a previous defined argument. If :undefine is given, undefine + # accessors as well. + # + # ==== Paremeters + # names:: Arguments to be removed + # + # ==== Examples + # + # remove_argument :foo + # remove_argument :foo, :bar, :baz, :undefine => true + # + def remove_argument(*names) + options = names.last.is_a?(Hash) ? names.pop : {} + + names.each do |name| + arguments.delete_if { |a| a.name == name.to_s } + undef_method name, "#{name}=" if options[:undefine] + end + end + + # Removes a previous defined class option. + # + # ==== Paremeters + # names:: Class options to be removed + # + # ==== Examples + # + # remove_class_option :foo + # remove_class_option :foo, :bar, :baz + # + def remove_class_option(*names) + names.each do |name| + class_options.delete(name) + end + end + + # Defines the group. This is used when thor list is invoked so you can specify + # that only tasks from a pre-defined group will be shown. Defaults to standard. + # + # ==== Parameters + # name + # + def group(name=nil) + case name + when nil + @group ||= from_superclass(:group, 'standard') + else + @group = name.to_s + end + end + + # Returns the tasks for this Thor class. + # + # ==== Returns + # OrderedHash:: An ordered hash with this class tasks. + # + def tasks + @tasks ||= Thor::CoreExt::OrderedHash.new + end + + # Returns the tasks for this Thor class and all subclasses. + # + # ==== Returns + # OrderedHash + # + def all_tasks + @all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new) + @all_tasks.merge(tasks) + end + + # Removes a given task from this Thor class. This is usually done if you + # are inheriting from another class and don't want it to be available + # anymore. + # + # By default it only remove the mapping to the task. But you can supply + # :undefine => true to undefine the method from the class as well. + # + # ==== Parameters + # name:: The name of the task to be removed + # options:: You can give :undefine => true if you want tasks the method + # to be undefined from the class as well. + # + def remove_task(*names) + options = names.last.is_a?(Hash) ? names.pop : {} + + names.each do |name| + tasks.delete(name.to_s) + all_tasks.delete(name.to_s) + undef_method name if options[:undefine] + end + end + + # All methods defined inside the given block are not added as tasks. + # + # So you can do: + # + # class MyScript < Thor + # no_tasks do + # def this_is_not_a_task + # end + # end + # end + # + # You can also add the method and remove it from the task list: + # + # class MyScript < Thor + # def this_is_not_a_task + # end + # remove_task :this_is_not_a_task + # end + # + def no_tasks + @no_tasks = true + yield + @no_tasks = false + end + + # Sets the namespace for the Thor or Thor::Group class. By default the + # namespace is retrieved from the class name. If your Thor class is named + # Scripts::MyScript, the help method, for example, will be called as: + # + # thor scripts:my_script -h + # + # If you change the namespace: + # + # namespace :my_scripts + # + # You change how your tasks are invoked: + # + # thor my_scripts -h + # + # Finally, if you change your namespace to default: + # + # namespace :default + # + # Your tasks can be invoked with a shortcut. Instead of: + # + # thor :my_task + # + def namespace(name=nil) + case name + when nil + @namespace ||= Thor::Util.constant_to_namespace(self, false) + else + @namespace = name.to_s + end + end + + # Default way to start generators from the command line. + # + def start(given_args=ARGV, config={}) #:nodoc: + config[:shell] ||= Thor::Base.shell.new + yield + rescue Thor::Error => e + if given_args.include?("--debug") + raise e + else + config[:shell].error e.message + end + end + + protected + + # Prints the class options per group. If an option does not belong to + # any group, it uses the ungrouped name value. This method provide to + # hooks to add extra options, one of them if the third argument called + # extra_group that should be a hash in the format :group => Array[Options]. + # + # The second is by returning a lamda used to print values. The lambda + # requires two options: the group name and the array of options. + # + def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc: + groups = {} + + class_options.each do |_, value| + groups[value.group] ||= [] + groups[value.group] << value + end + + printer = proc do |group_name, options| + list = [] + padding = options.collect{ |o| o.aliases.size }.max.to_i * 4 + + options.each do |option| + list << [ option.usage(padding), option.description || "" ] + list << [ "", "Default: #{option.default}" ] if option.show_default? + end + + unless list.empty? + if group_name + shell.say "#{group_name} options:" + else + shell.say "Options:" + end + + shell.print_table(list, :emphasize_last => true, :ident => 2) + shell.say "" + end + end + + # Deal with default group + global_options = groups.delete(nil) || [] + printer.call(ungrouped_name, global_options) if global_options + + # Print all others + groups = extra_group.merge(groups) if extra_group + groups.each(&printer) + printer + end + + # Raises an error if the word given is a Thor reserved word. + # + def is_thor_reserved_word?(word, type) + return false unless THOR_RESERVED_WORDS.include?(word.to_s) + raise "'#{word}' is a Thor reserved word and cannot be defined as #{type}" + end + + # Build an option and adds it to the given scope. + # + # ==== Parameters + # name:: The name of the argument. + # options:: Described in both class_option and method_option. + # + def build_option(name, options, scope) + scope[name] = Thor::Option.new(name, options[:desc], options[:required], + options[:type], options[:default], options[:banner], + options[:group], options[:aliases]) + end + + # Receives a hash of options, parse them and add to the scope. This is a + # fast way to set a bunch of options: + # + # build_options :foo => true, :bar => :required, :baz => :string + # + # ==== Parameters + # Hash[Symbol => Object] + # + def build_options(options, scope) + options.each do |key, value| + scope[key] = Thor::Option.parse(key, value) + end + end + + # Finds a task with the given name. If the task belongs to the current + # class, just return it, otherwise dup it and add the fresh copy to the + # current task hash. + # + def find_and_refresh_task(name) + task = if task = tasks[name.to_s] + task + elsif task = all_tasks[name.to_s] + tasks[name.to_s] = task.clone + else + raise ArgumentError, "You supplied :for => #{name.inspect}, but the task #{name.inspect} could not be found." + end + end + + # Everytime someone inherits from a Thor class, register the klass + # and file into baseclass. + # + def inherited(klass) + Thor::Base.register_klass_file(klass) + end + + # Fire this callback whenever a method is added. Added methods are + # tracked as tasks if the requirements set by valid_task? are valid. + # + def method_added(meth) + meth = meth.to_s + + if meth == "initialize" + initialize_added + return + end + + # Return if it's not a public instance method + return unless public_instance_methods.include?(meth) || + public_instance_methods.include?(meth.to_sym) + + # Return if @no_tasks is enabled or it's not a valid task + return if @no_tasks || !valid_task?(meth) + + is_thor_reserved_word?(meth, :task) + Thor::Base.register_klass_file(self) + create_task(meth) + end + + # Retrieves a value from superclass. If it reaches the baseclass, + # returns nil. + # + def from_superclass(method, default=nil) + if self == baseclass || !superclass.respond_to?(method, true) + default + else + value = superclass.send(method) + value.dup if value + end + end + + # SIGNATURE: Sets the baseclass. This is where the superclass lookup + # finishes. + def baseclass #:nodoc: + end + + # SIGNATURE: Defines if a given method is a valid_task?. This method is + # called before a new method is added to the class. + def valid_task?(meth) #:nodoc: + true # unless otherwise given + end + + # SIGNATURE: Creates a new task if valid_task? is true. This method is + # called when a new method is added to the class. + def create_task(meth) #:nodoc: + end + + # SIGNATURE: Defines behavior when the initialize method is added to the + # class. + def initialize_added #:nodoc: + end + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/hash_with_indifferent_access.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/hash_with_indifferent_access.rb new file mode 100644 index 0000000000..3213961fe4 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/hash_with_indifferent_access.rb @@ -0,0 +1,75 @@ +class Thor + module CoreExt + + # A hash with indifferent access and magic predicates. + # + # hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true + # + # hash[:foo] #=> 'bar' + # hash['foo'] #=> 'bar' + # hash.foo? #=> true + # + class HashWithIndifferentAccess < ::Hash + + def initialize(hash={}) + super() + hash.each do |key, value| + self[convert_key(key)] = value + end + end + + def [](key) + super(convert_key(key)) + end + + def []=(key, value) + super(convert_key(key), value) + end + + def delete(key) + super(convert_key(key)) + end + + def values_at(*indices) + indices.collect { |key| self[convert_key(key)] } + end + + def merge(other) + dup.merge!(other) + end + + def merge!(other) + other.each do |key, value| + self[convert_key(key)] = value + end + self + end + + protected + + def convert_key(key) + key.is_a?(Symbol) ? key.to_s : key + end + + # Magic predicates. For instance: + # + # options.force? # => !!options['force'] + # options.shebang # => "/usr/lib/local/ruby" + # options.test_framework?(:rspec) # => options[:test_framework] == :rspec + # + def method_missing(method, *args, &block) + method = method.to_s + if method =~ /^(\w+)\?$/ + if args.empty? + !!self[$1] + else + self[$1] == args.first + end + else + self[method] + end + end + + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/ordered_hash.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/ordered_hash.rb new file mode 100644 index 0000000000..5e4ad5609f --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/core_ext/ordered_hash.rb @@ -0,0 +1,102 @@ +require 'forwardable' + +class Thor #:nodoc: + module CoreExt #:nodoc: + + if RUBY_VERSION >= '1.9' + class OrderedHash < ::Hash + end + else + # This class is based on the Ruby 1.9 ordered hashes. + # + # It keeps the semantics and most of the efficiency of normal hashes + # while also keeping track of the order in which elements were set. + # + class OrderedHash #:nodoc: + include Enumerable + + Node = Struct.new(:key, :value, :next, :prev) + + def initialize + @hash = {} + end + + def [](key) + @hash[key] && @hash[key].value + end + + def []=(key, value) + if node = @hash[key] + node.value = value + else + node = Node.new(key, value) + + if @first.nil? + @first = @last = node + else + node.prev = @last + @last.next = node + @last = node + end + end + + @hash[key] = node + value + end + + def delete(key) + if node = @hash[key] + prev_node = node.prev + next_node = node.next + + next_node.prev = prev_node if next_node + prev_node.next = next_node if prev_node + + @first = next_node if @first == node + @last = prev_node if @last == node + + value = node.value + end + + @hash.delete(key) + value + end + + def keys + self.map { |k, v| k } + end + + def values + self.map { |k, v| v } + end + + def each + return unless @first + yield [@first.key, @first.value] + node = @first + yield [node.key, node.value] while node = node.next + self + end + + def merge(other) + hash = self.class.new + + self.each do |key, value| + hash[key] = value + end + + other.each do |key, value| + hash[key] = value + end + + hash + end + + def empty? + @hash.empty? + end + end + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/error.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/error.rb new file mode 100644 index 0000000000..c846e9ce74 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/error.rb @@ -0,0 +1,27 @@ +class Thor + # Thor::Error is raised when it's caused by the user invoking the task and + # only errors that inherit from it are rescued. + # + # So, for example, if the developer declares a required argument after an + # option, it should raise an ::ArgumentError and not ::Thor::ArgumentError, + # because it was caused by the developer and not the "final user". + # + class Error < StandardError #:nodoc: + end + + # Raised when a task was not found. + # + class UndefinedTaskError < Error #:nodoc: + end + + # Raised when a task was found, but not invoked properly. + # + class InvocationError < Error #:nodoc: + end + + class RequiredArgumentMissingError < InvocationError #:nodoc: + end + + class MalformattedArgumentError < InvocationError #:nodoc: + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/group.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/group.rb new file mode 100644 index 0000000000..ef1476a694 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/group.rb @@ -0,0 +1,262 @@ +# Thor has a special class called Thor::Group. The main difference to Thor class +# is that it invokes all tasks at once. It also include some methods that allows +# invocations to be done at the class method, which are not available to Thor +# tasks. +# +class Thor::Group + class << self + # The descrition for this Thor::Group. If none is provided, but a source root + # exists, tries to find the USAGE one folder above it, otherwise searches + # in the superclass. + # + # ==== Parameters + # description:: The description for this Thor::Group. + # + def desc(description=nil) + case description + when nil + @desc ||= from_superclass(:desc, nil) + else + @desc = description + end + end + + # Start works differently in Thor::Group, it simply invokes all tasks + # inside the class. + # + def start(given_args=ARGV, config={}) + super do + if Thor::HELP_MAPPINGS.include?(given_args.first) + help(config[:shell]) + return + end + + args, opts = Thor::Options.split(given_args) + new(args, opts, config).invoke + end + end + + # Prints help information. + # + # ==== Options + # short:: When true, shows only usage. + # + def help(shell, options={}) + if options[:short] + shell.say banner + else + shell.say "Usage:" + shell.say " #{banner}" + shell.say + class_options_help(shell) + shell.say self.desc if self.desc + end + end + + # Stores invocations for this class merging with superclass values. + # + def invocations #:nodoc: + @invocations ||= from_superclass(:invocations, {}) + end + + # Stores invocation blocks used on invoke_from_option. + # + def invocation_blocks #:nodoc: + @invocation_blocks ||= from_superclass(:invocation_blocks, {}) + end + + # Invoke the given namespace or class given. It adds an instance + # method that will invoke the klass and task. You can give a block to + # configure how it will be invoked. + # + # The namespace/class given will have its options showed on the help + # usage. Check invoke_from_option for more information. + # + def invoke(*names, &block) + options = names.last.is_a?(Hash) ? names.pop : {} + verbose = options.fetch(:verbose, :white) + + names.each do |name| + invocations[name] = false + invocation_blocks[name] = block if block_given? + + class_eval <<-METHOD, __FILE__, __LINE__ + def _invoke_#{name.to_s.gsub(/\W/, '_')} + klass, task = self.class.prepare_for_invocation(nil, #{name.inspect}) + + if klass + say_status :invoke, #{name.inspect}, #{verbose.inspect} + block = self.class.invocation_blocks[#{name.inspect}] + _invoke_for_class_method klass, task, &block + else + say_status :error, %(#{name.inspect} [not found]), :red + end + end + METHOD + end + end + + # Invoke a thor class based on the value supplied by the user to the + # given option named "name". A class option must be created before this + # method is invoked for each name given. + # + # ==== Examples + # + # class GemGenerator < Thor::Group + # class_option :test_framework, :type => :string + # invoke_from_option :test_framework + # end + # + # ==== Boolean options + # + # In some cases, you want to invoke a thor class if some option is true or + # false. This is automatically handled by invoke_from_option. Then the + # option name is used to invoke the generator. + # + # ==== Preparing for invocation + # + # In some cases you want to customize how a specified hook is going to be + # invoked. You can do that by overwriting the class method + # prepare_for_invocation. The class method must necessarily return a klass + # and an optional task. + # + # ==== Custom invocations + # + # You can also supply a block to customize how the option is giong to be + # invoked. The block receives two parameters, an instance of the current + # class and the klass to be invoked. + # + def invoke_from_option(*names, &block) + options = names.last.is_a?(Hash) ? names.pop : {} + verbose = options.fetch(:verbose, :white) + + names.each do |name| + unless class_options.key?(name) + raise ArgumentError, "You have to define the option #{name.inspect} " << + "before setting invoke_from_option." + end + + invocations[name] = true + invocation_blocks[name] = block if block_given? + + class_eval <<-METHOD, __FILE__, __LINE__ + def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')} + return unless options[#{name.inspect}] + + value = options[#{name.inspect}] + value = #{name.inspect} if TrueClass === value + klass, task = self.class.prepare_for_invocation(#{name.inspect}, value) + + if klass + say_status :invoke, value, #{verbose.inspect} + block = self.class.invocation_blocks[#{name.inspect}] + _invoke_for_class_method klass, task, &block + else + say_status :error, %(\#{value} [not found]), :red + end + end + METHOD + end + end + + # Remove a previously added invocation. + # + # ==== Examples + # + # remove_invocation :test_framework + # + def remove_invocation(*names) + names.each do |name| + remove_task(name) + remove_class_option(name) + invocations.delete(name) + invocation_blocks.delete(name) + end + end + + # Overwrite class options help to allow invoked generators options to be + # shown recursively when invoking a generator. + # + def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc: + group_options = {} + + get_options_from_invocations(group_options, class_options) do |klass| + klass.send(:get_options_from_invocations, group_options, class_options) + end + + group_options.merge!(extra_group) if extra_group + super(shell, ungrouped_name, group_options) + end + + # Get invocations array and merge options from invocations. Those + # options are added to group_options hash. Options that already exists + # in base_options are not added twice. + # + def get_options_from_invocations(group_options, base_options) #:nodoc: + invocations.each do |name, from_option| + value = if from_option + option = class_options[name] + option.type == :boolean ? name : option.default + else + name + end + next unless value + + klass, task = prepare_for_invocation(name, value) + next unless klass && klass.respond_to?(:class_options) + + value = value.to_s + human_name = value.respond_to?(:classify) ? value.classify : value + + group_options[human_name] ||= [] + group_options[human_name] += klass.class_options.values.select do |option| + base_options[option.name.to_sym].nil? && option.group.nil? && + !group_options.values.flatten.any? { |i| i.name == option.name } + end + + yield klass if block_given? + end + end + + protected + + # The banner for this class. You can customize it if you are invoking the + # thor class by another means which is not the Thor::Runner. + # + def banner #:nodoc: + "#{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}" + end + + def baseclass #:nodoc: + Thor::Group + end + + def create_task(meth) #:nodoc: + tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil) + end + end + + include Thor::Base + + protected + + # Shortcut to invoke with padding and block handling. Use internally by + # invoke and invoke_from_option class methods. + # + def _invoke_for_class_method(klass, task=nil, *args, &block) + shell.padding += 1 + + result = if block_given? + if block.arity == 2 + block.call(self, klass) + else + block.call(self, klass, task) + end + else + invoke klass, task, *args + end + + shell.padding -= 1 + result + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/invocation.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/invocation.rb new file mode 100644 index 0000000000..34e7a4b911 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/invocation.rb @@ -0,0 +1,172 @@ +class Thor + module Invocation + def self.included(base) #:nodoc: + base.extend ClassMethods + end + + module ClassMethods + # Prepare for class methods invocations. This method must return a klass to + # have the invoked class options showed in help messages in generators. + # + def prepare_for_invocation(key, name) #:nodoc: + case name + when Symbol, String + Thor::Util.namespace_to_thor_class(name.to_s, false) + else + name + end + end + end + + # Make initializer aware of invocations and the initializer proc. + # + def initialize(args=[], options={}, config={}, &block) #:nodoc: + @_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] } + @_initializer = [ args, options, config ] + super + end + + # Receives a name and invokes it. The name can be a string (either "task" or + # "namespace:task"), a Thor::Task, a Class or a Thor instance. If the task + # cannot be guessed by name, it can also be supplied as second argument. + # + # You can also supply the arguments, options and configuration values for + # the task to be invoked, if none is given, the same values used to + # initialize the invoker are used to initialize the invoked. + # + # ==== Examples + # + # class A < Thor + # def foo + # invoke :bar + # invoke "b:hello", ["José"] + # end + # + # def bar + # invoke "b:hello", ["José"] + # end + # end + # + # class B < Thor + # def hello(name) + # puts "hello #{name}" + # end + # end + # + # You can notice that the method "foo" above invokes two tasks: "bar", + # which belongs to the same class and "hello" which belongs to the class B. + # + # By using an invocation system you ensure that a task is invoked only once. + # In the example above, invoking "foo" will invoke "b:hello" just once, even + # if it's invoked later by "bar" method. + # + # When class A invokes class B, all arguments used on A initialization are + # supplied to B. This allows lazy parse of options. Let's suppose you have + # some rspec tasks: + # + # class Rspec < Thor::Group + # class_option :mock_framework, :type => :string, :default => :rr + # + # def invoke_mock_framework + # invoke "rspec:#{options[:mock_framework]}" + # end + # end + # + # As you noticed, it invokes the given mock framework, which might have its + # own options: + # + # class Rspec::RR < Thor::Group + # class_option :style, :type => :string, :default => :mock + # end + # + # Since it's not rspec concern to parse mock framework options, when RR + # is invoked all options are parsed again, so RR can extract only the options + # that it's going to use. + # + # If you want Rspec::RR to be initialized with its own set of options, you + # have to do that explicitely: + # + # invoke "rspec:rr", [], :style => :foo + # + # Besides giving an instance, you can also give a class to invoke: + # + # invoke Rspec::RR, [], :style => :foo + # + def invoke(name=nil, task=nil, args=nil, opts=nil, config=nil) + task, args, opts, config = nil, task, args, opts if task.nil? || task.is_a?(Array) + args, opts, config = nil, args, opts if args.is_a?(Hash) + + object, task = _prepare_for_invocation(name, task) + if object.is_a?(Class) + klass = object + + stored_args, stored_opts, stored_config = @_initializer + args ||= stored_args.dup + opts ||= stored_opts.dup + + config ||= {} + config = stored_config.merge(_shared_configuration).merge!(config) + instance = klass.new(args, opts, config) + else + klass, instance = object.class, object + end + + method_args = [] + current = @_invocations[klass] + + iterator = proc do |_, task| + unless current.include?(task.name) + current << task.name + task.run(instance, method_args) + end + end + + if task + args ||= [] + method_args = args[Range.new(klass.arguments.size, -1)] || [] + iterator.call(nil, task) + else + klass.all_tasks.map(&iterator) + end + end + + protected + + # Configuration values that are shared between invocations. + # + def _shared_configuration + { :invocations => @_invocations } + end + + # Prepare for invocation in the instance level. In this case, we have to + # take into account that a just a task name from the current class was + # given or even a Thor::Task object. + # + def _prepare_for_invocation(name, sent_task=nil) #:nodoc: + if name.is_a?(Thor::Task) + task = name + elsif task = self.class.all_tasks[name.to_s] + object = self + else + object, task = self.class.prepare_for_invocation(nil, name) + task ||= sent_task + end + + # If the object was not set, use self and use the name as task. + object, task = self, name unless object + return object, _validate_klass_and_task(object, task) + end + + # Check if the object given is a Thor class object and get a task object + # for it. + # + def _validate_klass_and_task(object, task) #:nodoc: + klass = object.is_a?(Class) ? object : object.class + raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base + + task ||= klass.default_task if klass <= Thor + task = klass.all_tasks[task.to_s] || Task.dynamic(task) if task && !task.is_a?(Thor::Task) + task + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/parser.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/parser.rb new file mode 100644 index 0000000000..57a3f6e1a5 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/parser.rb @@ -0,0 +1,4 @@ +require 'thor/parser/argument' +require 'thor/parser/arguments' +require 'thor/parser/option' +require 'thor/parser/options' diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/parser/argument.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/argument.rb new file mode 100644 index 0000000000..2d7f4dbafb --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/argument.rb @@ -0,0 +1,67 @@ +class Thor + class Argument + VALID_TYPES = [ :numeric, :hash, :array, :string ] + + attr_reader :name, :description, :required, :type, :default, :banner + alias :human_name :name + + def initialize(name, description=nil, required=true, type=:string, default=nil, banner=nil) + class_name = self.class.name.split("::").last + + raise ArgumentError, "#{class_name} name can't be nil." if name.nil? + raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) + + @name = name.to_s + @description = description + @required = required || false + @type = (type || :string).to_sym + @default = default + @banner = banner || default_banner + + validate! # Trigger specific validations + end + + def usage + required? ? banner : "[#{banner}]" + end + + def required? + required + end + + def show_default? + case default + when Array, String, Hash + !default.empty? + else + default + end + end + + protected + + def validate! + raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? + end + + def valid_type?(type) + VALID_TYPES.include?(type.to_sym) + end + + def default_banner + case type + when :boolean + nil + when :string, :default + human_name.upcase + when :numeric + "N" + when :hash + "key:value" + when :array + "one two three" + end + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/parser/arguments.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/arguments.rb new file mode 100644 index 0000000000..9a2262d6f7 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/arguments.rb @@ -0,0 +1,145 @@ +class Thor + class Arguments + NUMERIC = /(\d*\.\d+|\d+)/ + + # Receives an array of args and returns two arrays, one with arguments + # and one with switches. + # + def self.split(args) + arguments = [] + + args.each do |item| + break if item =~ /^-/ + arguments << item + end + + return arguments, args[Range.new(arguments.size, -1)] + end + + def self.parse(base, args) + new(base).parse(args) + end + + # Takes an array of Thor::Argument objects. + # + def initialize(arguments=[]) + @assigns, @non_assigned_required = {}, [] + @switches = arguments + + arguments.each do |argument| + if argument.default + @assigns[argument.human_name] = argument.default + elsif argument.required? + @non_assigned_required << argument + end + end + end + + def parse(args) + @pile = args.dup + + @switches.each do |argument| + break unless peek + @non_assigned_required.delete(argument) + @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name) + end + + check_requirement! + @assigns + end + + private + + def peek + @pile.first + end + + def shift + @pile.shift + end + + def unshift(arg) + unless arg.kind_of?(Array) + @pile.unshift(arg) + else + @pile = arg + @pile + end + end + + def current_is_value? + peek && peek.to_s !~ /^-/ + end + + # Runs through the argument array getting strings that contains ":" and + # mark it as a hash: + # + # [ "name:string", "age:integer" ] + # + # Becomes: + # + # { "name" => "string", "age" => "integer" } + # + def parse_hash(name) + return shift if peek.is_a?(Hash) + hash = {} + + while current_is_value? && peek.include?(?:) + key, value = shift.split(':') + hash[key] = value + end + hash + end + + # Runs through the argument array getting all strings until no string is + # found or a switch is found. + # + # ["a", "b", "c"] + # + # And returns it as an array: + # + # ["a", "b", "c"] + # + def parse_array(name) + return shift if peek.is_a?(Array) + array = [] + + while current_is_value? + array << shift + end + array + end + + # Check if the peel is numeric ofrmat and return a Float or Integer. + # Otherwise raises an error. + # + def parse_numeric(name) + return shift if peek.is_a?(Numeric) + + unless peek =~ NUMERIC && $& == peek + raise MalformattedArgumentError, "expected numeric value for '#{name}'; got #{peek.inspect}" + end + + $&.index('.') ? shift.to_f : shift.to_i + end + + # Parse string, i.e., just return the current value in the pile. + # + def parse_string(name) + shift + end + + # Raises an error if @non_assigned_required array is not empty. + # + def check_requirement! + unless @non_assigned_required.empty? + names = @non_assigned_required.map do |o| + o.respond_to?(:switch_name) ? o.switch_name : o.human_name + end.join("', '") + + class_name = self.class.name.split('::').last.downcase + raise RequiredArgumentMissingError, "no value provided for required #{class_name} '#{names}'" + end + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/parser/option.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/option.rb new file mode 100644 index 0000000000..5c43f6b18f --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/option.rb @@ -0,0 +1,132 @@ +class Thor + class Option < Argument + attr_reader :aliases, :group + + VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] + + def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, group=nil, aliases=nil) + super(name, description, required, type, default, banner) + @aliases = [*aliases].compact + @group = group.to_s.capitalize if group + end + + # This parse quick options given as method_options. It makes several + # assumptions, but you can be more specific using the option method. + # + # parse :foo => "bar" + # #=> Option foo with default value bar + # + # parse [:foo, :baz] => "bar" + # #=> Option foo with default value bar and alias :baz + # + # parse :foo => :required + # #=> Required option foo without default value + # + # parse :foo => 2 + # #=> Option foo with default value 2 and type numeric + # + # parse :foo => :numeric + # #=> Option foo without default value and type numeric + # + # parse :foo => true + # #=> Option foo with default value true and type boolean + # + # The valid types are :boolean, :numeric, :hash, :array and :string. If none + # is given a default type is assumed. This default type accepts arguments as + # string (--foo=value) or booleans (just --foo). + # + # By default all options are optional, unless :required is given. + # + def self.parse(key, value) + if key.is_a?(Array) + name, *aliases = key + else + name, aliases = key, [] + end + + name = name.to_s + default = value + + type = case value + when Symbol + default = nil + + if VALID_TYPES.include?(value) + value + elsif required = (value == :required) + :string + elsif value == :optional + # TODO Remove this warning in the future. + warn "Optional type is deprecated. Choose :boolean or :string instead. Assumed to be :boolean." + :boolean + end + when TrueClass, FalseClass + :boolean + when Numeric + :numeric + when Hash, Array, String + value.class.name.downcase.to_sym + end + + self.new(name.to_s, nil, required, type, default, nil, nil, aliases) + end + + def switch_name + @switch_name ||= dasherized? ? name : dasherize(name) + end + + def human_name + @human_name ||= dasherized? ? undasherize(name) : name + end + + def usage(padding=0) + sample = if banner && !banner.to_s.empty? + "#{switch_name}=#{banner}" + else + switch_name + end + + sample = "[#{sample}]" unless required? + + if aliases.empty? + (" " * padding) << sample + else + "#{aliases.join(', ')}, #{sample}" + end + end + + # Allow some type predicates as: boolean?, string? and etc. + # + def method_missing(method, *args, &block) + given = method.to_s.sub(/\?$/, '').to_sym + if valid_type?(given) + self.type == given + else + super + end + end + + protected + + def validate! + raise ArgumentError, "An option cannot be boolean and required." if boolean? && required? + end + + def valid_type?(type) + VALID_TYPES.include?(type.to_sym) + end + + def dasherized? + name.index('-') == 0 + end + + def undasherize(str) + str.sub(/^-{1,2}/, '') + end + + def dasherize(str) + (str.length > 1 ? "--" : "-") + str.gsub('_', '-') + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/parser/options.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/options.rb new file mode 100644 index 0000000000..01c86b7b27 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/parser/options.rb @@ -0,0 +1,142 @@ +class Thor + # This is a modified version of Daniel Berger's Getopt::Long class, licensed + # under Ruby's license. + # + class Options < Arguments + LONG_RE = /^(--\w+[-\w+]*)$/ + SHORT_RE = /^(-[a-z])$/i + EQ_RE = /^(--\w+[-\w+]*|-[a-z])=(.*)$/i + SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args + SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i + + # Receives a hash and makes it switches. + # + def self.to_switches(options) + options.map do |key, value| + case value + when true + "--#{key}" + when Array + "--#{key} #{value.map{ |v| v.inspect }.join(' ')}" + when Hash + "--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}" + when nil, false + "" + else + "--#{key} #{value.inspect}" + end + end.join(" ") + end + + # Takes a hash of Thor::Option objects. + # + def initialize(options={}) + options = options.values + super(options) + @shorts, @switches = {}, {} + + options.each do |option| + @switches[option.switch_name] = option + + option.aliases.each do |short| + @shorts[short.to_s] ||= option.switch_name + end + end + end + + def parse(args) + @pile = args.dup + + while peek + if current_is_switch? + case shift + when SHORT_SQ_RE + unshift($1.split('').map { |f| "-#{f}" }) + next + when EQ_RE, SHORT_NUM + unshift($2) + switch = $1 + when LONG_RE, SHORT_RE + switch = $1 + end + + switch = normalize_switch(switch) + next unless option = switch_option(switch) + + @assigns[option.human_name] = parse_peek(switch, option) + else + shift + end + end + + check_requirement! + @assigns + end + + protected + + # Returns true if the current value in peek is a registered switch. + # + def current_is_switch? + case peek + when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM + switch?($1) + when SHORT_SQ_RE + $1.split('').any? { |f| switch?("-#{f}") } + end + end + + def switch?(arg) + switch_option(arg) || @shorts.key?(arg) + end + + def switch_option(arg) + if match = no_or_skip?(arg) + @switches[arg] || @switches["--#{match}"] + else + @switches[arg] + end + end + + def no_or_skip?(arg) + arg =~ /^--(no|skip)-([-\w]+)$/ + $2 + end + + # Check if the given argument is actually a shortcut. + # + def normalize_switch(arg) + @shorts.key?(arg) ? @shorts[arg] : arg + end + + # Parse boolean values which can be given as --foo=true, --foo or --no-foo. + # + def parse_boolean(switch) + if current_is_value? + ["true", "TRUE", "t", "T", true].include?(shift) + else + @switches.key?(switch) || !no_or_skip?(switch) + end + end + + # Parse the value at the peek analyzing if it requires an input or not. + # + def parse_peek(switch, option) + unless current_is_value? + if option.boolean? + # No problem for boolean types + elsif no_or_skip?(switch) + return nil # User set value to nil + elsif option.string? && !option.required? + return option.human_name # Return the option name + else + raise MalformattedArgumentError, "no value provided for option '#{switch}'" + end + end + + @non_assigned_required.delete(option) + send(:"parse_#{option.type}", switch) + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/runner.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/runner.rb new file mode 100644 index 0000000000..330de38449 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/runner.rb @@ -0,0 +1,295 @@ +require 'fileutils' +require 'open-uri' +require 'yaml' +require 'digest/md5' +require 'pathname' + +class Thor::Runner < Thor + map "-T" => :list, "-i" => :install, "-u" => :update + + # Override Thor#help so it can give information about any class and any method. + # + def help(meth=nil) + if meth && !self.respond_to?(meth) + initialize_thorfiles(meth) + klass, task = Thor::Util.namespace_to_thor_class(meth) + klass.start(["-h", task].compact, :shell => self.shell) # send mapping -h because it works with Thor::Group too + else + super + end + end + + # If a task is not found on Thor::Runner, method missing is invoked and + # Thor::Runner is then responsable for finding the task in all classes. + # + def method_missing(meth, *args) + meth = meth.to_s + initialize_thorfiles(meth) + klass, task = Thor::Util.namespace_to_thor_class(meth) + args.unshift(task) if task + klass.start(args, :shell => shell) + end + + desc "install NAME", "Install a Thor file into your system tasks, optionally named for future updates" + method_options :as => :string, :relative => :boolean + def install(name) + initialize_thorfiles + + # If a directory name is provided as the argument, look for a 'main.thor' + # task in said directory. + begin + if File.directory?(File.expand_path(name)) + base, package = File.join(name, "main.thor"), :directory + contents = open(base).read + else + base, package = name, :file + contents = open(name).read + end + rescue OpenURI::HTTPError + raise Error, "Error opening URI '#{name}'" + rescue Errno::ENOENT + raise Error, "Error opening file '#{name}'" + end + + say "Your Thorfile contains:" + say contents + + return false if no?("Do you wish to continue [y/N]?") + + as = options["as"] || begin + first_line = contents.split("\n")[0] + (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil + end + + unless as + basename = File.basename(name) + as = ask("Please specify a name for #{name} in the system repository [#{basename}]:") + as = basename if as.empty? + end + + location = if options[:relative] || name =~ /^http:\/\// + name + else + File.expand_path(name) + end + + thor_yaml[as] = { + :filename => Digest::MD5.hexdigest(name + as), + :location => location, + :namespaces => Thor::Util.namespaces_in_contents(contents, base) + } + + save_yaml(thor_yaml) + say "Storing thor file in your system repository" + destination = File.join(thor_root, thor_yaml[as][:filename]) + + if package == :file + File.open(destination, "w") { |f| f.puts contents } + else + FileUtils.cp_r(name, destination) + end + + thor_yaml[as][:filename] # Indicate success + end + + desc "uninstall NAME", "Uninstall a named Thor module" + def uninstall(name) + raise Error, "Can't find module '#{name}'" unless thor_yaml[name] + say "Uninstalling #{name}." + FileUtils.rm_rf(File.join(thor_root, "#{thor_yaml[name][:filename]}")) + + thor_yaml.delete(name) + save_yaml(thor_yaml) + + puts "Done." + end + + desc "update NAME", "Update a Thor file from its original location" + def update(name) + raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location] + + say "Updating '#{name}' from #{thor_yaml[name][:location]}" + + old_filename = thor_yaml[name][:filename] + self.options = self.options.merge("as" => name) + filename = install(thor_yaml[name][:location]) + + unless filename == old_filename + File.delete(File.join(thor_root, old_filename)) + end + end + + desc "installed", "List the installed Thor modules and tasks" + method_options :internal => :boolean + def installed + initialize_thorfiles(nil, true) + + klasses = Thor::Base.subclasses + klasses -= [Thor, Thor::Runner] unless options["internal"] + + display_klasses(true, klasses) + end + + desc "list [SEARCH]", + "List the available thor tasks (--substring means SEARCH anywhere in the namespace)" + method_options :substring => :boolean, :group => :string, :all => :boolean + def list(search="") + initialize_thorfiles + + search = ".*#{search}" if options["substring"] + search = /^#{search}.*/i + group = options[:group] || "standard" + + klasses = Thor::Base.subclasses.select do |k| + (options[:all] || k.group == group) && k.namespace =~ search + end + + display_klasses(false, klasses) + end + + private + + def thor_root + Thor::Util.thor_root + end + + def thor_yaml + @thor_yaml ||= begin + yaml_file = File.join(thor_root, "thor.yml") + yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file) + yaml || {} + end + end + + # Save the yaml file. If none exists in thor root, creates one. + # + def save_yaml(yaml) + yaml_file = File.join(thor_root, "thor.yml") + + unless File.exists?(yaml_file) + FileUtils.mkdir_p(thor_root) + yaml_file = File.join(thor_root, "thor.yml") + FileUtils.touch(yaml_file) + end + + File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml } + end + + # Load the thorfiles. If relevant_to is supplied, looks for specific files + # in the thor_root instead of loading them all. + # + # By default, it also traverses the current path until find Thor files, as + # described in thorfiles. This look up can be skipped by suppliying + # skip_lookup true. + # + def initialize_thorfiles(relevant_to=nil, skip_lookup=false) + thorfiles(relevant_to, skip_lookup).each do |f| + Thor::Util.load_thorfile(f) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f)) + end + end + + # Finds Thorfiles by traversing from your current directory down to the root + # directory of your system. If at any time we find a Thor file, we stop. + # + # We also ensure that system-wide Thorfiles are loaded first, so local + # Thorfiles can override them. + # + # ==== Example + # + # If we start at /Users/wycats/dev/thor ... + # + # 1. /Users/wycats/dev/thor + # 2. /Users/wycats/dev + # 3. /Users/wycats <-- we find a Thorfile here, so we stop + # + # Suppose we start at c:\Documents and Settings\james\dev\thor ... + # + # 1. c:\Documents and Settings\james\dev\thor + # 2. c:\Documents and Settings\james\dev + # 3. c:\Documents and Settings\james + # 4. c:\Documents and Settings + # 5. c:\ <-- no Thorfiles found! + # + def thorfiles(relevant_to=nil, skip_lookup=false) + # Deal with deprecated thor when :namespaces: is available as constants + save_yaml(thor_yaml) if Thor::Util.convert_constants_to_namespaces(thor_yaml) + + thorfiles = [] + + unless skip_lookup + Pathname.pwd.ascend do |path| + thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten + break unless thorfiles.empty? + end + end + + files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob) + files += thorfiles + files -= ["#{thor_root}/thor.yml"] + + files.map! do |file| + File.directory?(file) ? File.join(file, "main.thor") : file + end + end + + # Load thorfiles relevant to the given method. If you provide "foo:bar" it + # will load all thor files in the thor.yaml that has "foo" e "foo:bar" + # namespaces registered. + # + def thorfiles_relevant_to(meth) + lookup = [ meth, meth.split(":")[0...-1].join(":") ] + + files = thor_yaml.select do |k, v| + v[:namespaces] && !(v[:namespaces] & lookup).empty? + end + + files.map { |k, v| File.join(thor_root, "#{v[:filename]}") } + end + + # Display information about the given klasses. If with_module is given, + # it shows a table with information extracted from the yaml file. + # + def display_klasses(with_modules=false, klasses=Thor.subclasses) + klasses -= [Thor, Thor::Runner] unless with_modules + raise Error, "No Thor tasks available" if klasses.empty? + + if with_modules && !thor_yaml.empty? + info = [] + labels = ["Modules", "Namespaces"] + + info << labels + info << [ "-" * labels[0].size, "-" * labels[1].size ] + + thor_yaml.each do |name, hash| + info << [ name, hash[:namespaces].join(", ") ] + end + + print_table info + say "" + end + + unless klasses.empty? + klasses.each { |k| display_tasks(k) } + else + say "\033[1;34mNo Thor tasks available\033[0m" + end + end + + # Display tasks from the given Thor class. + # + def display_tasks(klass) + unless klass.tasks.empty? + base = klass.namespace + + if base == "default" + say "\033[1;35m#{base}\033[0m" + else + say "\033[1;34m#{base}\033[0m" + end + say "-" * base.length + + klass.help(shell, :short => true, :namespace => true) + say + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/shell.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/shell.rb new file mode 100644 index 0000000000..7ed4a24bfb --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/shell.rb @@ -0,0 +1,72 @@ +require 'thor/shell/color' + +class Thor + module Base + # Returns the shell used in all Thor classes. Default to color one. + # + def self.shell + @shell ||= Thor::Shell::Color + end + + # Sets the shell used in all Thor classes. + # + def self.shell=(klass) + @shell = klass + end + end + + module Shell + SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_list, :print_table] + + # Add shell to initialize config values. + # + # ==== Configuration + # shell:: An instance of the shell to be used. + # + # ==== Examples + # + # class MyScript < Thor + # argument :first, :type => :numeric + # end + # + # MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new + # + def initialize(args=[], options={}, config={}) + super + self.shell = config[:shell] + self.shell.base ||= self if self.shell.respond_to?(:base) + end + + # Holds the shell for the given Thor instance. If no shell is given, + # it gets a default shell from Thor::Base.shell. + # + def shell + @shell ||= Thor::Base.shell.new + end + + # Sets the shell for this thor class. + # + def shell=(shell) + @shell = shell + end + + # Common methods that are delegated to the shell. + # + SHELL_DELEGATED_METHODS.each do |method| + module_eval <<-METHOD, __FILE__, __LINE__ + def #{method}(*args) + shell.#{method}(*args) + end + METHOD + end + + protected + + # Allow shell to be shared between invocations. + # + def _shared_configuration + super.merge!(:shell => self.shell) + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/shell/basic.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/shell/basic.rb new file mode 100644 index 0000000000..6f1a2ade07 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/shell/basic.rb @@ -0,0 +1,221 @@ +require 'tempfile' + +class Thor + module Shell + class Basic + attr_accessor :base, :padding + + # Initialize base and padding to nil. + # + def initialize #:nodoc: + @base, @padding = nil, 0 + end + + # Do not allow padding to be less than zero. + # + def padding=(value) #:nodoc: + @padding = [0, value].max + end + + # Ask something to the user and receives a response. + # + # ==== Example + # ask("What is your name?") + # + def ask(statement, color=nil) + say("#{statement} ", color) + $stdin.gets.strip + end + + # Say (print) something to the user. If the sentence ends with a whitespace + # or tab character, a new line is not appended (print + flush). Otherwise + # are passed straight to puts (behavior got from Highline). + # + # ==== Example + # say("I know you knew that.") + # + def say(message="", color=nil, force_new_line=false) + message = message.to_s + new_line = force_new_line || !(message[-1, 1] == " " || message[-1, 1] == "\t") + message = set_color(message, color) if color + + if new_line + $stdout.puts(message) + else + $stdout.print(message) + $stdout.flush + end + end + + # Say a status with the given color and appends the message. Since this + # method is used frequently by actions, it allows nil or false to be given + # in log_status, avoiding the message from being shown. If a Symbol is + # given in log_status, it's used as the color. + # + def say_status(status, message, log_status=true) #:nodoc: + return if quiet? || log_status == false + spaces = " " * (padding + 1) + color = log_status.is_a?(Symbol) ? log_status : :green + + status = status.to_s.rjust(12) + status = set_color status, color, true if color + say "#{status}#{spaces}#{message}", nil, true + end + + # Make a question the to user and returns true if the user replies "y" or + # "yes". + # + def yes?(statement, color=nil) + ask(statement, color) =~ is?(:yes) + end + + # Make a question the to user and returns true if the user replies "n" or + # "no". + # + def no?(statement, color=nil) + !yes?(statement, color) + end + + # Prints a list of items. + # + # ==== Parameters + # list + # mode:: Can be :rows or :inline. Defaults to :rows. + # + def print_list(list, mode=:rows) + return if list.empty? + + content = case mode + when :inline + last = list.pop + "#{list.join(", ")}, and #{last}" + else # rows + list.join("\n") + end + + $stdout.puts content + end + + # Prints a table. + # + # ==== Parameters + # Array[Array[String, String, ...]] + # + # ==== Options + # ident:: Ident the first column by ident value. + # emphasize_last:: When true, add a different behavior to the last column. + # + def print_table(table, options={}) + return if table.empty? + + formats = [] + 0.upto(table.first.length - 2) do |i| + maxima = table.max{ |a,b| a[i].size <=> b[i].size }[i].size + formats << "%-#{maxima + 2}s" + end + + formats[0] = formats[0].insert(0, " " * options[:ident]) if options[:ident] + formats << "%s" + + if options[:emphasize_last] + table.each do |row| + next if row[-1].empty? + row[-1] = "# #{row[-1]}" + end + end + + table.each do |row| + row.each_with_index do |column, i| + $stdout.print formats[i] % column.to_s + end + $stdout.puts + end + end + + # Deals with file collision and returns true if the file should be + # overwriten and false otherwise. If a block is given, it uses the block + # response as the content for the diff. + # + # ==== Parameters + # destination:: the destination file to solve conflicts + # block:: an optional proc that returns the value to be used in diff + # + def file_collision(destination) + return true if @always_force + options = block_given? ? "[Ynaqdh]" : "[Ynaqh]" + + while true + answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}] + + case answer + when is?(:yes), is?(:force) + return true + when is?(:no), is?(:skip) + return false + when is?(:always) + return @always_force = true + when is?(:quit) + say 'Aborting...' + raise SystemExit + when is?(:diff) + show_diff(destination, yield) if block_given? + say 'Retrying...' + else + say file_collision_help + end + end + end + + # Called if something goes wrong during the execution. This is used by Thor + # internally and should not be used inside your scripts. If someone went + # wrong, you can always raise an exception. If you raise a Thor::Error, it + # will be rescued and wrapped in the method below. + # + def error(statement) #:nodoc: + $stderr.puts statement + end + + protected + + def set_color(string, color, bold=false) + string + end + + def is?(value) + value = value.to_s + + if value.size == 1 + /\A#{value}\z/i + else + /\A(#{value}|#{value[0,1]})\z/i + end + end + + def file_collision_help +< e + parse_argument_error(instance, e, caller) + rescue NoMethodError => e + parse_no_method_error(instance, e) + end + + # Returns the formatted usage. If a class is given, the class arguments are + # injected in the usage. + # + def formatted_usage(klass=nil, namespace=false) + formatted = '' + formatted << "#{klass.namespace.gsub(/^default/,'')}:" if klass && namespace + formatted << formatted_arguments(klass) + formatted << " #{formatted_options}" + formatted.strip! + formatted + end + + # Injects the class arguments into the task usage. + # + def formatted_arguments(klass) + if klass && !klass.arguments.empty? + usage.to_s.gsub(/^#{name}/) do |match| + match << " " << klass.arguments.map{ |a| a.usage }.join(' ') + end + else + usage.to_s + end + end + + # Returns the options usage for this task. + # + def formatted_options + @formatted_options ||= options.map{ |_, o| o.usage }.sort.join(" ") + end + + protected + + # Given a target, checks if this class name is not a private/protected method. + # + def public_method?(instance) + collection = instance.private_methods + instance.protected_methods + !(collection).include?(name.to_s) && !(collection).include?(name.to_sym) # For Ruby 1.9 + end + + # Clean everything that comes from the Thor gempath and remove the caller. + # + def sans_backtrace(backtrace, caller) + dirname = /^#{Regexp.escape(File.dirname(__FILE__))}/ + saned = backtrace.reject { |frame| frame =~ dirname } + saned -= caller + end + + def parse_argument_error(instance, e, caller) + backtrace = sans_backtrace(e.backtrace, caller) + + if backtrace.empty? && e.message =~ /wrong number of arguments/ + if instance.is_a?(Thor::Group) + raise e, "'#{name}' was called incorrectly. Are you sure it has arity equals to 0?" + else + raise InvocationError, "'#{name}' was called incorrectly. Call as " << + "'#{formatted_usage(instance.class, true)}'" + end + else + raise e + end + end + + def parse_no_method_error(instance, e) + if e.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ + raise UndefinedTaskError, "The #{instance.class.namespace} namespace " << + "doesn't have a '#{name}' task" + else + raise e + end + end + + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/tasks.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks.rb new file mode 100644 index 0000000000..d1a7b1c673 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks.rb @@ -0,0 +1,4 @@ +# This only loads all tasks inside tasks. +Dir[File.join(File.dirname(__FILE__), "tasks", "*.rb")].each do |task| + require task +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/install.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/install.rb new file mode 100644 index 0000000000..6b20ff1634 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/install.rb @@ -0,0 +1,35 @@ +class Thor + # Creates an install task. + # + # ==== Parameters + # spec + # + # ==== Options + # :dir - The directory where the package is hold before installation. Defaults to ./pkg. + # + def self.install_task(spec, options={}) + package_task(spec, options) + tasks['install'] = Thor::InstallTask.new(spec, options) + end + + class InstallTask < Task + attr_accessor :spec, :config + + def initialize(gemspec, config={}) + super(:install, "Install the gem", "install", {}) + @spec = gemspec + @config = { :dir => File.join(Dir.pwd, "pkg") }.merge(config) + end + + def run(instance, args=[]) + null, sudo, gem = RUBY_PLATFORM =~ /mswin|mingw/ ? ['NUL', '', 'gem.bat'] : + ['/dev/null', 'sudo', 'gem'] + + old_stderr, $stderr = $stderr.dup, File.open(null, "w") + instance.invoke(:package) + $stderr = old_stderr + + system %{#{sudo} #{Gem.ruby} -S #{gem} install #{config[:dir]}/#{spec.name}-#{spec.version} --no-rdoc --no-ri --no-update-sources} + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/package.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/package.rb new file mode 100644 index 0000000000..603d61b4ab --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/package.rb @@ -0,0 +1,31 @@ +require "fileutils" + +class Thor + # Creates a package task. + # + # ==== Parameters + # spec + # + # ==== Options + # :dir - The package directory. Defaults to ./pkg. + # + def self.package_task(spec, options={}) + tasks['package'] = Thor::PackageTask.new(spec, options) + end + + class PackageTask < Task + attr_accessor :spec, :config + + def initialize(gemspec, config={}) + super(:package, "Build a gem package", "package", {}) + @spec = gemspec + @config = {:dir => File.join(Dir.pwd, "pkg")}.merge(config) + end + + def run(instance, args=[]) + FileUtils.mkdir_p(config[:dir]) + Gem::Builder.new(spec).build + FileUtils.mv(spec.file_name, File.join(config[:dir], spec.file_name)) + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/spec.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/spec.rb new file mode 100644 index 0000000000..c7d00968e8 --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/tasks/spec.rb @@ -0,0 +1,70 @@ +require "fileutils" + +class Thor + # Creates a spec task. + # + # ==== Parameters + # files - Array of files to spec + # + # ==== Options + # :name - The name of the task. It can be rcov or spec. Spec is the default. + # :rcov - A hash with rcov specific options. + # :rcov_dir - Where rcov reports should be printed. + # :verbose - Sets the default value for verbose, although it can be specified + # also through the command line. + # + # All other options are added to rspec. + # + def self.spec_task(files, options={}) + name = (options.delete(:name) || 'spec').to_s + tasks[name] = Thor::SpecTask.new(name, files, options) + end + + class SpecTask < Task + attr_accessor :name, :files, :rcov_dir, :rcov_config, :spec_config + + def initialize(name, files, config={}) + options = { :verbose => Thor::Option.parse(:verbose, config.delete(:verbose) || false) } + super(name, "#{name.capitalize} task", name, options) + + @name = name + @files = files.map{ |f| %["#{f}"] }.join(" ") + @rcov_dir = config.delete(:rdoc_dir) || File.join(Dir.pwd, 'coverage') + @rcov_config = config.delete(:rcov) || {} + @spec_config = { :format => 'specdoc', :color => true }.merge(config) + end + + def run(instance, args=[]) + rcov_opts = Thor::Options.to_switches(rcov_config) + spec_opts = Thor::Options.to_switches(spec_config) + + require 'rbconfig' + cmd = RbConfig::CONFIG['ruby_install_name'] << " " + + if rcov? + FileUtils.rm_rf(rcov_dir) + cmd << "-S #{where('rcov')} -o #{rcov_dir} #{rcov_opts} " + end + + cmd << [where('spec'), rcov? ? " -- " : nil, files, spec_opts].join(" ") + + puts cmd if instance.options.verbose? + system(cmd) + exit($?.exitstatus) + end + + private + + def rcov? + name == "rcov" + end + + def where(file) + ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| + file_with_path = File.join(path, file) + next unless File.exist?(file_with_path) && File.executable?(file_with_path) + return File.expand_path(file_with_path) + end + end + end +end diff --git a/railties/lib/vendor/thor-0.11.2/lib/thor/util.rb b/railties/lib/vendor/thor-0.11.2/lib/thor/util.rb new file mode 100644 index 0000000000..26db24aadb --- /dev/null +++ b/railties/lib/vendor/thor-0.11.2/lib/thor/util.rb @@ -0,0 +1,229 @@ +require 'rbconfig' + +class Thor + module Sandbox; end + + # This module holds several utilities: + # + # 1) Methods to convert thor namespaces to constants and vice-versa. + # + # Thor::Utils.constant_to_namespace(Foo::Bar::Baz) #=> "foo:bar:baz" + # Thor::Utils.namespace_to_constant("foo:bar:baz") #=> Foo::Bar::Baz + # + # 2) Loading thor files and sandboxing: + # + # Thor::Utils.load_thorfile("~/.thor/foo") + # + module Util + + # Receives a namespace and search for it in the Thor::Base subclasses. + # + # ==== Parameters + # namespace:: The namespace to search for. + # + def self.find_by_namespace(namespace) + namespace = 'default' if namespace.empty? + + Thor::Base.subclasses.find do |klass| + klass.namespace == namespace + end + end + + # Receives a constant and converts it to a Thor namespace. Since Thor tasks + # can be added to a sandbox, this method is also responsable for removing + # the sandbox namespace. + # + # This method should not be used in general because it's used to deal with + # older versions of Thor. On current versions, if you need to get the + # namespace from a class, just call namespace on it. + # + # ==== Parameters + # constant:: The constant to be converted to the thor path. + # + # ==== Returns + # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz" + # + def self.constant_to_namespace(constant, remove_default=true) + constant = constant.to_s.gsub(/^Thor::Sandbox::/, "") + constant = snake_case(constant).squeeze(":") + constant.gsub!(/^default/, '') if remove_default + constant + end + + # Given the contents, evaluate it inside the sandbox and returns the thor + # classes defined in the sandbox. + # + # ==== Parameters + # contents + # + # ==== Returns + # Array[Object] + # + def self.namespaces_in_contents(contents, file=__FILE__) + old_constants = Thor::Base.subclasses.dup + Thor::Base.subclasses.clear + + load_thorfile(file, contents) + + new_constants = Thor::Base.subclasses.dup + Thor::Base.subclasses.replace(old_constants) + + new_constants.map!{ |c| c.namespace } + new_constants.compact! + new_constants + end + + # Receives a string and convert it to snake case. SnakeCase returns snake_case. + # + # ==== Parameters + # String + # + # ==== Returns + # String + # + def self.snake_case(str) + return str.downcase if str =~ /^[A-Z_]+$/ + str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/ + return $+.downcase + end + + # Receives a namespace and tries to retrieve a Thor or Thor::Group class + # from it. It first searches for a class using the all the given namespace, + # if it's not found, removes the highest entry and searches for the class + # again. If found, returns the highest entry as the class name. + # + # ==== Examples + # + # class Foo::Bar < Thor + # def baz + # end + # end + # + # class Baz::Foo < Thor::Group + # end + # + # Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default task + # Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil + # Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz" + # + # ==== Parameters + # namespace + # + # ==== Errors + # Thor::Error:: raised if the namespace cannot be found. + # + # Thor::Error:: raised if the namespace evals to a class which does not + # inherit from Thor or Thor::Group. + # + def self.namespace_to_thor_class(namespace, raise_if_nil=true) + klass, task_name = Thor::Util.find_by_namespace(namespace), nil + + if klass.nil? && namespace.include?(?:) + namespace = namespace.split(":") + task_name = namespace.pop + klass = Thor::Util.find_by_namespace(namespace.join(":")) + end + + raise Error, "could not find Thor class or task '#{namespace}'" if raise_if_nil && klass.nil? + + return klass, task_name + end + + # Receives a path and load the thor file in the path. The file is evaluated + # inside the sandbox to avoid namespacing conflicts. + # + def self.load_thorfile(path, content=nil) + content ||= File.read(path) + + begin + Thor::Sandbox.class_eval(content, path) + rescue Exception => e + $stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}" + end + end + + # Receives a yaml (hash) and updates all constants entries to namespace. + # This was added to deal with deprecated versions of Thor. + # + # TODO Deprecate this method in the future. + # + # ==== Returns + # TrueClass|FalseClass:: Returns true if any change to the yaml file was made. + # + def self.convert_constants_to_namespaces(yaml) + yaml_changed = false + + yaml.each do |k, v| + next unless v[:constants] && v[:namespaces].nil? + yaml_changed = true + yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.constant_to_namespace(c)} + end + + yaml_changed + end + + def self.user_home + @@user_home ||= if ENV["HOME"] + ENV["HOME"] + elsif ENV["USERPROFILE"] + ENV["USERPROFILE"] + elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"] + File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"]) + elsif ENV["APPDATA"] + ENV["APPDATA"] + else + begin + File.expand_path("~") + rescue + if File::ALT_SEPARATOR + "C:/" + else + "/" + end + end + end + end + + # Returns the root where thor files are located, dependending on the OS. + # + def self.thor_root + File.join(user_home, ".thor") + end + + # Returns the files in the thor root. On Windows thor_root will be something + # like this: + # + # C:\Documents and Settings\james\.thor + # + # If we don't #gsub the \ character, Dir.glob will fail. + # + def self.thor_root_glob + files = Dir["#{thor_root.gsub(/\\/, '/')}/*"] + + files.map! do |file| + File.directory?(file) ? File.join(file, "main.thor") : file + end + end + + # Where to look for Thor files. + # + def self.globs_for(path) + ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] + end + + # Return the path to the ruby interpreter taking into account multiple + # installations and windows extensions. + # + def self.ruby_command #:nodoc: + @ruby_command ||= begin + ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) + ruby << Config::CONFIG['EXEEXT'] + + # escape string in case path to ruby executable contain spaces. + ruby.sub!(/.*\s.*/m, '"\&"') + ruby + end + end + + end +end diff --git a/railties/lib/vendor/thor.rb b/railties/lib/vendor/thor.rb index 89201313cd..9919497c8f 100644 --- a/railties/lib/vendor/thor.rb +++ b/railties/lib/vendor/thor.rb @@ -1,9 +1,9 @@ begin # Prefer gems to the bundled libs. require 'rubygems' - gem 'thor', '>= 0.11.1' + gem 'thor', '>= 0.11.2' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/thor-0.11.1/lib" + $:.unshift "#{File.dirname(__FILE__)}/thor-0.11.2/lib" end require 'thor' diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 9a8d8075a1..aeddb21d1f 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -31,6 +31,19 @@ class ActionsTest < GeneratorsTestCase assert_match /cool padding/, content end + def test_apply_does_not_log_status_if_required + template = <<-TEMPLATE + say_status :cool, :padding + TEMPLATE + template.instance_eval "def read; self; end" + + generator.expects(:open).with("http://gist.github.com/103208.txt").returns(template) + content = action(:apply, "http://gist.github.com/103208.txt", :verbose => false) + + assert_match /cool padding/, content + assert_no_match /apply http/, content + end + def test_create_file_should_write_data_to_file_path action :create_file, 'lib/test_file.rb', 'heres test data' assert_file 'lib/test_file.rb', 'heres test data' -- cgit v1.2.3