class File

def self.basename(path)

def self.basename(path)
  (offset = path.rindex SEPARATOR) ? path[(offset + 1)..-1] : path
end

def self.dirname(path)

def self.dirname(path)
  (offset = path.rindex SEPARATOR) ? path[0..(offset - 1)] : '.'
end

def self.expand_path(path)

def self.expand_path(path)
  path
end

def self.extname(path)

def self.extname(path)
  return '' if path.nil_or_empty?
  last_dot_idx = path[1..-1].rindex('.')
  last_dot_idx.nil? ? '' : path[(last_dot_idx + 1)..-1]
end

def self.file?(path)

TODO use XMLHttpRequest HEAD request unless in local file mode
def self.file?(path)
  true
end

def self.join(*paths)

def self.join(*paths)
  paths * SEPARATOR
end

def self.read(path)

def self.read(path)
  case JAVASCRIPT_PLATFORM
  when 'node'
    %x(return require('fs').readFileSync(path, 'utf8');)
  when 'java-nashorn'
    %x(
      var Paths = Java.type('java.nio.file.Paths');
      var Files = Java.type('java.nio.file.Files');
      var lines = Files.readAllLines(Paths.get(path), Java.type('java.nio.charset.StandardCharsets').UTF_8);
      var data = [];
      lines.forEach(function(line) { data.push(line); });
      return data.join("\n");
    )
  #when 'java-rhino'
  when 'browser'
    %x(
      var data = '';
      var status = -1;
      try {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', path, false);
        xhr.addEventListener('load', function() {
          status = this.status;
          // status is 0 for local file mode (i.e., file://)
          if (status == 0 || status == 200) {
            data = this.responseText;
          }
        });
        xhr.overrideMimeType('text/plain');
        xhr.send();
      }
      catch (e) {
        status = 0;
      }
      // assume that no data in local file mode means it doesn't exist
      if (status == 404 || (status == 0 && data == '')) {
        throw #{IOError.new `'No such file or directory: ' + path`};
      }
      return data;
    )
  # NOTE we're assuming standalone is SpiderMonkey
  when 'standalone'
    %x(return read(path);)
  else
    ''
  end
end

def each_line(separator = $/, &block)

def each_line(separator = $/, &block)
  if @eof
    return block_given? ? self : [].to_enum
  end
  if block_given?
    lines = File.read(@path)
    %x(
      self.eof = false;
      self.lineno = 0; 
      var chomped  = #{lines.chomp},
          trailing = lines.length != chomped.length,
          splitted = chomped.split(separator);
      for (var i = 0, length = splitted.length; i < length; i++) {
        self.lineno += 1;
        if (i < length - 1 || trailing) {
          #{yield `splitted[i] + separator`};
        }
        else {
          #{yield `splitted[i]`};
        }
      }
      self.eof = true;
    )
    self
  else
    read.each_line
  end
end

def initialize(path, mode = 'r')

def initialize(path, mode = 'r')
  @path = path
  @contents = nil
  @eof = false
  @lineno = 0
end

def read

def read
  if @eof
    ''
  else
    res = File.read(@path)
    @eof = true
    @lineno = res.size
    res
  end
end