awshucks 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +4 -0
- data/LICENSE +19 -0
- data/README +32 -0
- data/Rakefile +14 -0
- data/TODO +143 -0
- data/bin/awshucks +10 -0
- data/lib/awshucks.rb +29 -0
- data/lib/awshucks/cli.rb +76 -0
- data/lib/awshucks/command.rb +98 -0
- data/lib/awshucks/commands.rb +3 -0
- data/lib/awshucks/commands/backup.rb +59 -0
- data/lib/awshucks/commands/backups.rb +25 -0
- data/lib/awshucks/commands/help.rb +22 -0
- data/lib/awshucks/commands/list.rb +39 -0
- data/lib/awshucks/commands/new_config.rb +36 -0
- data/lib/awshucks/commands/reset_metadata_cache.rb +38 -0
- data/lib/awshucks/commands/restore.rb +54 -0
- data/lib/awshucks/config.rb +83 -0
- data/lib/awshucks/ext.rb +23 -0
- data/lib/awshucks/file_info.rb +23 -0
- data/lib/awshucks/file_store.rb +111 -0
- data/lib/awshucks/gemspec.rb +48 -0
- data/lib/awshucks/scanner.rb +58 -0
- data/lib/awshucks/specification.rb +128 -0
- data/lib/awshucks/version.rb +18 -0
- data/resources/awshucks.yml +21 -0
- data/spec/awshucks_spec.rb +7 -0
- data/spec/cli_spec.rb +130 -0
- data/spec/command_spec.rb +111 -0
- data/spec/commands/backup_spec.rb +164 -0
- data/spec/commands/backups_spec.rb +41 -0
- data/spec/commands/help_spec.rb +42 -0
- data/spec/commands/list_spec.rb +77 -0
- data/spec/commands/new_config_spec.rb +102 -0
- data/spec/commands/reset_metadata_cache_spec.rb +93 -0
- data/spec/commands/restore_spec.rb +219 -0
- data/spec/config_spec.rb +152 -0
- data/spec/ext_spec.rb +28 -0
- data/spec/file_info_spec.rb +45 -0
- data/spec/file_store_spec.rb +352 -0
- data/spec/scanner_spec.rb +106 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/specification_spec.rb +41 -0
- metadata +121 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'awshucks/specification'
|
3
|
+
require 'awshucks/version'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
# The Gem Specification plus some extras for awshucks.
|
7
|
+
module Awshucks
|
8
|
+
SPEC = Awshucks::Specification.new do |spec|
|
9
|
+
spec.name = "awshucks"
|
10
|
+
spec.version = Awshucks::VERSION
|
11
|
+
spec.rubyforge_project = "awshucks"
|
12
|
+
spec.author = "Nathan Witmer"
|
13
|
+
spec.email = "nathan-ruby@otherward.net"
|
14
|
+
spec.homepage = "http://awshucks.rubyforge.org/"
|
15
|
+
|
16
|
+
spec.summary = "A Summary of awshucks."
|
17
|
+
spec.description = <<-DESC
|
18
|
+
TODO: A longer more detailed description of awshucks.
|
19
|
+
DESC
|
20
|
+
|
21
|
+
spec.extra_rdoc_files = FileList["[A-Z]*"]
|
22
|
+
spec.has_rdoc = true
|
23
|
+
spec.rdoc_main = "README"
|
24
|
+
spec.rdoc_options = [ "--line-numbers" , "--inline-source" ]
|
25
|
+
|
26
|
+
spec.test_files = FileList["spec/**/*.rb", "test/**/*.rb"]
|
27
|
+
spec.executable = spec.name
|
28
|
+
spec.files = spec.test_files + spec.extra_rdoc_files +
|
29
|
+
FileList["lib/**/*.rb", "resources/**/*"]
|
30
|
+
|
31
|
+
# add dependencies
|
32
|
+
# spec.add_dependency("somegem", ">= 0.4.2")
|
33
|
+
spec.add_dependency("aws-s3", ">= 0.4.0")
|
34
|
+
# spec.add_dependency("main", ">= 0.2.0")
|
35
|
+
|
36
|
+
spec.platform = Gem::Platform::RUBY
|
37
|
+
|
38
|
+
spec.local_rdoc_dir = "doc/rdoc"
|
39
|
+
spec.remote_rdoc_dir = "#{spec.name}/rdoc"
|
40
|
+
spec.local_coverage_dir = "doc/coverage"
|
41
|
+
spec.remote_coverage_dir= "#{spec.name}/coverage"
|
42
|
+
|
43
|
+
spec.remote_site_dir = "#{spec.name}/"
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Awshucks
|
2
|
+
|
3
|
+
class Scanner
|
4
|
+
|
5
|
+
def self.each_file(dir, ignore = [])
|
6
|
+
new(dir, ignore).each_file {|entry| yield entry }
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(dir, ignore = [])
|
10
|
+
@base_dir, @ignored = dir, ignore
|
11
|
+
end
|
12
|
+
|
13
|
+
# yields FileInfo object for each non-ignored file in the specified directory
|
14
|
+
def each_file
|
15
|
+
directory_stack << ''
|
16
|
+
while dir = directory_stack.pop
|
17
|
+
scan_directory(dir) { |entry| yield entry }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#######
|
22
|
+
private
|
23
|
+
#######
|
24
|
+
|
25
|
+
attr_reader :base_dir
|
26
|
+
attr_reader :ignored
|
27
|
+
|
28
|
+
def scan_directory(dir_name)
|
29
|
+
Dir.open(File.join(base_dir, dir_name)) do |dir|
|
30
|
+
while entry = dir.read
|
31
|
+
next if entry == '.' || entry == '..' || ignored?(entry)
|
32
|
+
|
33
|
+
stat = File.lstat(File.join(base_dir, dir_name, entry))
|
34
|
+
next if stat.symlink?
|
35
|
+
|
36
|
+
relative_path = File.join(dir_name, entry)
|
37
|
+
|
38
|
+
if stat.directory?
|
39
|
+
directory_stack << relative_path
|
40
|
+
else
|
41
|
+
# strip off the leading / in the relative path
|
42
|
+
yield FileInfo.new(relative_path[1..-1], File.join(base_dir, relative_path), stat)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def directory_stack
|
49
|
+
@directory_stack ||= []
|
50
|
+
end
|
51
|
+
|
52
|
+
def ignored?(filename)
|
53
|
+
ignored.any? {|ignore| File.fnmatch(ignore, filename) }
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/specification'
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
module Awshucks
|
6
|
+
# Add some additional items to Gem::Specification
|
7
|
+
# A Awshucks::Specification adds additional pieces of information the
|
8
|
+
# typical gem specification
|
9
|
+
class Specification
|
10
|
+
|
11
|
+
RUBYFORGE_ROOT = "/var/www/gforge-projects/"
|
12
|
+
|
13
|
+
# user that accesses remote site
|
14
|
+
attr_accessor :remote_user
|
15
|
+
|
16
|
+
# remote host, default 'rubyforge.org'
|
17
|
+
attr_accessor :remote_host
|
18
|
+
|
19
|
+
# name the rdoc main
|
20
|
+
attr_accessor :rdoc_main
|
21
|
+
|
22
|
+
# local directory in development holding the generated rdoc
|
23
|
+
# default 'doc'
|
24
|
+
attr_accessor :local_rdoc_dir
|
25
|
+
|
26
|
+
# remote directory for storing rdoc, default 'doc'
|
27
|
+
attr_accessor :remote_rdoc_dir
|
28
|
+
|
29
|
+
# local directory for coverage report
|
30
|
+
attr_accessor :local_coverage_dir
|
31
|
+
|
32
|
+
# remote directory for storing coverage reports
|
33
|
+
# This defaults to 'coverage'
|
34
|
+
attr_accessor :remote_coverage_dir
|
35
|
+
|
36
|
+
# local directory for generated website, default +site/public+
|
37
|
+
attr_accessor :local_site_dir
|
38
|
+
|
39
|
+
# remote directory relative to +remote_root+ for the website.
|
40
|
+
# website.
|
41
|
+
attr_accessor :remote_site_dir
|
42
|
+
|
43
|
+
# is a .tgz to be created?, default 'true'
|
44
|
+
attr_accessor :need_tar
|
45
|
+
|
46
|
+
# is a .zip to be created, default 'true'
|
47
|
+
attr_accessor :need_zip
|
48
|
+
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
@remote_user = nil
|
52
|
+
@remote_host = "rubyforge.org"
|
53
|
+
|
54
|
+
@rdoc_main = "README"
|
55
|
+
@local_rdoc_dir = "doc"
|
56
|
+
@remote_rdoc_dir = "doc"
|
57
|
+
@local_coverage_dir = "coverage"
|
58
|
+
@remote_coverage_dir = "coverage"
|
59
|
+
@local_site_dir = "site/public"
|
60
|
+
@remote_site_dir = "."
|
61
|
+
|
62
|
+
@need_tar = true
|
63
|
+
@need_zip = true
|
64
|
+
|
65
|
+
@spec = Gem::Specification.new
|
66
|
+
|
67
|
+
yield self if block_given?
|
68
|
+
|
69
|
+
# update rdoc options to take care of the rdoc_main if it is
|
70
|
+
# there, and add a default title if one is not given
|
71
|
+
if not @spec.rdoc_options.include?("--main") then
|
72
|
+
@spec.rdoc_options.concat(["--main", rdoc_main])
|
73
|
+
end
|
74
|
+
|
75
|
+
if not @spec.rdoc_options.include?("--title") then
|
76
|
+
@spec.rdoc_options.concat(["--title","'#{name} -- #{summary}'"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# if this gets set then it overwrites what would be the
|
81
|
+
# rubyforge default. If rubyforge project is not set then use
|
82
|
+
# name. If rubyforge project and name are set, but they are
|
83
|
+
# different then assume that name is a subproject of the
|
84
|
+
# rubyforge project
|
85
|
+
def remote_root
|
86
|
+
if rubyforge_project.nil? or
|
87
|
+
rubyforge_project == name then
|
88
|
+
return RUBYFORGE_ROOT + "#{name}/"
|
89
|
+
else
|
90
|
+
return RUBYFORGE_ROOT + "#{rubyforge_project}/#{name}/"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# rdoc files is the same as what would be generated during gem
|
95
|
+
# installation. That is, everything in the require paths plus
|
96
|
+
# the rdoc_extra_files
|
97
|
+
#
|
98
|
+
def rdoc_files
|
99
|
+
flist = extra_rdoc_files.dup
|
100
|
+
@spec.require_paths.each do |rp|
|
101
|
+
flist << FileList["#{rp}/**/*.rb"]
|
102
|
+
end
|
103
|
+
flist.flatten.uniq
|
104
|
+
end
|
105
|
+
|
106
|
+
# calculate the remote directories
|
107
|
+
def remote_root_location
|
108
|
+
"#{remote_user}@#{remote_host}:#{remote_root}"
|
109
|
+
end
|
110
|
+
|
111
|
+
def remote_rdoc_location
|
112
|
+
remote_root_location + @remote_rdoc_dir
|
113
|
+
end
|
114
|
+
|
115
|
+
def remote_coverage_location
|
116
|
+
remote_root_location + @remote_coverage_dir
|
117
|
+
end
|
118
|
+
|
119
|
+
def remote_site_location
|
120
|
+
remote_root_location + @remote_site_dir
|
121
|
+
end
|
122
|
+
|
123
|
+
# we delegate any other calls to spec
|
124
|
+
def method_missing(method_id,*params,&block)
|
125
|
+
@spec.send method_id, *params, &block
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
# awshucks-generated config file
|
3
|
+
# The default filename is awshucks.yml, but can be overridden.
|
4
|
+
|
5
|
+
# Amazon S3 configuration
|
6
|
+
access_key_id: insert your access key here
|
7
|
+
secret_access_key: insert your secret access key here
|
8
|
+
|
9
|
+
# This is where awshucks will store all of your backed-up files.
|
10
|
+
bucket: bucket name
|
11
|
+
|
12
|
+
# Backup location configurations. Add as many of them as you like.
|
13
|
+
# Currently the only required key is location.
|
14
|
+
|
15
|
+
# For example (replace these with your own):
|
16
|
+
|
17
|
+
photos:
|
18
|
+
location: "~/pictures"
|
19
|
+
|
20
|
+
email:
|
21
|
+
location: "~/mail"
|
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"spec_helper.rb")
|
2
|
+
|
3
|
+
describe Awshucks::CLI, '#execute' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@cli = Awshucks::CLI.new
|
7
|
+
@cmd = mock('pretend command')
|
8
|
+
@cmd.stub!(:command).and_return('pretend')
|
9
|
+
@old_stdout, $stdout = $stdout, StringIO.new
|
10
|
+
@old_stderr, $stderr = $stderr, StringIO.new
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
$stdout = @old_stdout
|
15
|
+
$stderr = @old_stderr
|
16
|
+
end
|
17
|
+
|
18
|
+
it "fails with a help message with empty arguments" do
|
19
|
+
@cli.execute([])
|
20
|
+
$stdout.string.should include("--help")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "loads the configuration from awshucks.yml in the current working directory by default" do
|
24
|
+
config = mock('config')
|
25
|
+
Awshucks::Config.should_receive(:new).with('awshucks.yml').and_return(config)
|
26
|
+
config.stub!(:help_message=)
|
27
|
+
Dir.chdir(dummy_fs_path) do
|
28
|
+
@cli.execute([])
|
29
|
+
@cli.send(:config) # lazily loaded, so force it
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "assigns the main help method to the config object as a way to piggyback it for commands" do
|
34
|
+
config = mock('config')
|
35
|
+
Awshucks::Config.should_receive(:new).with('awshucks.yml').and_return(config)
|
36
|
+
config.should_receive(:help_message=).with(/-h, --help/)
|
37
|
+
Dir.chdir(dummy_fs_path) do
|
38
|
+
@cli.execute([])
|
39
|
+
@cli.send(:config) # lazily loaded, so force it
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "runs the specified subcommand if a command is provided" do
|
44
|
+
@cmd.should_receive(:execute)
|
45
|
+
Awshucks::Command.should_receive(:commands).at_least(1).times.and_return({'pretend' => @cmd})
|
46
|
+
@cli.execute(['pretend'])
|
47
|
+
end
|
48
|
+
|
49
|
+
it "prints an error and exit if a specified subcommand is not found" do
|
50
|
+
Awshucks::Command.should_receive(:parse_and_execute).and_raise(Awshucks::UnknownCommandError.new('pretend'))
|
51
|
+
lambda { @cli.execute(['pretend']) }.should raise_error(SystemExit)
|
52
|
+
$stderr.string.should =~ /could not find.*pretend/i
|
53
|
+
end
|
54
|
+
|
55
|
+
it "prints an error and exit if a subcommand raises an error" do
|
56
|
+
Awshucks::Command.should_receive(:parse_and_execute).and_raise(Awshucks::CommandError.new('pretend error'))
|
57
|
+
lambda { @cli.execute(['pretend']) }.should raise_error(SystemExit)
|
58
|
+
$stderr.string.should =~ /pretend error/
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe Awshucks::CLI, '#execute with no command-line arguments provided' do
|
64
|
+
|
65
|
+
before(:each) do
|
66
|
+
@old_stdout, $stdout = $stdout, StringIO.new
|
67
|
+
@cli = Awshucks::CLI.new
|
68
|
+
@cli.execute([])
|
69
|
+
end
|
70
|
+
|
71
|
+
after(:each) do
|
72
|
+
$stdout = @old_stdout
|
73
|
+
end
|
74
|
+
|
75
|
+
it "prints out a help message to stdout" do
|
76
|
+
$stdout.string.should =~ /-h, --help/
|
77
|
+
end
|
78
|
+
|
79
|
+
it "prints out a list of available commands" do
|
80
|
+
$stdout.string.should =~ / help/
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
describe Awshucks::CLI, '#execute with the -h argument' do
|
86
|
+
|
87
|
+
before(:each) do
|
88
|
+
@old_stdout, $stdout = $stdout, StringIO.new
|
89
|
+
@cli = Awshucks::CLI.new
|
90
|
+
@cli.execute(%w(-h))
|
91
|
+
end
|
92
|
+
|
93
|
+
after(:each) do
|
94
|
+
$stdout = @old_stdout
|
95
|
+
end
|
96
|
+
|
97
|
+
it "prints out a help message to stdout" do
|
98
|
+
$stdout.string.should =~ /-h, --help/
|
99
|
+
end
|
100
|
+
|
101
|
+
it "includes the version string" do
|
102
|
+
$stdout.string.should include("version #{Awshucks::VERSION}")
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
describe Awshucks::CLI, '#execute with the -c argument' do
|
108
|
+
|
109
|
+
before(:each) do
|
110
|
+
@cli = Awshucks::CLI.new
|
111
|
+
end
|
112
|
+
|
113
|
+
it "executes the given command with the specified config" do
|
114
|
+
config = mock('config')
|
115
|
+
Awshucks::Config.should_receive(:new).with('asdf.yml').and_return(config)
|
116
|
+
config.stub!(:help_message=)
|
117
|
+
Awshucks::Command.should_receive(:parse_and_execute)
|
118
|
+
@cli.execute(['-c', 'asdf.yml', 'command'])
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
describe Awshucks::CLI, '.execute' do
|
124
|
+
it "instantiates the CLI and calls execute with ARGV" do
|
125
|
+
@cli = mock('cli')
|
126
|
+
Awshucks::CLI.should_receive(:new).and_return(@cli)
|
127
|
+
@cli.should_receive(:execute).with(ARGV)
|
128
|
+
Awshucks::CLI.execute
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"spec_helper.rb")
|
2
|
+
|
3
|
+
describe Awshucks::Command, '.commands' do
|
4
|
+
|
5
|
+
it "should return a list of commands stored at the class level" do
|
6
|
+
Awshucks::Command.commands.should be_kind_of(Hash)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have the standard commands loaded via the inherited callback" do
|
10
|
+
Awshucks::Command.commands['help'].should == Awshucks::HelpCommand
|
11
|
+
Awshucks::Command.commands['backup'].should == Awshucks::BackupCommand
|
12
|
+
Awshucks::Command.commands['backups'].should == Awshucks::BackupsCommand
|
13
|
+
Awshucks::Command.commands['list'].should == Awshucks::ListCommand
|
14
|
+
Awshucks::Command.commands['new_config'].should == Awshucks::NewConfigCommand
|
15
|
+
Awshucks::Command.commands['reset_metadata_cache'].should == Awshucks::ResetMetadataCacheCommand
|
16
|
+
Awshucks::Command.commands['restore'].should == Awshucks::RestoreCommand
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Awshucks::Command, '.parse_and_execute' do
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
@cmd = mock('command')
|
25
|
+
@config = mock('config')
|
26
|
+
Awshucks::Command.commands['mock'] = @cmd
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should call execute on the command matching the first argument" do
|
30
|
+
@cmd.should_receive(:execute)
|
31
|
+
Awshucks::Command.parse_and_execute(['mock'], @config)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should strip the first argument from the arguments passed in when calling execute" do
|
35
|
+
@cmd.should_receive(:execute).with(['arg', 'arg2'], @config)
|
36
|
+
Awshucks::Command.parse_and_execute(['mock', 'arg', 'arg2'], @config)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should raise an unknown command error if the command isn't one that's registered" do
|
40
|
+
lambda { Awshucks::Command.parse_and_execute(['blahblah'], nil) }.should raise_error(Awshucks::UnknownCommandError)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe Awshucks::Command, '.execute' do
|
45
|
+
it "should instantiate and call execute on the command class" do
|
46
|
+
class MockCommand < Awshucks::Command
|
47
|
+
end
|
48
|
+
|
49
|
+
@mock = mock('dummy command instance')
|
50
|
+
MockCommand.should_receive(:new).and_return(@mock)
|
51
|
+
@mock.should_receive(:execute)
|
52
|
+
|
53
|
+
MockCommand.execute(nil, nil)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe Awshucks::Command, '.option_string, when no custom options are defined' do
|
58
|
+
|
59
|
+
before(:each) do
|
60
|
+
class DummyCommand < Awshucks::Command
|
61
|
+
self.command = 'command name'
|
62
|
+
self.usage = 'usage string'
|
63
|
+
self.description = 'description'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should include usage in the option parser string" do
|
68
|
+
DummyCommand.option_string.should include('usage string')
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should include description in the option parser string" do
|
72
|
+
DummyCommand.option_string.should include('description')
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should state 'no options' in option parser string" do
|
76
|
+
DummyCommand.option_string.should include('No options')
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
describe Awshucks::Command, '.option_string, with custom options defined' do
|
82
|
+
|
83
|
+
before(:each) do
|
84
|
+
class DummyCommand < Awshucks::Command
|
85
|
+
self.command = 'command name'
|
86
|
+
self.usage = 'usage string'
|
87
|
+
self.description = 'description'
|
88
|
+
def custom_options(opts)
|
89
|
+
opts.on('-v', "be verbose")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should include custom options in option parser string if a block was used" do
|
95
|
+
DummyCommand.option_string.should include('Options:')
|
96
|
+
DummyCommand.option_string.should include('be verbose')
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
describe Awshucks::Command, '#parsed_options' do
|
102
|
+
it "should return an OpenStruct by default for use in option definitions" do
|
103
|
+
Awshucks::Command.new.send(:parsed_options).should be_instance_of(OpenStruct)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe Awshucks::Command, '#execute' do
|
108
|
+
it "raises an exception since it's meant to be an abstract method" do
|
109
|
+
lambda {Awshucks::Command.new.execute(nil, nil) }.should raise_error(Awshucks::CommandError)
|
110
|
+
end
|
111
|
+
end
|