class String


Rake extension methods for String.
#####################################################################

def ext(newext='')

+ext+ is a user added method for the String class.

is not given, or is the empty string, remove any existing extension.
the string, append the new extension to the end. If the new extension
Replace the file extension with +newext+. If there is no extension on
def ext(newext='')
  return self.dup if ['.', '..'].include? self
  if newext != ''
    newext = (newext =~ /^\./) ? newext : ("." + newext)
  end
  self.chomp(File.extname(self)) << newext
end

def pathmap(spec=nil, &block)


"/path/to/file.txt"

Returns:

}
ext.downcase
"/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext|

For example:

some arbitrary calculation for the replacement.
If the replacement text is '*', then a block may be provided to perform

"bin/org/onestepback/proj/A.class"

returns:

"src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")

For example:

reasonable).
excluded from both the pattern and replacement text (let's keep parsing
used in the replacement text. Curly braces, commas and semi-colons are
Regular expressions may be used for the pattern, and back refs may be

semi-colons (e.g. "%{old,new;src,bin}d").
"%{old,new}d"). Multiple replacement specs should be separated by
after the % character but before the operator letter. (e.g.
by a comma and are enclosed by curly braces. The replacement spec comes
particular part of the path. The pattern and replacement are separated
pattern/replacement argument to perform simple string substitutions on a
Also the %d, %p, %f, %n, %x, and %X operators can take a

'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d'
'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b'

Examples:

|+n+| directories from the right hand side of the path.
starting from the left hand side. If +n+ is negative, return (up to)
number is positive, only return (up to) +n+ directories in the path,
The %d specifier can also have a numeric prefix (e.g. '%2d'). If the

* %% -- A percent sign.
the standard file separator.
* %s -- The alternate file separator if defined, otherwise use
* %X -- Everything *but* the file extension.
is no extension.
* %x -- The file extension of the path. An empty string if there
* %d -- The directory list of the path.
* %n -- The file name of the path without its file extension.
but without any directories.
* %f -- The base file name of the path, with its file extension,
* %p -- The complete path.

recognized:
controls the details of the mapping. The following special patterns are
Map the path according to the given specification. The specification
def pathmap(spec=nil, &block)
  return self if spec.nil?
  result = ''
  spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
    case frag
    when '%f'
      result << File.basename(self)
    when '%n'
      result << File.basename(self).ext
    when '%d'
      result << File.dirname(self)
    when '%x'
      result << File.extname(self)
    when '%X'
      result << self.ext
    when '%p'
      result << self
    when '%s'
      result << (File::ALT_SEPARATOR || File::SEPARATOR)
    when '%-'
      # do nothing
    when '%%'
      result << "%"
    when /%(-?\d+)d/
      result << pathmap_partial($1.to_i)
    when /^%\{([^}]*)\}(\d*[dpfnxX])/
      patterns, operator = $1, $2
      result << pathmap('%' + operator).pathmap_replace(patterns, &block)
    when /^%/
      fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'"
    else
      result << frag
    end
  end
  result
end

def pathmap_explode

Explode a path into individual components. Used by +pathmap+.
def pathmap_explode
  head, tail = File.split(self)
  return [self] if head == self
  return [tail] if head == '.' || tail == '/'
  return [head, tail] if head == '/'
  return head.pathmap_explode + [tail]
end

def pathmap_partial(n)

directories from the back end (right hand side) if +n+ is negative.
front end (left hand side) if +n+ is positive. Include |+n+|
Extract a partial path from the path. Include +n+ directories from the
def pathmap_partial(n)
  dirs = File.dirname(self).pathmap_explode
  partial_dirs =
    if n > 0
      dirs[0...n]
    elsif n < 0
      dirs.reverse[0...-n].reverse
    else
      "."
    end
  File.join(partial_dirs)
end

def pathmap_replace(patterns, &block)

patterns take the form 'pat1,rep1;pat2,rep2...'.
Preform the pathmap replacement operations on the given path. The
def pathmap_replace(patterns, &block)
  result = self
  patterns.split(';').each do |pair|
    pattern, replacement = pair.split(',')
    pattern = Regexp.new(pattern)
    if replacement == '*' && block_given?
      result = result.sub(pattern, &block)
    elsif replacement
      result = result.sub(pattern, replacement)
    else
      result = result.sub(pattern, '')
    end
  end
  result
end