232 lines
6.2 KiB
Ruby
Executable File
232 lines
6.2 KiB
Ruby
Executable File
#
|
|
# environment.rb
|
|
# Project Environment Table Class
|
|
#
|
|
# Author:: David Muir <david.muir@rockstarnorth.com>
|
|
# Date:: 8 February 2008
|
|
#
|
|
|
|
module Pipeline
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
# Exception raised for any errors within the Environment class occurs.
|
|
#
|
|
class EnvironmentException < Exception; end
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
# Environment symbol table implementation. Essentially just a nice wrapper
|
|
# around Ruby's Hash.
|
|
#
|
|
# Internally the symbol_table does not use the ENVIRONMENT_PREFIX.
|
|
#
|
|
# Symbols added to the environment automatically declare publically
|
|
# readable member variables with the same name as the variable. This
|
|
# allows speedy lookup if you know the name of the environment variable.
|
|
# A NameError exception will be raised by Ruby however if the variable is
|
|
# not available.
|
|
#
|
|
# == Example Usage
|
|
#
|
|
# env = Pipeline::Environment.new()
|
|
# env.add( "testvar1", "**testvalue1**" )
|
|
# env.add( "testvar2", "&&testvalue2&&" )
|
|
# env.list
|
|
# env.testvar1 => "**testvalue1**"
|
|
# env.testvar2 => "&&testvalue2&&"
|
|
#
|
|
class Environment
|
|
|
|
protected
|
|
|
|
attr_reader :symbol_table
|
|
|
|
# If any additional member variables are added to this class, ensure you
|
|
# add their name to this list, otherwise bad things will happen in the
|
|
# unlikely event a user attempts to get the environment to store such a
|
|
# variable.
|
|
DISALLOWED_VARS = [ 'symbol_table', 'symbol_stack' ]
|
|
|
|
public
|
|
|
|
#---------------------------------------------------------------------
|
|
# Constants
|
|
#---------------------------------------------------------------------
|
|
|
|
ENVIRONMENT_PREFIX = '$'
|
|
|
|
#---------------------------------------------------------------------
|
|
# Methods
|
|
#---------------------------------------------------------------------
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
# Class constructor, initialising a new Environment object with an
|
|
# empty symbol table.
|
|
#
|
|
def initialize( )
|
|
|
|
@symbol_table = Hash.new()
|
|
@symbol_stack = []
|
|
@symbol_stack << @symbol_table
|
|
end
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
# Returns the value of the specified environment variable name.
|
|
#
|
|
def lookup( varname )
|
|
|
|
# Return variable value if we have it.
|
|
return @symbol_table[varname] unless !@symbol_table[varname]
|
|
|
|
# Otherwise throw an exception.
|
|
raise EnvironmentException.new( "Environment has no definition for #{varname}." )
|
|
end
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
# Returns a new string with any environment variables having their
|
|
# actual value substituted in place.
|
|
#
|
|
# Since the subst string may contain new symbols requiring further substitution
|
|
# set exhaustive to true to make sure they are replaced. But DONT make such things
|
|
# iterate forever :) - I should probably find a way to prevent this. - DW
|
|
#
|
|
def subst( string, exhaustive = false )
|
|
throw ArgumentError.new( "Invalid String to substitute (#{string}, #{string.class})." ) \
|
|
unless ( string.is_a?( String ) )
|
|
|
|
return nil if ( nil == string )
|
|
|
|
newstring = string.dup
|
|
|
|
if exhaustive then
|
|
loop do
|
|
replaced = false
|
|
@symbol_table.each do |varname, value|
|
|
|
|
realVarname = "$(#{varname})"
|
|
result = newstring.gsub!( realVarname, value )
|
|
replaced = true if (not result.nil?)
|
|
end
|
|
break if not replaced
|
|
end
|
|
else
|
|
@symbol_table.each do |varname, value|
|
|
|
|
realVarname = "$(#{varname})"
|
|
newstring.gsub!( realVarname, value )
|
|
end
|
|
end
|
|
|
|
newstring
|
|
end
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
# Add a new or replace an existing, environment variable definition in
|
|
# our symbol table.
|
|
#
|
|
# == References
|
|
#
|
|
# http://www.pullmonkey.com/2008/1/6/convert-a-ruby-hash-into-a-class-object
|
|
#
|
|
def add( varname, value )
|
|
throw EnvironmentException.new( "Environment \"#{varname}\" cannot contain variables resolving to nil." ) \
|
|
unless ( nil != value )
|
|
throw EnvironmentException.new( "Environment cannot contain a variable called \"#{varname}\"." ) \
|
|
if ( DISALLOWED_VARS.include?( varname ) )
|
|
|
|
@symbol_table[varname] = value
|
|
syminst = :"@#{varname}"
|
|
sym = :"#{varname}"
|
|
self.instance_variable_set( syminst, value )
|
|
self.class.send( :define_method, sym, proc { self.instance_variable_get( syminst ) } )
|
|
end
|
|
|
|
#
|
|
# Clear all environment variables.
|
|
#
|
|
def clear( )
|
|
|
|
@symbol_table.clear()
|
|
|
|
# Clear any created instance variables
|
|
self.instance_variables.each do |var|
|
|
next if ( DISALLOWED_VARS.include?( var.tr( '@', '' ) ) )
|
|
self.instance_variable_set( var, nil )
|
|
end
|
|
end
|
|
|
|
#
|
|
# Return the number of variables we have currently defined.
|
|
#
|
|
def count
|
|
|
|
@symbol_table.size()
|
|
end
|
|
|
|
#
|
|
# Push a new symbol table onto the stack.
|
|
#
|
|
def push
|
|
@symbol_stack.push( @symbol_table.clone() )
|
|
@symbol_table = @symbol_stack[@symbol_stack.size - 1]
|
|
end
|
|
|
|
#
|
|
# Pop a symbol table from the stack and correct the @symbol_table
|
|
# reference to ensure we point to the top of the stack.
|
|
#
|
|
def pop
|
|
|
|
@symbol_stack.pop()
|
|
# Update to point to top of symbol_stack
|
|
@symbol_table = @symbol_stack[@symbol_stack.size - 1]
|
|
end
|
|
|
|
#
|
|
# Pretty print listing of symbol table to stdout for debugging.
|
|
#
|
|
def list( )
|
|
|
|
indent = @symbol_stack.size - 1
|
|
@symbol_stack.reverse_each do |sym|
|
|
print_symbol_table( sym, indent, "\t" )
|
|
indent -= 1
|
|
end
|
|
end
|
|
|
|
#---------------------------------------------------------------------
|
|
# Private
|
|
#---------------------------------------------------------------------
|
|
private
|
|
|
|
def print_symbol_table( table, indent = 0, indent_char = "\t" )
|
|
puts ""
|
|
indent.times do print indent_char; end
|
|
print "Environment Listing (depth: #{indent}):\n"
|
|
indent.times do print indent_char; end
|
|
print "---------------------------------------\n"
|
|
table.each do |varname, value|
|
|
|
|
indent.times do print indent_char; end
|
|
print " #{varname} => #{value}\n"
|
|
end
|
|
indent.times do print indent_char; end
|
|
print "---------------------------------------\n"
|
|
end
|
|
end
|
|
|
|
end # Pipeline module
|
|
|
|
# End of environment.rb
|