excavator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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