Skip to content
Browse files

Start project

  • Loading branch information...
0 parents commit 1e6359072731d2ece00440fc3ad8b0f06d4df100 @njonsson committed Nov 28, 2011
Showing with 2,081 additions and 0 deletions.
  1. 0 .gemtest
  2. +6 −0 .gitignore
  3. +7 −0 .travis.yml
  4. +1 −0 .yardopts
  5. +18 −0 Gemfile
  6. +7 −0 History.markdown
  7. +10 −0 MIT-LICENSE.markdown
  8. +157 −0 README.markdown
  9. +49 −0 Rakefile
  10. +36 −0 cape.gemspec
  11. +43 −0 features/dsl/each_rake_task/with_defined_namespace_argument.feature
  12. +37 −0 features/dsl/each_rake_task/with_defined_task_argument.feature
  13. +31 −0 features/dsl/each_rake_task/with_undefined_argument.feature
  14. +81 −0 features/dsl/each_rake_task/without_arguments.feature
  15. +93 −0 features/dsl/mirror_rake_tasks/inside_capistrano_namespace/with_defined_namespace_argument.feature
  16. +66 −0 features/dsl/mirror_rake_tasks/inside_capistrano_namespace/with_defined_task_argument.feature
  17. +39 −0 features/dsl/mirror_rake_tasks/inside_capistrano_namespace/with_undefined_argument.feature
  18. +263 −0 features/dsl/mirror_rake_tasks/inside_capistrano_namespace/without_arguments.feature
  19. +85 −0 features/dsl/mirror_rake_tasks/with_defined_namespace_argument.feature
  20. +60 −0 features/dsl/mirror_rake_tasks/with_defined_task_argument.feature
  21. +35 −0 features/dsl/mirror_rake_tasks/with_undefined_argument.feature
  22. +243 −0 features/dsl/mirror_rake_tasks/without_arguments.feature
  23. +33 −0 features/step_definitions.rb
  24. +1 −0 features/support/env.rb
  25. +69 −0 features/task_invocation/nonparameterized.feature
  26. +70 −0 features/task_invocation/parameterized.feature
  27. +22 −0 lib/cape.rb
  28. +86 −0 lib/cape/capistrano.rb
  29. +10 −0 lib/cape/core_ext.rb
  30. +24 −0 lib/cape/core_ext/hash.rb
  31. +25 −0 lib/cape/core_ext/symbol.rb
  32. +81 −0 lib/cape/dsl.rb
  33. +60 −0 lib/cape/rake.rb
  34. +25 −0 lib/cape/strings.rb
  35. +6 −0 lib/cape/version.rb
  36. 0 spec/cape/capistrano_spec.rb
  37. +12 −0 spec/cape/core_ext/hash_spec.rb
  38. +7 −0 spec/cape/core_ext/symbol_spec.rb
  39. +128 −0 spec/cape/dsl_spec.rb
  40. 0 spec/cape/rake_spec.rb
  41. +44 −0 spec/cape/strings_spec.rb
  42. 0 spec/cape/task_spec.rb
  43. +6 −0 spec/cape/version_spec.rb
  44. +5 −0 spec/cape_spec.rb
0 .gemtest
No changes.
6 .gitignore
@@ -0,0 +1,6 @@
+.bundle
+.rvmrc
+.yardoc
+Gemfile.lock
+doc
+pkg
7 .travis.yml
@@ -0,0 +1,7 @@
+bundler_args: --without development
+rvm:
+ - 1.8.7
+ - 1.9.2
+ - 1.9.3
+ - ree
+script: "bundle exec rake test"
1 .yardopts
@@ -0,0 +1 @@
+--file MIT-LICENSE.markdown --file History.markdown --no-private --protected --title "Cape"
18 Gemfile
@@ -0,0 +1,18 @@
+source 'http://rubygems.org'
+
+gemspec
+
+gem 'jruby-openssl', :platforms => :jruby
+
+group :development do
+ gem 'ruby-debug', :platforms => :mri_18
+
+ # This is a dependency of ruby-debug. We're specifying it here because its
+ # v0.45 is incompatible with Ruby v1.8.7.
+ gem 'linecache', '<= 0.43', :platforms => :mri_18
+
+ gem 'ruby-debug19', :platforms => :mri_19
+
+ gem 'yard', :platforms => [:ruby, :mswin, :mingw]
+ gem 'rdiscount', :platforms => [:ruby, :mswin, :mingw]
+end
7 History.markdown
@@ -0,0 +1,7 @@
+Version history for the _Cape_ project
+======================================
+
+<a name="v1.0.0"></a>v1.0.0, Mon 11/28/2011
+-------------------------------------------
+
+(First release)
10 MIT-LICENSE.markdown
@@ -0,0 +1,10 @@
+The MIT License
+===============
+
+Source code for _Cape_ is Copyright © 2011 [Nils Jonsson](mailto:cape@nilsjonsson.com) and [contributors](http://github.com/njonsson/cape/contributors "Cape contributors at GitHub").
+
+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.
157 README.markdown
@@ -0,0 +1,157 @@
+ _____ __
+ / ___/___ / /_ __ _____ __ ______
+ / (_ // -_) __/ / // / _ | // / __/
+ \___/ \__/\__/ \_, /\___|_,_/_/
+ '-(+++++... /___/ ............ s++++++++.
+ .(++++++++++++( -+++~~~~~ 'N++++++++++= B++++++++s
+ '+++++++++++++++( DN=++++++< -NB+++++++++s Bz++++++++
+ +++++++++++++++++. 'NNN=++++++(-BNB+++++++++'BN========-
+ =B=+++++++++sDBBBBs<. +NNNN=+++++(<NNNBDBDBNNNNDBNNBBBBBBBz
+ 'NN+s+++++=BBBh=+((+sB=DNNNNNBBBNNDhNNNN' .. -BNs (z
+ sN+N+z+++sBs- .hNNNNBNh(-' NNNN. .NB- <Ns +BBBz
+ D+N+N+z=Bs. .~. 'NNNNNB~ DNNN .NN+ (Ns =B+~
+ BN+N+NNB+ ~NBD BNNNBN h' hNNN .Bs< <Ns =Dz~
+ BNNNN+ND +BhB DNNNBz 'N~ sNNN 'ND' hNs -(z-
+ NNNNNNB( sDDN hNNNB( +N~ +NNN ..-<hBNs ~=h-
+ NNNNNNB- sDBN 'DNNNN. DN~ <BNN 'NNhs(NNs =NN-
+ NNNNNNB' zNNN(+sDNNBNNNz .NB( ~BNN 'D NNs =Bh~
+ NNNNNNN. zNNNBNBBNNNNNB( <NB~ 'BNB 'D <Bs =NNNN
+ NNNNNNN. zNNNNNNNNNNBNN. . .NDB -D hs N
+ NNNNNNN. zNNNNNhBNBN=+z +BN- NDB '(D <BhhhhhhhN
+ BNNNNNN. zNNNh=<~. h-s< D~D'.-~B<NBNBDs ''``
+ DNNNNNN. zNNN D-B-~(+B DNBDzs-`
+ sNNNNNN. zNNN B(NDhs=( ''`
+ (BNNNNN' zNDB ~D.
+ sNNNNB- +hsz h< O___
+ <NNNB( -=s' 'hz ___ ___ < s > \____
+ ~BNh .+B+ / _ \/ _ \ = \ /
+ ~Dz~. .~+zB=' \___/_//_/ / \ \__/
+ <hNNBNBh=(. / \ `
+ ..
+
+Cape
+====
+
+If
+
+* **You use [Capistrano](http://capify.org)** to deploy your application, and
+* **You have [Rake](http://rake.rubyforge.org) tasks you want to run remotely** — but you don’t want to hand-code Capistrano recipes for each Rake task —
+
+Then
+
+* **You can invoke [Cape](http://github.com/njonsson/cape)** to dynamically add Capistrano recipes for each of your application’s Rake tasks, and
+* **You can run your Rake tasks on your deployed servers,** friction-free, and look like a superhero. _[cue fanfare]_
+
+Features
+--------
+
+* **Mirror Rake tasks** as Capistrano recipes, optionally filtered by namespace or name
+* **Embed Rake tasks** in a Capistrano namespace
+* **Pass arguments** to Rake tasks by setting environment variables with the same names
+* **Override the default executables** for local and remote Rake installations (`/usr/bin/env rake` is the default)
+* **Enumerate Rake tasks** for your own purposes
+
+Examples
+--------
+
+Assume we have the following _Rakefile_.
+
+ desc 'Rakes the leaves'
+ task :leaves do
+ # (Raking action goes here.)
+ end
+
+ desc 'Rakes and bags the leaves'
+ task :bag_leaves, [:paper_or_plastic] => :leaves do
+ # (Bagging action goes here.)
+ end
+
+Rake lists these tasks in the expected fashion.
+
+ $ rake --tasks
+ rake bag_leaves[paper_or_plastic] # Rakes and bags the leaves
+ rake leaves # Rakes the leaves
+
+Put the following in your _config/deploy.rb_. **Note that Cape statements must be executed within a `Cape` block.**
+
+ require 'cape'
+
+ Cape do
+ # Create Capistrano recipes for all Rake tasks.
+ mirror_rake_tasks
+ end
+
+Now all your Rake tasks can be invoked as Capistrano recipes. Capistrano lists the recipes in the following fashion.
+
+ $ cap --tasks
+ cap deploy # Deploys your project.
+ ...
+ [other built-in Capistrano recipes]
+ ...
+ cap bag_leaves # Rakes and bags the leaves.
+ cap leaves # Rakes the leaves.
+ Some tasks were not listed, either because they have no description,
+ or because they are only used internally by other tasks. To see all
+ tasks, type `cap -vT'.
+
+ Extended help may be available for these tasks.
+ Type `cap -e taskname' to view it.
+
+Let’s use Capistrano to view the unabbreviated description of a Rake task recipe, including instructions for how to pass arguments to it. Note that Rake task parameters are automatically converted to environment variables.
+
+ $ cap --explain bag_leaves
+ ------------------------------------------------------------
+ cap bag_leaves
+ ------------------------------------------------------------
+ Bags the leaves.
+
+ You must set environment variable PAPER_OR_PLASTIC.
+
+Cape lets you filter the Rake tasks to be mirrored:
+
+ Cape do
+ # Create Capistrano recipes for the Rake task 'foo' or for the tasks in a
+ # 'foo' namespace.
+ mirror_rake_tasks :foo
+
+ # Create Capistrano recipes only for the Rake task 'bar:baz' or for the
+ # tasks in the 'bar:baz' namespace.
+ mirror_rake_tasks 'bar:baz'
+ end
+
+Cape plays friendly with the Capistrano DSL for organizing Rake tasks in Capistrano namespaces.
+
+ # Use an argument with the Cape block, if you want to or need to.
+ namespace :rake_tasks do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+
+Cape lets you enumerate Rake tasks, optionally filtering them by task name or namespace.
+
+ Cape do
+ each_rake_task do |t|
+ # Do something interesting with this hash:
+ # * t[:name] -- the full name of the task
+ # * t[:parameters] -- the names of task arguments
+ # * t[:description] -- documentation on the task, including parameters
+ end
+ end
+
+Limitations
+-----------
+
+For now, only Rake tasks that have descriptions can be mirrored or enumerated.
+
+Contributing
+------------
+
+Report defects and feature requests on [GitHub Issues](http://github.com/njonsson/cape/issues).
+
+Your patches are welcome, and you will receive attribution here for good stuff.
+
+License
+-------
+
+Released under the [MIT License](http://github.com/njonsson/cape/blob/master/MIT-LICENSE.markdown).
49 Rakefile
@@ -0,0 +1,49 @@
+require 'bundler/gem_tasks'
+require 'cucumber'
+require 'cucumber/rake/task'
+require 'rspec/core/rake_task'
+
+begin
+ require 'yard'
+rescue LoadError
+else
+ namespace :build do
+ YARD::Rake::YardocTask.new :doc
+ end
+end
+
+Cucumber::Rake::Task.new :features, 'Test features'
+
+def define_spec_task(name, options={})
+ RSpec::Core::RakeTask.new name do |t|
+ t.rspec_opts = ['--color']
+ unless options[:debug] == false
+ begin
+ require 'ruby-debug'
+ rescue LoadError
+ else
+ t.rspec_opts << '--debug'
+ end
+ end
+ t.pattern = "spec/**/*_spec.rb"
+ end
+end
+
+desc 'Run all specs'
+define_spec_task :spec
+
+desc 'Run all specs and test features'
+task '' => [:spec, :features]
+task :default => [:spec, :features]
+
+# Support the 'gem test' command.
+namespace :test do
+ desc ''
+ define_spec_task :specs, :debug => false
+
+ Cucumber::Rake::Task.new :features, '' do |t|
+ t.bundler = false
+ t.cucumber_opts = '--backtrace'
+ end
+end
+task :test => %w(test:specs test:features)
36 cape.gemspec
@@ -0,0 +1,36 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path('../lib', __FILE__)
+require 'cape/version'
+
+Gem::Specification.new do |s|
+ s.name = 'cape'
+ s.version = Cape::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ['Nils Jonsson']
+ s.email = %w(cape@nilsjonsson.com)
+ s.homepage = ''
+ s.summary = 'Dynamically generates Capistrano recipes for Rake tasks'
+ s.description = 'Cape provides a simple DSL for selecting Rake tasks to be ' +
+ 'made available as documented Capistrano recipes. You can ' +
+ 'pass required arguments to Rake tasks via environment ' +
+ 'variables.'
+ s.license = 'MIT'
+
+ # TODO: Apply for RubyForge project
+ # s.rubyforge_project = 'cape'
+
+ s.required_ruby_version = '>= 1.8.7'
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map do |f|
+ File.basename f
+ end
+ s.require_paths = %w(lib)
+ s.has_rdoc = true
+
+ s.add_development_dependency 'aruba'
+ s.add_development_dependency 'capistrano'
+ s.add_development_dependency 'rake'
+ s.add_development_dependency 'rspec', '~> 2.7'
+end
43 features/dsl/each_rake_task/with_defined_namespace_argument.feature
@@ -0,0 +1,43 @@
+Feature: The #each_rake_task DSL method with an argument of a defined namespace
+
+ In order to use the metadata of Rake tasks in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: enumerate only the Rake tasks in the matching namespace
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ each_rake_task :my_namespace do |t|
+ $stdout.puts '', "Name: #{t[:name].inspect}"
+ if t[:parameters]
+ $stdout.puts "Parameters: #{t[:parameters].inspect}"
+ end
+ if t[:description]
+ $stdout.puts "Description: #{t[:description].inspect}"
+ end
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should not contain:
+ """
+
+ Name: "with_period"
+ Description: "Ends with period."
+ """
+ And the output should contain:
+ """
+
+ Name: "my_namespace:in_a_namespace"
+ Description: "My task in a namespace"
+ """
+ And the output should contain:
+ """
+
+ Name: "my_namespace:my_nested_namespace:in_a_nested_namespace"
+ Description: "My task in a nested namespace"
+ """
37 features/dsl/each_rake_task/with_defined_task_argument.feature
@@ -0,0 +1,37 @@
+Feature: The #each_rake_task DSL method with an argument of a defined task
+
+ In order to use the metadata of Rake tasks in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: enumerate only the matching Rake task
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ each_rake_task 'with_period' do |t|
+ $stdout.puts '', "Name: #{t[:name].inspect}"
+ if t[:parameters]
+ $stdout.puts "Parameters: #{t[:parameters].inspect}"
+ end
+ if t[:description]
+ $stdout.puts "Description: #{t[:description].inspect}"
+ end
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should contain:
+ """
+
+ Name: "with_period"
+ Description: "Ends with period."
+ """
+ And the output should not contain:
+ """
+
+ Name: "without_period"
+ Description: "Ends without period"
+ """
31 features/dsl/each_rake_task/with_undefined_argument.feature
@@ -0,0 +1,31 @@
+Feature: The #each_rake_task DSL method with an undefined argument
+
+ In order to use the metadata of Rake tasks in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: do not enumerate any Rake tasks
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ each_rake_task :this_does_not_exist do |t|
+ $stdout.puts '', "Name: #{t[:name].inspect}"
+ if t[:parameters]
+ $stdout.puts "Parameters: #{t[:parameters].inspect}"
+ end
+ if t[:description]
+ $stdout.puts "Description: #{t[:description].inspect}"
+ end
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should not contain:
+ """
+
+ Name: "with_period"
+ Description: "Ends with period."
+ """
81 features/dsl/each_rake_task/without_arguments.feature
@@ -0,0 +1,81 @@
+Feature: The #each_rake_task DSL method without arguments
+
+ In order to use the metadata of Rake tasks in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: enumerate all non-hidden Rake tasks
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ each_rake_task do |t|
+ $stdout.puts '', "Name: #{t[:name].inspect}"
+ if t[:parameters]
+ $stdout.puts "Parameters: #{t[:parameters].inspect}"
+ end
+ if t[:description]
+ $stdout.puts "Description: #{t[:description].inspect}"
+ end
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should contain:
+ """
+
+ Name: "with_period"
+ Description: "Ends with period."
+ """
+ And the output should contain:
+ """
+
+ Name: "without_period"
+ Description: "Ends without period"
+ """
+ And the output should contain:
+ """
+
+ Name: "long"
+ Description: "My long task -- it has a very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very long description"
+ """
+ And the output should contain:
+ """
+
+ Name: "with_one_arg"
+ Parameters: ["the_arg"]
+ Description: "My task with one argument"
+ """
+ And the output should contain:
+ """
+
+ Name: "my_namespace:in_a_namespace"
+ Description: "My task in a namespace"
+ """
+ And the output should contain:
+ """
+
+ Name: "my_namespace:my_nested_namespace:in_a_nested_namespace"
+ Description: "My task in a nested namespace"
+ """
+ And the output should contain:
+ """
+
+ Name: "with_two_args"
+ Parameters: ["my_arg1", "my_arg2"]
+ Description: "My task with two arguments"
+ """
+ And the output should contain:
+ """
+
+ Name: "with_three_args"
+ Parameters: ["an_arg1", "an_arg2", "an_arg3"]
+ Description: "My task with three arguments"
+ """
+ And the output should not contain:
+ """
+
+ Name: "hidden_task"
+ """
93 ...dsl/mirror_rake_tasks/inside_capistrano_namespace/with_defined_namespace_argument.feature
@@ -0,0 +1,93 @@
+Feature: The #mirror_rake_tasks DSL method, inside a Capistrano namespace, with an argument of a defined namespace
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: mirror only the Rake tasks in the matching namespace
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks 'my_namespace'
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should not contain "cap ns:with_period"
+ And the output should contain:
+ """
+ cap ns:my_namespace:in_a_namespace # My task in a namespace.
+ """
+ And the output should contain:
+ """
+ cap ns:my_namespace:my_nested_namespace:in_a_nested_namespace # My task in a nested namespace.
+ """
+
+ Scenario: do not mirror Rake task 'with_period'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks :my_namespace
+ end
+ end
+ """
+ When I run `cap -e ns:with_period`
+ Then the output should contain exactly:
+ """
+ The task `ns:with_period' does not exist.
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:in_a_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks :my_namespace
+ end
+ end
+ """
+ When I run `cap -e ns:my_namespace:in_a_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:my_namespace:in_a_namespace
+ ------------------------------------------------------------
+ My task in a namespace.
+
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:my_nested_namespace:in_a_nested_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks :my_namespace
+ end
+ end
+ """
+ When I run `cap -e ns:my_namespace:my_nested_namespace:in_a_nested_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:my_namespace:my_nested_namespace:in_a_nested_namespace
+ ------------------------------------------------------------
+ My task in a nested namespace.
+
+
+ """
66 ...ures/dsl/mirror_rake_tasks/inside_capistrano_namespace/with_defined_task_argument.feature
@@ -0,0 +1,66 @@
+Feature: The #mirror_rake_tasks DSL method, inside a Capistrano namespace, with an argument of a defined task
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: mirror only the matching Rake task
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks 'with_period'
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should contain:
+ """
+ cap ns:with_period # Ends with period.
+ """
+ And the output should not contain "cap ns:without_period"
+
+ Scenario: mirror Rake task 'with_period' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks :with_period
+ end
+ end
+ """
+ When I run `cap -e ns:with_period`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:with_period
+ ------------------------------------------------------------
+ Ends with period.
+
+
+ """
+
+ Scenario: do not mirror Rake task 'without_period'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks :with_period
+ end
+ end
+ """
+ When I run `cap -e ns:without_period`
+ Then the output should contain exactly:
+ """
+ The task `ns:without_period' does not exist.
+
+ """
39 features/dsl/mirror_rake_tasks/inside_capistrano_namespace/with_undefined_argument.feature
@@ -0,0 +1,39 @@
+Feature: The #mirror_rake_tasks DSL method, inside a Capistrano namespace, with an undefined argument
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: do not mirror any Rake tasks
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks 'this_does_not_exist'
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should not contain "cap ns:with_period"
+
+ Scenario: do not mirror Rake task 'with_period'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks :this_does_not_exist
+ end
+ end
+ """
+ When I run `cap -e ns:with_period`
+ Then the output should contain exactly:
+ """
+ The task `ns:with_period' does not exist.
+
+ """
263 features/dsl/mirror_rake_tasks/inside_capistrano_namespace/without_arguments.feature
@@ -0,0 +1,263 @@
+Feature: The #mirror_rake_tasks DSL method, inside a Capistrano namespace, without arguments
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: mirror all non-hidden Rake tasks
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -T`
+ Then the output should contain:
+ """
+ cap ns:with_period # Ends with period.
+ """
+ And the output should contain:
+ """
+ cap ns:without_period # Ends without period.
+ """
+ And the output should contain:
+ """
+ cap ns:long # My long task -- it has a ve...
+ """
+ And the output should contain:
+ """
+ cap ns:with_one_arg # My task with one argument.
+ """
+ And the output should contain:
+ """
+ cap ns:my_namespace:in_a_namespace # My task in a namespace.
+ """
+ And the output should contain:
+ """
+ cap ns:my_namespace:my_nested_namespace:in_a_nested_namespace # My task in a nested namespace.
+ """
+ And the output should contain:
+ """
+ cap ns:with_two_args # My task with two arguments.
+ """
+ And the output should contain:
+ """
+ cap ns:with_three_args # My task with three arguments.
+ """
+ And the output should not contain "cap hidden_task"
+
+ Scenario: mirror Rake task 'with_period' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:with_period`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:with_period
+ ------------------------------------------------------------
+ Ends with period.
+
+
+ """
+
+ Scenario: mirror Rake task 'without_period' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:without_period`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:without_period
+ ------------------------------------------------------------
+ Ends without period.
+
+
+ """
+
+ Scenario: mirror Rake task 'long' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:long`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:long
+ ------------------------------------------------------------
+ My long task -- it has a very, very, very, very, very, very, very, very, very,
+ very, very, very, very, very, very, very, very, very, very, very, very, very,
+ very, very, very, very long description.
+
+
+ """
+
+ Scenario: mirror Rake task 'with_one_arg' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:with_one_arg`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:with_one_arg
+ ------------------------------------------------------------
+ My task with one argument.
+
+ You must set environment variable THE_ARG.
+
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:in_a_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:my_namespace:in_a_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:my_namespace:in_a_namespace
+ ------------------------------------------------------------
+ My task in a namespace.
+
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:my_nested_namespace:in_a_nested_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:my_namespace:my_nested_namespace:in_a_nested_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:my_namespace:my_nested_namespace:in_a_nested_namespace
+ ------------------------------------------------------------
+ My task in a nested namespace.
+
+
+ """
+
+ Scenario: mirror Rake task 'with_two_args' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:with_two_args`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:with_two_args
+ ------------------------------------------------------------
+ My task with two arguments.
+
+ You must set environment variables MY_ARG1 and MY_ARG2.
+
+
+ """
+
+ Scenario: mirror Rake task 'with_three_args' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:with_three_args`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap ns:with_three_args
+ ------------------------------------------------------------
+ My task with three arguments.
+
+ You must set environment variables AN_ARG1, AN_ARG2, and AN_ARG3.
+
+
+ """
+
+ Scenario: do not mirror Rake task 'hidden_task'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ namespace :ns do
+ Cape do |cape|
+ cape.mirror_rake_tasks
+ end
+ end
+ """
+ When I run `cap -e ns:hidden_task`
+ Then the output should contain exactly:
+ """
+ The task `ns:hidden_task' does not exist.
+
+ """
85 features/dsl/mirror_rake_tasks/with_defined_namespace_argument.feature
@@ -0,0 +1,85 @@
+Feature: The #mirror_rake_tasks DSL method with an argument of a defined namespace
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: mirror only the Rake tasks in the matching namespace
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks 'my_namespace'
+ end
+ """
+ When I run `cap -T`
+ Then the output should not contain "cap with_period"
+ And the output should contain:
+ """
+ cap my_namespace:in_a_namespace # My task in a namespace.
+ """
+ And the output should contain:
+ """
+ cap my_namespace:my_nested_namespace:in_a_nested_namespace # My task in a nested namespace.
+ """
+
+ Scenario: do not mirror Rake task 'with_period'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks :my_namespace
+ end
+ """
+ When I run `cap -e with_period`
+ Then the output should contain exactly:
+ """
+ The task `with_period' does not exist.
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:in_a_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks :my_namespace
+ end
+ """
+ When I run `cap -e my_namespace:in_a_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap my_namespace:in_a_namespace
+ ------------------------------------------------------------
+ My task in a namespace.
+
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:my_nested_namespace:in_a_nested_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks :my_namespace
+ end
+ """
+ When I run `cap -e my_namespace:my_nested_namespace:in_a_nested_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap my_namespace:my_nested_namespace:in_a_nested_namespace
+ ------------------------------------------------------------
+ My task in a nested namespace.
+
+
+ """
60 features/dsl/mirror_rake_tasks/with_defined_task_argument.feature
@@ -0,0 +1,60 @@
+Feature: The #mirror_rake_tasks DSL method with an argument of a defined task
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: mirror only the matching Rake task
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks 'with_period'
+ end
+ """
+ When I run `cap -T`
+ Then the output should contain:
+ """
+ cap with_period # Ends with period.
+ """
+ And the output should not contain "cap without_period"
+
+ Scenario: mirror Rake task 'with_period' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks :with_period
+ end
+ """
+ When I run `cap -e with_period`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap with_period
+ ------------------------------------------------------------
+ Ends with period.
+
+
+ """
+
+ Scenario: do not mirror Rake task 'without_period'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks :with_period
+ end
+ """
+ When I run `cap -e without_period`
+ Then the output should contain exactly:
+ """
+ The task `without_period' does not exist.
+
+ """
35 features/dsl/mirror_rake_tasks/with_undefined_argument.feature
@@ -0,0 +1,35 @@
+Feature: The #mirror_rake_tasks DSL method with an undefined argument
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: do not mirror any Rake tasks
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks 'this_does_not_exist'
+ end
+ """
+ When I run `cap -T`
+ Then the output should not contain "cap with_period"
+
+ Scenario: do not mirror Rake task 'with_period'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks :this_does_not_exist
+ end
+ """
+ When I run `cap -e with_period`
+ Then the output should contain exactly:
+ """
+ The task `with_period' does not exist.
+
+ """
243 features/dsl/mirror_rake_tasks/without_arguments.feature
@@ -0,0 +1,243 @@
+Feature: The #mirror_rake_tasks DSL method without arguments
+
+ In order to include Rake tasks with descriptions in my Capistrano recipes,
+ As a developer using Cape,
+ I want to use the Cape DSL.
+
+ Scenario: mirror all non-hidden Rake tasks
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -T`
+ Then the output should contain:
+ """
+ cap with_period # Ends with period.
+ """
+ And the output should contain:
+ """
+ cap without_period # Ends without period.
+ """
+ And the output should contain:
+ """
+ cap long # My long task -- it has a ve...
+ """
+ And the output should contain:
+ """
+ cap with_one_arg # My task with one argument.
+ """
+ And the output should contain:
+ """
+ cap my_namespace:in_a_namespace # My task in a namespace.
+ """
+ And the output should contain:
+ """
+ cap my_namespace:my_nested_namespace:in_a_nested_namespace # My task in a nested namespace.
+ """
+ And the output should contain:
+ """
+ cap with_two_args # My task with two arguments.
+ """
+ And the output should contain:
+ """
+ cap with_three_args # My task with three arguments.
+ """
+ And the output should not contain "cap hidden_task"
+
+ Scenario: mirror Rake task 'with_period' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e with_period`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap with_period
+ ------------------------------------------------------------
+ Ends with period.
+
+
+ """
+
+ Scenario: mirror Rake task 'without_period' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e without_period`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap without_period
+ ------------------------------------------------------------
+ Ends without period.
+
+
+ """
+
+ Scenario: mirror Rake task 'long' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e long`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap long
+ ------------------------------------------------------------
+ My long task -- it has a very, very, very, very, very, very, very, very, very,
+ very, very, very, very, very, very, very, very, very, very, very, very, very,
+ very, very, very, very long description.
+
+
+ """
+
+ Scenario: mirror Rake task 'with_one_arg' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e with_one_arg`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap with_one_arg
+ ------------------------------------------------------------
+ My task with one argument.
+
+ You must set environment variable THE_ARG.
+
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:in_a_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e my_namespace:in_a_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap my_namespace:in_a_namespace
+ ------------------------------------------------------------
+ My task in a namespace.
+
+
+ """
+
+ Scenario: mirror Rake task 'my_namespace:my_nested_namespace:in_a_nested_namespace' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e my_namespace:my_nested_namespace:in_a_nested_namespace`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap my_namespace:my_nested_namespace:in_a_nested_namespace
+ ------------------------------------------------------------
+ My task in a nested namespace.
+
+
+ """
+
+ Scenario: mirror Rake task 'with_two_args' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e with_two_args`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap with_two_args
+ ------------------------------------------------------------
+ My task with two arguments.
+
+ You must set environment variables MY_ARG1 and MY_ARG2.
+
+
+ """
+
+ Scenario: mirror Rake task 'with_three_args' with its description
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e with_three_args`
+ Then the output should contain exactly:
+ """
+ ------------------------------------------------------------
+ cap with_three_args
+ ------------------------------------------------------------
+ My task with three arguments.
+
+ You must set environment variables AN_ARG1, AN_ARG2, and AN_ARG3.
+
+
+ """
+
+ Scenario: do not mirror Rake task 'hidden_task'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap -e hidden_task`
+ Then the output should contain exactly:
+ """
+ The task `hidden_task' does not exist.
+
+ """
33 features/step_definitions.rb
@@ -0,0 +1,33 @@
+Given 'a full-featured Rakefile' do
+ step 'a file named "Rakefile" with:', <<-end_step
+ desc 'Ends with period.'
+ task :with_period
+
+ desc 'Ends without period'
+ task :without_period
+
+ desc 'My long task -- it has a very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very long description'
+ task :long
+
+ desc 'My task with one argument'
+ task :with_one_arg, [:the_arg]
+
+ namespace :my_namespace do
+ desc 'My task in a namespace'
+ task :in_a_namespace
+
+ namespace :my_nested_namespace do
+ desc 'My task in a nested namespace'
+ task :in_a_nested_namespace
+ end
+ end
+
+ desc 'My task with two arguments'
+ task :with_two_args, [:my_arg1, :my_arg2]
+
+ desc 'My task with three arguments'
+ task :with_three_args, [:an_arg1, :an_arg2, :an_arg3]
+
+ task :hidden_task
+ end_step
+end
1 features/support/env.rb
@@ -0,0 +1 @@
+require 'aruba/cucumber'
69 features/task_invocation/nonparameterized.feature
@@ -0,0 +1,69 @@
+Feature: Invoking parameterless Rake tasks via Capistrano
+
+ In order to invoke Rake tasks via Capistrano,
+ As a developer using Cape,
+ I want to use the `cap` command.
+
+ Scenario: invoke Rake task 'with_period'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+
+ # Uncomment if you are using Rails' asset pipeline
+ # load 'deploy/assets'
+
+ Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
+
+ load 'config/deploy' # remove this line to skip loading any of the default tasks
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ And a file named "config/deploy.rb" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap with_period`
+ Then the output should contain:
+ """
+ * executing `with_period'
+ """
+
+ Scenario: invoke Rake task 'my_namespace:in_a_namespace'
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+
+ # Uncomment if you are using Rails' asset pipeline
+ # load 'deploy/assets'
+
+ Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
+
+ load 'config/deploy' # remove this line to skip loading any of the default tasks
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ And a file named "config/deploy.rb" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap my_namespace:in_a_namespace`
+ Then the output should contain:
+ """
+ * executing `my_namespace:in_a_namespace'
+ """
70 features/task_invocation/parameterized.feature
@@ -0,0 +1,70 @@
+Feature: Invoking parameterized Rake tasks via Capistrano
+
+ In order to invoke Rake tasks via Capistrano,
+ As a developer using Cape,
+ I want to use the `cap` command.
+
+ Scenario: invoke Rake task 'with_one_arg' without an argument
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+
+ # Uncomment if you are using Rails' asset pipeline
+ # load 'deploy/assets'
+
+ Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
+
+ load 'config/deploy' # remove this line to skip loading any of the default tasks
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ And a file named "config/deploy.rb" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap with_one_arg`
+ Then the output should contain:
+ """
+ * executing `with_one_arg'
+ """
+ And the output should contain "Environment variable THE_ARG must be set (RuntimeError)"
+
+ Scenario: invoke Rake task 'with_one_arg' with its argument
+ Given a full-featured Rakefile
+ And a file named "Capfile" with:
+ """
+ load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+
+ # Uncomment if you are using Rails' asset pipeline
+ # load 'deploy/assets'
+
+ Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
+
+ load 'config/deploy' # remove this line to skip loading any of the default tasks
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ And a file named "config/deploy.rb" with:
+ """
+ require 'cape'
+
+ Cape do
+ mirror_rake_tasks
+ end
+ """
+ When I run `cap with_one_arg THE_ARG="the arg goes here"`
+ Then the output should contain:
+ """
+ * executing `with_one_arg'
+ """
22 lib/cape.rb
@@ -0,0 +1,22 @@
+Dir.glob( File.expand_path( 'cape/*.rb', File.dirname( __FILE__ ))) do |f|
+ require "cape/#{File.basename f, '.rb'}"
+end
+
+# Contains the implementation of Cape.
+module Cape
+
+ extend DSL
+
+end
+
+# The method used to group Cape statements in a block.
+def Cape(&block)
+ Cape.module_eval do
+ @outer_self = block.binding.eval('self', __FILE__, __LINE__)
+ if 0 < block.arity
+ block.call self
+ else
+ module_eval(&block)
+ end
+ end
+end
86 lib/cape/capistrano.rb
@@ -0,0 +1,86 @@
+require 'cape/strings'
+
+module Cape
+
+ # An abstraction of the Capistrano installation.
+ class Capistrano
+
+ # Defines the specified _task_ as a Capistrano task, provided a Binding
+ # named argument +:binding+ and a Cape::Rake named argument +:rake+. Any
+ # parameters the task has are converted to environment variables, since
+ # Capistrano does not have the concept of task parameters.
+ #
+ # The _task_ argument must be a Hash of the form:
+ #
+ # {:name => <String>,
+ # :parameters => <String Array or nil>,
+ # :description => <String>}
+ def define(task, named_arguments={})
+ unless (binding = named_arguments[:binding])
+ raise ::ArgumentError, ':binding named argument is required'
+ end
+ unless (rake = named_arguments[:rake])
+ raise ::ArgumentError, ':rake named argument is required'
+ end
+ roles = named_arguments[:roles] || :app
+
+ capistrano = binding.eval('self', __FILE__, __LINE__)
+ if (description = build_capistrano_description(task))
+ capistrano.desc description
+ end
+ implement task, roles, capistrano, rake
+ self
+ end
+
+ private
+
+ def build_capistrano_description(task)
+ return nil unless task[:description]
+
+ description = [task[:description]]
+ description << '.' unless task[:description].end_with?('.')
+ unless (parameters = Array(task[:parameters])).empty?
+ noun = Strings.pluralize('variable', parameters.length)
+ parameters_list = Strings.to_list_phrase(parameters.collect(&:upcase))
+ description << <<-end_description
+
+
+You must set environment #{noun} #{parameters_list}.
+ end_description
+ end
+ description.join
+ end
+
+ def implement(task, roles, capistrano_context, rake)
+ name = task[:name].split(':')
+ # Define the task.
+ block = lambda { |context|
+ context.task name.last, :roles => roles do
+ arguments = Array(task[:parameters]).collect do |a|
+ unless (value = ENV[a.upcase])
+ fail "Environment variable #{a.upcase} must be set"
+ end
+ value
+ end
+ if arguments.empty?
+ arguments = nil
+ else
+ arguments = "[#{arguments.join ','}]"
+ end
+ context.run "cd #{context.current_path} && " +
+ "#{rake.remote_executable} #{name.join ':'}#{arguments}"
+ end
+ }
+ # Nest the task inside its containing namespaces.
+ name[0...-1].reverse.each do |namespace_token|
+ inner_block = block
+ block = lambda { |context|
+ context.namespace(namespace_token, &inner_block)
+ }
+ end
+ block.call capistrano_context
+ end
+
+ end
+
+end
10 lib/cape/core_ext.rb
@@ -0,0 +1,10 @@
+Dir.glob( File.expand_path( 'core_ext/*.rb', File.dirname( __FILE__ ))) do |f|
+ require "cape/core_ext/#{File.basename f, '.rb'}"
+end
+
+module Cape
+
+ # Contains extensions to core types.
+ module CoreExt; end
+
+end
24 lib/cape/core_ext/hash.rb
@@ -0,0 +1,24 @@
+module Cape
+
+ module CoreExt
+
+ # Contains extensions to the Hash core class.
+ module Hash
+
+ # Returns a copy of the Hash containing values only for the specified
+ # _keys_.
+ def slice(*keys)
+ ::Hash[select { |key, value| keys.include? key }]
+ end
+
+ end
+
+ end
+
+end
+
+unless Hash.instance_methods.collect(&:to_s).include?('slice')
+ Hash.class_eval do
+ include Cape::CoreExt::Hash
+ end
+end
25 lib/cape/core_ext/symbol.rb
@@ -0,0 +1,25 @@
+module Cape
+
+ module CoreExt
+
+ # Contains extensions to the Symbol core class.
+ module Symbol
+
+ # Returns +0+ if the Symbol is equal to _other_, +-1+ if it is
+ # alphabetically lesser than _other_, and +1+ if it is alphabetically
+ # greater than _other_.
+ def <=>(other)
+ to_s <=> other.to_s
+ end
+
+ end
+
+ end
+
+end
+
+unless Symbol.instance_methods.collect(&:to_s).include?('<=>')
+ Symbol.class_eval do
+ include Cape::CoreExt::Symbol
+ end
+end
81 lib/cape/dsl.rb
@@ -0,0 +1,81 @@
+require 'cape/capistrano'
+require 'cape/rake'
+
+module Cape
+
+ # Provides methods for integrating Capistrano and Rake.
+ module DSL
+
+ # Yields each available Rake task to a block. The optional _task_expression_
+ # argument limits the list to a single task or a namespace containing
+ # multiple tasks.
+ #
+ # Tasks are yielded as Hash objects of the form:
+ #
+ # {:name => <String>,
+ # :parameters => <String Array or nil>,
+ # :description => <String>}
+ def each_rake_task(task_expression=nil, &block)
+ rake.each_task(task_expression, &block)
+ self
+ end
+
+ # Returns the command used to run Rake on the local computer. Defaults to
+ # Rake::DEFAULT_EXECUTABLE.
+ def local_rake_executable
+ rake.local_executable
+ end
+
+ # Sets the command used to run Rake on the local computer.
+ def local_rake_executable=(value)
+ rake.local_executable = value
+ end
+
+ # Defines each available Rake task as a Capistrano task. Any
+ # parameters the tasks have are converted to environment variables, since
+ # Capistrano does not have the concept of task parameters. The optional
+ # _task_expression_ argument limits the list to a single task or a namespace
+ # containing multiple tasks.
+ def mirror_rake_tasks(task_expression=nil)
+ d = nil
+ rake.each_task task_expression do |t|
+ (d ||= deployment_library).define t, :binding => binding, :rake => rake
+ end
+ self
+ end
+
+ # Returns the command used to run Rake on remote computers. Defaults to
+ # Rake::DEFAULT_EXECUTABLE.
+ def remote_rake_executable
+ rake.remote_executable
+ end
+
+ # Sets the command used to run Rake on remote computers.
+ def remote_rake_executable=(value)
+ rake.remote_executable = value
+ end
+
+ private
+
+ def deployment_library
+ raise_unless_capistrano
+ Capistrano.new
+ end
+
+ def method_missing(method, *args, &block)
+ @outer_self.send(method, *args, &block)
+ end
+
+ def raise_unless_capistrano
+ if @outer_self.method(:task).owner.name !~ /^Capistrano::/
+ raise 'Use this in the context of Capistrano recipes'
+ end
+ end
+
+ def rake
+ @rake ||= Rake.new
+ end
+
+ end
+
+end
60 lib/cape/rake.rb
@@ -0,0 +1,60 @@
+module Cape
+
+ # An abstraction of the Rake installation and available tasks.
+ class Rake
+
+ # The default command used to run Rake.
+ DEFAULT_EXECUTABLE = '/usr/bin/env rake'.freeze
+
+ # Sets the command used to run Rake on the local computer.
+ attr_writer :local_executable
+
+ # Sets the command used to run Rake on remote computers.
+ attr_writer :remote_executable
+
+ # Constructs a new Rake object with the specified _attributes_.
+ def initialize(attributes={})
+ attributes.each do |name, value|
+ send "#{name}=", value
+ end
+ end
+
+ # Yields each available Rake task to a block. The optional _task_expression_
+ # argument limits the list to a single task or a namespace containing
+ # multiple tasks.
+ #
+ # Tasks are yielded as Hash objects of the form:
+ #
+ # {:name => <String>,
+ # :parameters => <String Array or nil>,
+ # :description => <String>}
+ def each_task(task_expression=nil)
+ task_expression = " #{task_expression}" if task_expression
+ command = "#{local_executable} --tasks #{task_expression}"
+ `#{command}`.each_line do |l|
+ matches = l.chomp.match(/^rake (.+?)(?:\[(.+?)\])?\s+# (.+)/)
+ task = {}.tap do |t|
+ t[:name] = matches[1].strip
+ t[:parameters] = matches[2].split(',') if matches[2]
+ t[:description] = matches[3]
+ end
+ yield task
+ end
+ self
+ end
+
+ # Returns the command used to run Rake on the local computer. Defaults to
+ # DEFAULT_EXECUTABLE.
+ def local_executable
+ @local_executable ||= DEFAULT_EXECUTABLE
+ end
+
+ # Returns the command used to run Rake on remote computers. Defaults to
+ # DEFAULT_EXECUTABLE.
+ def remote_executable
+ @remote_executable ||= DEFAULT_EXECUTABLE
+ end
+
+ end
+
+end
25 lib/cape/strings.rb
@@ -0,0 +1,25 @@
+module Cape
+
+ # Provides utility methods for String objects.
+ module Strings
+
+ extend self
+
+ # Returns the English plural form of _noun_, unless _count_ is +1+. The
+ # _count_ argument is optional, and defaults to +2+.
+ def pluralize(noun, count=2)
+ return noun if count == 1
+
+ "#{noun}s"
+ end
+
+ # Builds an English list phrase from the elements of _array_.
+ def to_list_phrase(array)
+ return array.join(' and ') if (array.length <= 2)
+
+ [array[0...-1].join(', '), array[-1]].join ', and '
+ end
+
+ end
+
+end
6 lib/cape/version.rb
@@ -0,0 +1,6 @@
+module Cape
+
+ # The version of Cape.
+ VERSION = '1.0.0'
+
+end
0 spec/cape/capistrano_spec.rb
No changes.
12 spec/cape/core_ext/hash_spec.rb
@@ -0,0 +1,12 @@
+require 'cape/core_ext/hash'
+
+describe Hash do
+ describe '#slice' do
+ it 'should return the expected Hash' do
+ hash = {:foo => 'bar', :baz => 'qux', :quux => 'corge'}
+ hash.slice(:baz, :quux).should == {:baz => 'qux', :quux => 'corge'}
+
+ {}.slice(:foo).should == {}
+ end
+ end
+end
7 spec/cape/core_ext/symbol_spec.rb
@@ -0,0 +1,7 @@
+require 'cape/core_ext/symbol'
+
+describe Symbol do
+ it 'should compare as expected to another Symbol' do
+ (:foo <=> :bar).should == 1
+ end
+end
128 spec/cape/dsl_spec.rb
@@ -0,0 +1,128 @@
+require 'cape/dsl'
+require 'cape/capistrano'
+require 'cape/core_ext/hash'
+require 'cape/core_ext/symbol'
+require 'cape/rake'
+
+describe Cape::DSL do
+ subject do
+ Object.new.tap do |o|
+ o.extend described_class
+ end
+ end
+
+ let(:mock_capistrano) { mock(Cape::Capistrano).as_null_object }
+
+ let(:mock_rake) { mock(Cape::Rake).as_null_object }
+
+ let(:task_expression) { 'task:expression' }
+
+ before :each do
+ Cape::Capistrano.stub!(:new).and_return mock_capistrano
+ Cape::Rake.stub!(:new).and_return mock_rake
+ end
+
+ describe 'when sent #each_rake_task' do
+ def do_each_rake_task(&block)
+ subject.each_rake_task(task_expression, &block)
+ end
+
+ it 'should delegate to Rake#each_task' do
+ mock_rake.should_receive(:each_task).
+ with(task_expression).
+ and_yield({:name => task_expression})
+ do_each_rake_task do |t|
+ t.should == {:name => task_expression}
+ end
+ end
+
+ it 'should return itself' do
+ do_each_rake_task.should == subject
+ end
+ end
+
+ describe 'when sent #mirror_rake_tasks' do
+ before :each do
+ mock_rake.stub!(:each_task).and_yield({:name => task_expression})
+ subject.stub! :raise_unless_capistrano
+ end
+
+ def do_mirror_rake_tasks
+ subject.mirror_rake_tasks task_expression
+ end
+
+ it 'should collect Rake#each_task' do
+ mock_rake.should_receive(:each_task).with task_expression
+ do_mirror_rake_tasks
+ end
+
+ it 'should verify that Capistrano is in use' do
+ subject.should_receive :raise_unless_capistrano
+ do_mirror_rake_tasks
+ end
+
+ describe 'should Capistrano#define Rake#each_task' do
+ it 'with the expected task' do
+ mock_capistrano.should_receive(:define).with do |task, options|
+ task == {:name => task_expression}
+ end
+ do_mirror_rake_tasks
+ end
+
+ it 'with the expected named options' do
+ mock_capistrano.should_receive(:define).with do |task, opts|
+ opts.keys.sort == [:binding, :rake]
+ end
+ do_mirror_rake_tasks
+ end
+
+ it 'with a :binding option' do
+ mock_capistrano.should_receive(:define).with do |task, options|
+ options[:binding].is_a? Binding
+ end
+ do_mirror_rake_tasks
+ end
+
+ it 'with the expected :rake option' do
+ mock_capistrano.should_receive(:define).with do |task, options|
+ options[:rake] == mock_rake
+ end
+ do_mirror_rake_tasks
+ end
+ end
+
+ it 'should return itself' do
+ do_mirror_rake_tasks.should == subject
+ end
+ end
+
+ describe 'when sent #local_rake_executable' do
+ before :each do
+ mock_rake.stub!(:local_executable).and_return 'foo'
+ end
+
+ it 'should delegate to Rake#local_executable' do
+ mock_rake.should_receive :local_executable
+ subject.local_rake_executable
+ end
+
+ it 'should return the result of Rake#local_executable' do
+ subject.local_rake_executable.should == 'foo'
+ end
+ end
+
+ describe 'when sent #remote_rake_executable' do
+ before :each do
+ mock_rake.stub!(:remote_executable).and_return 'foo'
+ end
+
+ it 'should delegate to Rake#remote_executable' do
+ mock_rake.should_receive :remote_executable
+ subject.remote_rake_executable
+ end
+
+ it 'should return the result of Rake#remote_executable' do
+ subject.remote_rake_executable.should == 'foo'
+ end
+ end
+end
0 spec/cape/rake_spec.rb
No changes.
44 spec/cape/strings_spec.rb
@@ -0,0 +1,44 @@
+require 'cape/strings'
+
+describe Cape::Strings do
+ describe '::pluralize' do
+ it "should pluralize 'foo' as expected" do
+ Cape::Strings.pluralize('foo').should == 'foos'
+ end
+
+ it "should pluralize 'foo' as expected for a count of 2" do
+ Cape::Strings.pluralize('foo', 2).should == 'foos'
+ end
+
+ it "should not pluralize for a count of 1" do
+ Cape::Strings.pluralize('foo', 1).should == 'foo'
+ end
+
+ it "should pluralize 'foo' as expected for a count of 0" do
+ Cape::Strings.pluralize('foo', 0).should == 'foos'
+ end
+
+ it "should pluralize 'foo' as expected for a count of -1" do
+ Cape::Strings.pluralize('foo', -1).should == 'foos'
+ end
+ end
+
+ describe '::to_list_phrase' do
+ it 'should make the expected list phrase of an empty array' do
+ Cape::Strings.to_list_phrase([]).should == ''
+ end
+
+ it 'should make the expected list phrase of a 1-element array' do
+ Cape::Strings.to_list_phrase(%w(foo)).should == 'foo'
+ end
+
+ it 'should make the expected list phrase of a 2-element array' do
+ Cape::Strings.to_list_phrase(%w(foo bar)).should == 'foo and bar'
+ end
+
+ it 'should make the expected list phrase of a 3-element array' do
+ array = %w(foo bar baz)
+ Cape::Strings.to_list_phrase(array).should == 'foo, bar, and baz'
+ end
+ end
+end
0 spec/cape/task_spec.rb
No changes.
6 spec/cape/version_spec.rb
@@ -0,0 +1,6 @@
+require 'rspec'
+require 'cape/version'
+
+describe Cape::VERSION do
+ it { should =~ /^\d+\.\d+\.\d+/ }
+end
5 spec/cape_spec.rb
@@ -0,0 +1,5 @@
+require 'cape/version'
+
+describe Cape::VERSION do
+ it { should match(/^\d+\.\d+\.\d+$/) }
+end

0 comments on commit 1e63590

Please sign in to comment.
Something went wrong with that request. Please try again.