module Scide
# A command to be used in a GNU Screen window. There are several
# command implementations (show command, run command, tail file, etc).
# See under Scide::Commands.
class Command
# The options given to this command. These are built by merging
# global options, project options and window options.
attr_reader :options
# Returns a new command for the given window.
#
# ==== Arguments
# * window - The window in which the command will be used.
# Command options are retrieved from Scide::Window#options. See
# #initialize.
# * contents - The command configuration (String or Hash).
#
# ==== String Initialization
# The string must be in the format COMMAND [CONTENTS].
#
# TYPE is the name of the command class under
# Scide::Commands, in uppercase camelcase. For example, TAIL
# corresponds to Scide::Commands::Tail, MY_COMMAND would
# correspond to Scide::Commands::MyCommand.
#
# CONTENTS is the contents of the command.
#
# ==== Hash Initialization
# The following options can be given:
# * :command => string is the same COMMAND as
# for string initialization above.
# * :contents => string or other is the same CONTENTS
# as for string initialization above. Typically this is only a
# string, but more advanced commands might be initialized with
# arrays or hashes.
def self.resolve window, contents
if contents.kind_of? Hash
resolve_from_hash window, contents
elsif contents.kind_of? String
resolve_from_string window, contents
else
raise ArgumentError, 'command must be a string or a hash'
end
end
# Returns a new command with the given options.
#
# ==== Arguments
# * contents - The contents of the command. Typically this
# is only a string, but more advanced commands might be initialized
# with arrays or hashes. By default, the contents can be retrieved
# as a string with #text_with_options.
# * options - Options that can be used in the string contents
# of the command. See #text_with_options.
def initialize contents, options = {}
# fill text only if it's not already there, in case a subclass does
# some initialization work before calling super
@text ||= contents.to_s
# merge given options to the already initialized ones, if any
@options = (@options || {}).merge options
end
# Returns a representation of this command as a GNU Screen
# configuration fragment.
#
# This default implementation raises an error and must be
# overriden by subclasses.
def to_screen
raise 'Use a subclass'
end
# Returns the text of this command with filtered option placeholders.
#
# ==== Examples
# com_text = 'tail %{tail} -f file.txt -c %{foo}'
# com = Scide::Command.new com_text, :tail => '-n 1000', :foo => 400
#
# com.text_with_options #=> 'tail -n 1000 -f file.txt -c 400'
def text_with_options
@text.dup.tap do |s|
@options.each_pair do |key, value|
s.gsub! /\%\{#{Regexp.escape key}\}/, value.to_s
end
end
end
private
# Returns a new command for the given window. The given
# contents are a hash. See Scide::Command.resolve.
def self.resolve_from_hash window, contents
begin
klass = Scide::Commands.const_get contents[:command].downcase.camelize
klass.new contents[:contents], window.options.dup
rescue NameError => err
raise ArgumentError, "unknown '#{contents[:command]}' command type"
end
end
# Returns a new command for the given window. The given
# contents are a string. See Scide::Command.resolve.
def self.resolve_from_string window, contents
klass_name, text = contents.split /\s+/, 2
begin
klass = Scide::Commands.const_get klass_name.downcase.camelize
klass.new text, window.options.dup
rescue NameError => err
raise ArgumentError, "unknown '#{klass_name}' command type"
end
end
end
# Module containing scide command classes.
module Commands
end
end
# load pre-defined commands
deps_dir = File.join File.dirname(__FILE__), 'commands'
%w( show run tail edit ).each{ |dep| require File.join(deps_dir, dep) }