class Grizzled::String::Template::UnixShellStringTemplate

A string template that uses the Unix shell-like syntax +${varname}+ (or +$varname+) for variable references. A variable's name typically consists of alphanumerics and underscores, but is controlled by the a supplied regular expression. To include a literal “$” in a string, escape it with a backslash.

For this class, the general form of a variable reference is:

${varname?default}

The +?default+ suffix is optional and specifies a default value to be used if the variable has no value.

A shorthand form of a variable reference is:

$varname

The default capability is not available in the shorthand form.

Constants

ESCAPED_DOLLAR
ESCAPED_DOLLAR_PLACEHOLDER

Public Class Methods

new(resolver, options={}) click to toggle source

Initialize a new UnixShellStringTemplate. Supports various hash options.

Parameters:

resolver

A hash-like object that can take a variable name (via the +[]+ function) and resolve its value, returning the value (which is converted to string) or nil.

options

hash of options. See below.

Options:

:safe

true for a safe template that substitutes a blank string for a non-existent variable, instead of throwing an exception. Defaults to true.

:var_pattern

Regular expression pattern (as a string, not a Regexp object) to match a variable name. Defaults to “[A-Za-z0-9_]+”

# File lib/grizzled/string/template.rb, line 209
def initialize(resolver, options={})
  super(resolver, options)
  var_re = options.fetch(:var_pattern, "[A-Za-z0-9_]+")
  @long_var_regexp = %r{\$\{(#{var_re})(\?[^\}]*)?\}}
  @short_var_regexp = %r{\$(#{var_re})}
end

Public Instance Methods

find_variable_ref(s) click to toggle source

Parse the location of the first variable in the string. Subclasses should override this method.

Parameters:

s

the string

Returns a Variable object, or nil.

# File lib/grizzled/string/template.rb, line 275
def find_variable_ref(s)

  def handle_long_match(m)
    name = m[1]
    if m[2].nil?
      default = nil
    else
      # Pull off the "?"
      default = m[2][1..-1]
    end

    Variable.new(m.begin(0), m.end(0), name, default)
  end

  def handle_no_long_match(s)
    m = @short_var_regexp.match(s)
    if m.nil?
      nil
    else
      Variable.new(m.begin(0), m.end(0), m[1], nil)
    end
  end

  m = @long_var_regexp.match(s)
  if m.nil?
    handle_no_long_match(s)
  else
    handle_long_match(m)
  end
end
handle_long_match(m) click to toggle source
# File lib/grizzled/string/template.rb, line 277
def handle_long_match(m)
  name = m[1]
  if m[2].nil?
    default = nil
  else
    # Pull off the "?"
    default = m[2][1..-1]
  end

  Variable.new(m.begin(0), m.end(0), name, default)
end
handle_match(m, s) click to toggle source
# File lib/grizzled/string/template.rb, line 239
def handle_match(m, s)
  if (m[1].length % 2) == 0
    # Odd number of backslashes before "$", including
    # the one with the dollar token (group 2). Valid escape.

    b = m.begin(0)
    start = (b == 0 ? "" : s[0..(b-1)])
    start + ESCAPED_DOLLAR_PLACEHOLDER + pre_sub(s[m.end(0)..-1])
  else
    # Even number of backslashes before "$", including the one
    # with the dollar token (group 2). Not an escape.
    s
  end
end
handle_no_long_match(s) click to toggle source
# File lib/grizzled/string/template.rb, line 289
def handle_no_long_match(s)
  m = @short_var_regexp.match(s)
  if m.nil?
    nil
  else
    Variable.new(m.begin(0), m.end(0), m[1], nil)
  end
end
pre_sub(s) click to toggle source

Kludge to handle escaped “$”. Temporarily replace it with something highly unlikely to be in the string. Then, put a single “$” in its place, after the substitution. Must be sure to handle even versus odd number of backslash characters.

# File lib/grizzled/string/template.rb, line 237
def pre_sub(s)

  def handle_match(m, s)
    if (m[1].length % 2) == 0
      # Odd number of backslashes before "$", including
      # the one with the dollar token (group 2). Valid escape.

      b = m.begin(0)
      start = (b == 0 ? "" : s[0..(b-1)])
      start + ESCAPED_DOLLAR_PLACEHOLDER + pre_sub(s[m.end(0)..-1])
    else
      # Even number of backslashes before "$", including the one
      # with the dollar token (group 2). Not an escape.
      s
    end
  end

  # Check for an escaped "$"
  m = ESCAPED_DOLLAR.match(s)
  if (m)
    handle_match(m, s)
  else
    s
  end
end
substitute(s) click to toggle source

Replace all variable references in the given string. Variable references are recognized per the regular expression passed to the constructor. If a referenced variable is not found in the resolver, this method either:

  • throws a VariableNotFoundException (if safe is false).

  • substitutes an empty string (if safe is true)

Recursive references are supported (but beware of infinite recursion).

Parameters:

s

the string in which to replace variable references

Returns the substituted result.

# File lib/grizzled/string/template.rb, line 231
def substitute(s)
  # Kludge to handle escaped "$". Temporarily replace it with
  # something highly unlikely to be in the string. Then, put a single
  # "$" in its place, after the substitution. Must be sure to handle
  # even versus odd number of backslash characters.

  def pre_sub(s)

    def handle_match(m, s)
      if (m[1].length % 2) == 0
        # Odd number of backslashes before "$", including
        # the one with the dollar token (group 2). Valid escape.

        b = m.begin(0)
        start = (b == 0 ? "" : s[0..(b-1)])
        start + ESCAPED_DOLLAR_PLACEHOLDER + pre_sub(s[m.end(0)..-1])
      else
        # Even number of backslashes before "$", including the one
        # with the dollar token (group 2). Not an escape.
        s
      end
    end

    # Check for an escaped "$"
    m = ESCAPED_DOLLAR.match(s)
    if (m)
      handle_match(m, s)
    else
      s
    end
  end

  s2 = super(pre_sub(s))
  s2.gsub(ESCAPED_DOLLAR_PLACEHOLDER, '$')
end