Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Beginnings of refactor for better design
- Loading branch information
Showing
18 changed files
with
386 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,3 +15,4 @@ spec/reports | |
test/tmp | ||
test/version_tmp | ||
tmp | ||
tags |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,16 @@ | ||
require 'escort/version' | ||
|
||
require 'escort/trollop' | ||
require 'escort/error/error' | ||
|
||
require 'escort/setup/option_string_tokenizer' | ||
require 'escort/setup/global_setup_accessor' | ||
require 'escort/setup/common' | ||
require 'escort/setup/command' | ||
require 'escort/setup/global' | ||
|
||
require 'escort/validations' | ||
require 'escort/arguments' | ||
|
||
require 'escort/global_dsl' | ||
require 'escort/dsl' | ||
|
||
require 'escort/command' | ||
require 'escort/app' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,133 @@ | ||
module Escort | ||
class App | ||
include Dsl | ||
include GlobalDsl | ||
|
||
class << self | ||
def create(options_string = nil, &block) | ||
self.new(options_string).tap do |app| | ||
block.call(app) #run the block to get the various sub blocks | ||
begin | ||
app.use_default_options_string_if_needed | ||
app.parse_options # parse the global options | ||
if !app.command_names.nil? && app.command_names.size > 0 | ||
app.current_command.parse_options # parse the current command options | ||
app.execute_before_block(app.current_command.name, app.current_options, app.current_command.current_options, app.arguments) | ||
app.current_command.perform_action(app.current_options, app.arguments, app.valid_with_no_arguments) | ||
else | ||
app.perform_action(app.current_options, app.arguments) | ||
end | ||
exit(0) #everything executed successfully so returning 0 as exit status | ||
rescue => e | ||
app.execute_error_block(e) | ||
#TODO once we have a standard exception hierarchy we can have different exit codes for the various different exceptions here | ||
exit(1) #execution finished unsuccessfully | ||
end | ||
end | ||
app = self.new(Escort::Setup::Global.new(options_string, &block)) | ||
app.has_sub_commands? ? app.execute_active_command : app.execute_global_action | ||
exit(0) | ||
end | ||
end | ||
|
||
attr_reader :current_options | ||
attr_reader :global_setup, :options, :global_setup_accessor | ||
|
||
def initialize(options_string = nil) | ||
@options_string = options_string || ARGV.dup | ||
def initialize(global_setup) | ||
@global_setup = global_setup | ||
@global_setup_accessor = GlobalSetupAccessor.new(global_setup) | ||
end | ||
|
||
def use_default_options_string_if_needed | ||
@default_options_string ||= ['-h'] | ||
if @options_string.size == 0 | ||
@options_string = @default_options_string | ||
end | ||
def has_sub_commands? | ||
!global_setup_accessor.command_names.nil? && global_setup_accessor.command_names.size > 0 | ||
rescue => e | ||
handle_error(e) | ||
end | ||
|
||
def execute_global_action | ||
parse_options | ||
perform_action | ||
rescue => e | ||
handle_error(e) | ||
end | ||
|
||
def arguments | ||
@options_string | ||
def execute_active_command | ||
parse_options # we still need to parse the global options | ||
current_command_setup = Escort::Setup::Command.new(global_setup) | ||
command = Command.new(current_command_setup, self) | ||
command.parse_options | ||
command.perform_action | ||
rescue => e | ||
handle_error(e) | ||
end | ||
|
||
def valid_with_no_arguments | ||
@no_arguments_valid | ||
private | ||
|
||
def handle_error(e) | ||
e.extend(Escort::Error) | ||
raise e | ||
exit(1) #execution finished unsuccessfully | ||
end | ||
|
||
def parse_options | ||
parser = Trollop::Parser.new(&@options_block) | ||
parser.stop_on(@command_names) | ||
@parser = Trollop::Parser.new(&global_setup_accessor.options_block) | ||
@parser.stop_on(global_setup_accessor.command_names) | ||
|
||
@current_options = Trollop::with_standard_exception_handling(parser) do | ||
parser.parse @options_string | ||
@options = Trollop::with_standard_exception_handling(@parser) do | ||
@parser.parse(global_setup_accessor.options_string) | ||
end | ||
Escort::Validations.validate(@current_options, parser, &@validations_block) if @validations_block | ||
#Escort::Validations.validate(@current_options, parser, &@validations_block) if @validations_block | ||
end | ||
|
||
def current_command | ||
return @current_command if @current_command | ||
command_name = @options_string.shift.to_s | ||
command_block = @command_blocks[command_name] | ||
command_description = @command_descriptions[command_name] || nil | ||
raise "No command was passed in" unless command_block | ||
@current_command = Command.new(command_name, command_description, @options_string) | ||
command_block.call(@current_command) | ||
@current_command | ||
def perform_action | ||
#TODO should this even raise, or should it just print an error to stderr and jump to an exit block | ||
raise Escort::ClientError, "Must define a global action block if there are no sub-commands" unless global_setup_accessor.action_block | ||
global_setup_accessor.action_block.call(options, Escort::Arguments.read(global_setup_accessor.arguments)) | ||
#if command_names.nil? || command_names.size == 0 | ||
##TODO what should be raised here (ClientError), should anything | ||
#raise "Must define a global action block if there are no sub-commands" unless @action_block | ||
#raise "Can't define before blocks if there are no sub-commands" if @before_block | ||
#@action_block.call(current_options, Escort::Arguments.read(arguments, @no_arguments_valid)) | ||
#else | ||
##TODO what should be raised here (ClientError), should anything | ||
#raise "Can't define global actions for an app with sub-commands" | ||
#end | ||
end | ||
|
||
def execute_before_block(command_name, global_options, command_options, arguments) | ||
@before_block.call(command_name, global_options, command_options, arguments) if @before_block | ||
end | ||
|
||
def perform_action(current_options, arguments) | ||
if command_names.nil? || command_names.size == 0 | ||
raise "Must define a global action block if there are no sub-commands" unless @action_block | ||
raise "Can't define before blocks if there are no sub-commands" if @before_block | ||
@action_block.call(current_options, Escort::Arguments.read(arguments, @no_arguments_valid)) | ||
else | ||
raise "Can't define global actions for an app with sub-commands" | ||
end | ||
end | ||
|
||
def execute_error_block(error) | ||
@error_block ? @error_block.call(error) : (raise error) | ||
end | ||
|
||
|
||
|
||
|
||
|
||
|
||
#def arguments | ||
#@options_string | ||
#end | ||
|
||
#def valid_with_no_arguments | ||
#@no_arguments_valid | ||
#end | ||
|
||
#def parse_options | ||
#parser = Trollop::Parser.new(&@options_block) | ||
#parser.stop_on(@command_names) | ||
|
||
#@current_options = Trollop::with_standard_exception_handling(parser) do | ||
#parser.parse @options_string | ||
#end | ||
#Escort::Validations.validate(@current_options, parser, &@validations_block) if @validations_block | ||
#end | ||
|
||
#def current_command | ||
#return @current_command if @current_command | ||
#command_name = @options_string.shift.to_s | ||
#command_block = @command_blocks[command_name] | ||
#command_description = @command_descriptions[command_name] || nil | ||
##TODO what should be raised here (UserError), should anything | ||
#raise "No command was passed in" unless command_block | ||
#@current_command = Command.new(command_name, command_description, @options_string) | ||
#command_block.call(@current_command) | ||
#@current_command | ||
#end | ||
|
||
#def execute_before_block(command_name, global_options, command_options, arguments) | ||
#@before_block.call(command_name, global_options, command_options, arguments) if @before_block | ||
#end | ||
|
||
#def perform_action(current_options, arguments) | ||
#if command_names.nil? || command_names.size == 0 | ||
##TODO what should be raised here (ClientError), should anything | ||
#raise "Must define a global action block if there are no sub-commands" unless @action_block | ||
#raise "Can't define before blocks if there are no sub-commands" if @before_block | ||
#@action_block.call(current_options, Escort::Arguments.read(arguments, @no_arguments_valid)) | ||
#else | ||
##TODO what should be raised here (ClientError), should anything | ||
#raise "Can't define global actions for an app with sub-commands" | ||
#end | ||
#end | ||
|
||
#def execute_error_block(error) | ||
##TODO make sure we tag the error here if we're going to re-raise it | ||
#@error_block ? @error_block.call(error) : (raise error) | ||
#end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
module Escort | ||
CLIENT_ERROR_EXIT_CODE = 2 | ||
#module to tag all exceptions coming out of Escort with | ||
module Error | ||
end | ||
|
||
#all our exceptions will supported nesting other exceptions | ||
#also all our exception will be a kind_of? Escort::Error | ||
class BaseError < StandardError | ||
include Error | ||
attr_reader :original | ||
|
||
def initialize(msg, original=$!) | ||
super(msg) | ||
@original = original | ||
end | ||
end | ||
|
||
#user did something invalid | ||
class UserError < BaseError | ||
end | ||
|
||
#for errors with escort itself | ||
class InternalError < BaseError | ||
end | ||
|
||
#for errors with how escort is being used | ||
class ClientError < BaseError | ||
end | ||
|
||
#a dependency is temporarily unavailable | ||
class TransientError < BaseError | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.