excavator 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.
@@ -0,0 +1,107 @@
1
+ require 'excavator'
2
+ module Excavator
3
+ class Runner
4
+
5
+ # Runner specific vars
6
+ attr_accessor :command_paths
7
+ attr_accessor :commands
8
+ attr_reader :current_namespace
9
+
10
+ def initialize
11
+ @namespace = Namespace.new(:default)
12
+ @current_namespace = @namespace
13
+ end
14
+
15
+ def cwd
16
+ Excavator.cwd
17
+ end
18
+
19
+ def namespaces
20
+ @namespaces
21
+ end
22
+
23
+ def namespace
24
+ @namespace
25
+ end
26
+
27
+ def current_namespace
28
+ @current_namespace
29
+ end
30
+
31
+ def in_namespace(name)
32
+ ns = @current_namespace.namespace(name)
33
+ ns = @current_namespace << Excavator.namespace_class.new(name) unless ns
34
+ @current_namespace = ns
35
+ yield
36
+ @current_namespace = ns.parent
37
+ end
38
+
39
+ def clear_commands!
40
+ self.commands = {}
41
+ end
42
+
43
+ def run(*args)
44
+ args.flatten!
45
+
46
+ name = args.delete_at(0)
47
+ load_commands
48
+
49
+ if (name.nil? && args.size == 0) || display_help?(name)
50
+ display_help
51
+ return
52
+ end
53
+
54
+ command = find_command name
55
+ command.execute *args
56
+ end
57
+
58
+ def find_command(cmd)
59
+ *namespaces, command_name = cmd.to_s.split(':').collect {|c| c.to_sym }
60
+ cur_namespace = current_namespace
61
+ namespaces.each do |n|
62
+ cur_namespace = cur_namespace.namespace(n)
63
+ end
64
+
65
+ cur_namespace.command(command_name)
66
+ end
67
+
68
+ def display_help?(command_name)
69
+ ["-h", "-?", "--help", "help"].include?(command_name)
70
+ end
71
+
72
+ def display_help
73
+ table_view = Excavator::TableView.new do |t|
74
+ t.title "#{File.basename($0)} commands:\n"
75
+ t.header "Command"
76
+ t.header "Description"
77
+ t.divider "\t"
78
+
79
+ namespace.commands_and_descriptions.sort.each do |command|
80
+ t.record *command
81
+ end
82
+ end
83
+
84
+ puts table_view
85
+ end
86
+
87
+ def load_commands
88
+ command_paths.each do |path|
89
+ Dir["#{path.to_s}/**/*.rb"].each { |file| load file }
90
+ end
91
+ end
92
+
93
+ def last_command
94
+ @last_command ||= Excavator.command_class.new(
95
+ self, :namespace => current_namespace
96
+ )
97
+ end
98
+
99
+ def clear_last_command!
100
+ @last_command = nil
101
+ end
102
+
103
+ def command_paths
104
+ @command_paths = Excavator.command_paths || [cwd.join("commands")]
105
+ end
106
+ end # Runner
107
+ end
@@ -0,0 +1,90 @@
1
+ require 'excavator'
2
+ module Excavator
3
+ class TableView
4
+ class InvalidDataForHeaders < StandardError; end
5
+
6
+ DEFAULT_DIVIDER = " | "
7
+
8
+ def initialize(options = {})
9
+ @options = options
10
+ @_title = ""
11
+ @_headers = []
12
+ @_records = []
13
+ @col_widths = Hash.new { |hash, key| hash[key] = 0 }
14
+ @divider = options[:divider] || DEFAULT_DIVIDER
15
+
16
+ yield self if block_given?
17
+ end
18
+
19
+ def title(t = nil)
20
+ if t.nil?
21
+ @_title = t
22
+ else
23
+ @_title = t
24
+ end
25
+ end
26
+
27
+ def header(*headers)
28
+ headers.flatten!
29
+
30
+ headers.each do |h|
31
+ index = @_headers.size
32
+ @_headers << h
33
+ @col_widths[h] = h.to_s.size
34
+ end
35
+ end
36
+
37
+ def divider(str)
38
+ @divider = str
39
+ end
40
+
41
+ def record(*args)
42
+ args.flatten!
43
+ if args.size != @_headers.size
44
+ raise InvalidDataForHeaders.new(<<-MSG)
45
+ Number of columns for record (#{args.size}) does not match number
46
+ of headers (#{@_headers.size})
47
+ MSG
48
+ end
49
+ update_column_widths Hash[*@_headers.zip(args).flatten]
50
+ @_records << args
51
+ end
52
+
53
+ def to_s
54
+ out = ""
55
+ out << @_title << "\n" if !@_title.nil? && @_title != ""
56
+
57
+ print_headers out
58
+
59
+ @_records.each_with_index do |record|
60
+ record.each_with_index do |val, i|
61
+ out << column_formats[i] % val
62
+ out << @divider if i != (record.size - 1)
63
+ end
64
+ out << "\n"
65
+ end
66
+ out << "\n"
67
+
68
+ out
69
+ end
70
+
71
+ def update_column_widths(hash)
72
+ hash.each do |key, val|
73
+ @col_widths[key] = val.size if val && val.size > @col_widths[key]
74
+ end
75
+ end
76
+
77
+ def print_headers(out)
78
+ @_headers.each_with_index do |h, i|
79
+ out << column_formats[i] % h
80
+ out << @divider if i != (@_headers.size - 1)
81
+ end
82
+ out << "\n"
83
+ end
84
+
85
+ # Internal
86
+ def column_formats
87
+ @col_widths.collect { |h, width| "%-#{width}s" }
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,3 @@
1
+ module Excavator
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,18 @@
1
+ command :test do
2
+ puts "test command"
3
+ end
4
+
5
+ desc "A command with an argument"
6
+ param :region, :default => "west"
7
+ command :command_with_arg do
8
+ puts params[:region]
9
+ end
10
+
11
+ namespace :first do
12
+ namespace :second do
13
+ command :third do
14
+ puts "third"
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,32 @@
1
+ require 'pathname'
2
+ basedir = Pathname.new(File.dirname(__FILE__)).join("..").expand_path
3
+ $LOAD_PATH.unshift(basedir.join("lib").to_s)
4
+ require 'excavator'
5
+
6
+ gem 'minitest'
7
+ require 'minitest/spec'
8
+ require 'minitest/autorun'
9
+ require 'minitest/mock'
10
+
11
+ require 'ruby-debug'
12
+ Debugger.start
13
+
14
+ module TestHelpers
15
+ def basedir
16
+ Pathname.new(__FILE__).join("..", "..").expand_path
17
+ end
18
+ end
19
+
20
+ # I like #context more than #describe
21
+ alias :context :describe
22
+
23
+ class MiniTest::Spec
24
+ include TestHelpers
25
+ class << self
26
+ # Oh Rails, you have a strangle hold on my conventions ...
27
+ alias :test :it
28
+ alias :setup :before
29
+ alias :teardown :after
30
+ end
31
+ end
32
+
@@ -0,0 +1,75 @@
1
+ require 'test_helper'
2
+ context "Command" do
3
+ include Excavator
4
+
5
+ setup do
6
+ Excavator.reset!
7
+ @runner = Excavator.runner
8
+ end
9
+
10
+ test "execute a command" do
11
+ cmd = Command.new(@runner, :name => "test", :block => proc { puts "test"})
12
+ out, error = capture_io do
13
+ cmd.execute
14
+ end
15
+ assert_match /test/, out
16
+ end
17
+
18
+ test "command arguments available in #params" do
19
+ cmd = Command.new(
20
+ @runner,
21
+ :name => "test",
22
+ :param_definitions => [Param.new(:name)],
23
+ :block => proc { puts params[:name] }
24
+ )
25
+ out, error = capture_io do
26
+ cmd.execute("--name", "hello, world!")
27
+ end
28
+ assert_match /hello, world!/, out
29
+ end
30
+
31
+ test "passing in two named parameters" do
32
+ cmd = Command.new(
33
+ @runner,
34
+ :name => "test",
35
+ :param_definitions => [Param.new(:arg1), Param.new(:arg2)],
36
+ :block => proc { puts "#{params[:arg1]}#{params[:arg2]}" }
37
+ )
38
+ out, error = capture_io do
39
+ cmd.execute("--arg1", "1", "--arg2", "2")
40
+ end
41
+ assert_match /12/, out
42
+ end
43
+
44
+
45
+ test "#execute_with_params runs a command's block" do
46
+ cmd = Command.new(Excavator.runner).tap do |c|
47
+ c.name = "test"
48
+ c.add_param(Param.new(:name))
49
+ c.add_param(Param.new(:server))
50
+ c.block = Proc.new do
51
+ [params[:name], params[:server]]
52
+ end
53
+ end
54
+
55
+ results = cmd.execute_with_params :name => "paydro", :server => "web"
56
+ assert_equal ["paydro", "web"], results
57
+ end
58
+
59
+ test "#execute_with_params throws error when missing param" do
60
+ cmd = Command.new(Excavator.runner).tap do |c|
61
+ c.name = "test"
62
+ c.add_param(Param.new(:name))
63
+ c.add_param(Param.new(:server))
64
+ c.block = Proc.new do
65
+ [params[:name], params[:server]]
66
+ end
67
+ end
68
+
69
+ error = assert_raises MissingParamsError do
70
+ cmd.execute_with_params :name => "paydro"
71
+ end
72
+ assert error.params.include?(:server)
73
+ end
74
+ end # Command
75
+
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+
3
+ context "DSL command creation and execution" do
4
+ include Excavator::DSL
5
+
6
+ setup do
7
+ Excavator.reset!
8
+ @runner = Excavator.runner
9
+ end
10
+
11
+ test "create a command" do
12
+ refute @runner.find_command("test")
13
+ cmd = command(:test) { puts "test" }
14
+ assert cmd = @runner.find_command("test")
15
+ end
16
+
17
+ test "creating command clears out #last_command for a new command" do
18
+ cmd1 = command(:first) {}
19
+ refute_equal cmd1.object_id, @runner.last_command.object_id
20
+ end
21
+
22
+ test "adding a description to a command" do
23
+ desc "test desc"
24
+ command(:test) {}
25
+ assert_equal "test desc", @runner.find_command("test").desc
26
+ end
27
+
28
+ test "create a namespaced command" do
29
+ cmd = nil
30
+ namespace :outer do
31
+ cmd = command(:test) { }
32
+ end
33
+
34
+ assert found_cmd = @runner.find_command("outer:test")
35
+ assert_equal cmd.object_id, found_cmd.object_id
36
+ end
37
+
38
+ test "command has access to it's namespace" do
39
+ cmd = nil
40
+ b = nil
41
+ namespace :a do
42
+ namespace :b do
43
+ cmd = command(:inside) {}
44
+ end
45
+ end
46
+ assert_equal :inside, cmd.name
47
+ assert_equal :b, cmd.namespace.name
48
+ end
49
+ end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+
3
+ context "Environment" do
4
+ include Excavator
5
+ include Excavator::DSL
6
+
7
+ setup do
8
+ Excavator.reset!
9
+ Excavator.command_paths = [
10
+ basedir.join("test", "fixtures", "commands")
11
+ ]
12
+ end
13
+
14
+ test "execute another command" do
15
+ cmd = command(:first) { execute :second }
16
+ command(:second) { "called from second" }
17
+ assert_equal "called from second", cmd.execute
18
+ end
19
+
20
+ test "execute command with params" do
21
+ cmd = command(:run_another_cmd) do
22
+ execute :my_name, :name => 'paydro'
23
+ end
24
+
25
+ param :name
26
+ command(:my_name) { params[:name] }
27
+
28
+ assert_equal "paydro", cmd.execute
29
+ end
30
+
31
+ end # Environment
32
+
33
+ context "Environment#modify" do
34
+ include Excavator
35
+
36
+ module OtherCommands
37
+ def hello
38
+ "world"
39
+ end
40
+ end
41
+
42
+ setup do
43
+ env_class = Class.new(Excavator::Environment)
44
+ Excavator.environment_class = env_class
45
+ @class = env_class
46
+ end
47
+
48
+ teardown do
49
+ Excavator.environment_class = nil
50
+ end
51
+
52
+ test "modify environment with modules" do
53
+ @class.modify OtherCommands
54
+ assert_equal "world", @class.new.hello
55
+ end
56
+
57
+ test "modify environment with a block" do
58
+ @class.modify do
59
+ include OtherCommands
60
+ end
61
+
62
+ assert_equal "world", @class.new.hello
63
+ end
64
+ end