cj/opal-webpack

View on GitHub
lib/compiler_patches/pathname.rb

Summary

Maintainability
D
1 day
Test Coverage
class Pathname
  # Backports from opal 0.10
  unless Pathname.method_defined?(:+) && Pathname.method_defined?(:join) && Pathname('.').join('./tree').to_s == 'tree'
    SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/

    # https://github.com/opal/opal/pull/1430 - included in Opal 0.10
    def initialize(path)
      if Pathname === path
        @path = path.path.to_s
      elsif path.respond_to?(:to_path)
        @path = path.to_path
      elsif path.is_a?(String)
        @path = path
      elsif path.nil?
        raise TypeError, 'no implicit conversion of nil into String'
      else
        raise TypeError, "no implicit conversion of #{path.class} into String"
      end
      raise ArgumentError if @path == "\0"
    end

    # https://github.com/opal/opal/pull/1430 - included in Opal 0.10
    def absolute?
      !relative?
    end

    # https://github.com/opal/opal/pull/1430 - included in Opal 0.10
    def relative?
      path = @path
      while r = chop_basename(path)
        path, = r
      end
      path == ''
    end

    # https://github.com/opal/opal/pull/1430 - included in Opal 0.10
    def chop_basename(path) # :nodoc:
      base = File.basename(path)
      # ruby uses /^#{SEPARATOR_PAT}?$/o but having issues with interpolation
      if Regexp.new("^#{Pathname::SEPARATOR_PAT.source}?$") =~ base
        return nil
      else
        return path[0, path.rindex(base)], base
      end
    end

    # https://github.com/opal/opal/pull/1430 - included in Opal 0.10
    def +(other)
      other = Pathname.new(other) unless Pathname === other
      Pathname.new(plus(@path, other.to_s))
    end

    # https://github.com/opal/opal/pull/1430 - included in Opal 0.10
    def plus(path1, path2) # -> path # :nodoc:
      prefix2 = path2
      index_list2 = []
      basename_list2 = []
      while r2 = chop_basename(prefix2)
        prefix2, basename2 = r2
        index_list2.unshift prefix2.length
        basename_list2.unshift basename2
      end
      return path2 if prefix2 != ''
      prefix1 = path1
      while true
        while !basename_list2.empty? && basename_list2.first == '.'
          index_list2.shift
          basename_list2.shift
        end
        break unless r1 = chop_basename(prefix1)
        prefix1, basename1 = r1
        next if basename1 == '.'
        if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
          prefix1 = prefix1 + basename1
          break
        end
        index_list2.shift
        basename_list2.shift
      end
      r1 = chop_basename(prefix1)
      if !r1 && /#{SEPARATOR_PAT}/o =~ File.basename(prefix1)
        while !basename_list2.empty? && basename_list2.first == '..'
          index_list2.shift
          basename_list2.shift
        end
      end
      if !basename_list2.empty?
        suffix2 = path2[index_list2.first..-1]
        r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
      else
        r1 ? prefix1 : File.dirname(prefix1)
      end
    end

    # https://github.com/opal/opal/pull/1430 - included in Opal 0.10
    def join(*args)
      return self if args.empty?
      result = args.pop
      result = Pathname.new(result) unless Pathname === result
      return result if result.absolute?
      args.reverse_each {|arg|
        arg = Pathname.new(arg) unless Pathname === arg
        result = arg + result
        return result if result.absolute?
      }
      self + result
    end
  end

  # Fixed in Opal 0.10
  if `Opal.normalize === undefined`
    def cleanpath
      %x{
        var path = #@path;
        var parts, part, new_parts = [], SEPARATOR = '/';

        if (Opal.current_dir !== '.') {
          path = Opal.current_dir.replace(/\/*$/, '/') + path;
        }

        path = path.replace(/\.(rb|opal|js)$/, '');
        parts = path.split(SEPARATOR);

        for (var i = 0, ii = parts.length; i < ii; i++) {
          part = parts[i];
          if (part === '') continue;
          (part === '..') ? new_parts.pop() : new_parts.push(part)
        }

        return new_parts.join(SEPARATOR);
      }
    end
  end

  # https://github.com/opal/opal/pull/1408 - pending
  unless Pathname.method_defined?(:entries)
    def entries
      Dir.entries(@path).map {|f| self.class.new(f) }
    end
  end

  # these methods were all implemented togther in 0.10
  unless Pathname.method_defined?(:expand_path)
    def expand_path
      File.expand_path @path
    end

    def split
      [ dirname, basename ]
    end

    def dirname
      Pathname.new(File.dirname(@path))
    end

    def basename
      Pathname.new(File.basename(@path))
    end

    def directory?
      File.directory?(@path)
    end

    def extname
      File.extname(@path)
    end

    def <=>(other)
      `self.path > other.path ? 1 : (self.path < other.path ? -1 : 0)`
    end

    alias eql? ==
    alias === ==
  end

  # not yet in 0.10
  unless Pathname.method_defined?(:relative_path_from)
    SAME_PATHS = if File::FNM_SYSCASE.nonzero?
      # Avoid #zero? here because #casecmp can return nil.
      proc {|a, b| a.casecmp(b) == 0}
    else
      proc {|a, b| a == b}
    end

    def relative_path_from(base_directory)
      dest_directory = self.cleanpath.to_s
      base_directory = base_directory.cleanpath.to_s
      dest_prefix = dest_directory
      dest_names = []
      while r = chop_basename(dest_prefix)
        dest_prefix, basename = r
        dest_names.unshift basename if basename != '.'
      end
      base_prefix = base_directory
      base_names = []
      while r = chop_basename(base_prefix)
        base_prefix, basename = r
        base_names.unshift basename if basename != '.'
      end
      unless SAME_PATHS[dest_prefix, base_prefix]
        raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
      end
      while !dest_names.empty? &&
            !base_names.empty? &&
            SAME_PATHS[dest_names.first, base_names.first]
        dest_names.shift
        base_names.shift
      end
      if base_names.include? '..'
        raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
      end
      base_names.fill('..')
      relpath_names = base_names + dest_names
      if relpath_names.empty?
        Pathname.new('.')
      else
        Pathname.new(File.join(*relpath_names))
      end
    end
  end
end