Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9eaa1bd2ba88
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: bc7036afa72e
Choose a head ref
  • 7 commits
  • 3 files changed
  • 2 contributors

Commits on Sep 3, 2016

  1. fix File.dirname with backslashes in unix

    Daniel Smith committed Sep 3, 2016

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    aef4bad View commit details

Commits on Sep 24, 2016

  1. Merge remote-tracking branch 'upstream/master' into dirname-with-back…

    …slash-on-unix
    Daniel Smith committed Sep 24, 2016
    Copy the full SHA
    db355da View commit details
  2. Fix File.dirname on Windows (including UNC)

    Daniel Smith committed Sep 24, 2016
    Copy the full SHA
    f20829c View commit details

Commits on Oct 8, 2016

  1. Remove jruby deviation from File.split spec

    Daniel Smith committed Oct 8, 2016
    Copy the full SHA
    3eb2550 View commit details

Commits on Oct 23, 2016

  1. use SEPARATOR and ALT_SEPARATOR in File.basename

    Daniel Smith committed Oct 23, 2016
    Copy the full SHA
    580a2e6 View commit details
  2. Fix basename with mixed slashes on windows

    Daniel Smith committed Oct 23, 2016
    Copy the full SHA
    5f2cced View commit details

Commits on Nov 6, 2016

  1. Merge pull request #4177 from jellymann/dirname-with-backslash-on-unix

    Fix issues with File.dirname
    enebo authored Nov 6, 2016
    Copy the full SHA
    bc7036a View commit details
Showing with 90 additions and 24 deletions.
  1. +71 −24 core/src/main/java/org/jruby/RubyFile.java
  2. +14 −0 spec/ruby/core/file/basename_spec.rb
  3. +5 −0 spec/ruby/core/file/dirname_spec.rb
95 changes: 71 additions & 24 deletions core/src/main/java/org/jruby/RubyFile.java
Original file line number Diff line number Diff line change
@@ -509,6 +509,15 @@ public IRubyObject inspect() {
@JRubyMethod(required = 1, optional = 1, meta = true)
public static IRubyObject basename(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
final String separator = runtime.getClass("File").getConstant("SEPARATOR").toString();
final char separatorChar = separator.charAt(0);
String altSeparator = null;
char altSeparatorChar = '\0';
final IRubyObject rbAltSeparator = runtime.getClass("File").getConstant("ALT_SEPARATOR");
if (rbAltSeparator != context.nil) {
altSeparator = rbAltSeparator.toString();
altSeparatorChar = altSeparator.charAt(0);
}

RubyString origString = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[0]));
Encoding origEncoding = origString.getEncoding();
@@ -542,16 +551,16 @@ public static IRubyObject basename(ThreadContext context, IRubyObject recv, IRub
}
}

while (name.length() > 1 && name.charAt(name.length() - 1) == '/') {
while (name.length() > 1 && (name.charAt(name.length() - 1) == separatorChar || (altSeparator != null && name.charAt(name.length() - 1) == altSeparatorChar))) {
name = name.substring(0, name.length() - 1);
}

// Paths which end in "/" or "\\" must be stripped off.
// Paths which end in File::SEPARATOR or File::ALT_SEPARATOR must be stripped off.
int slashCount = 0;
int length = name.length();
for (int i = length - 1; i >= 0; i--) {
char c = name.charAt(i);
if (c != '/' && c != '\\') {
if (c != separatorChar && (altSeparator == null || c != altSeparatorChar)) {
break;
}
slashCount++;
@@ -560,13 +569,12 @@ public static IRubyObject basename(ThreadContext context, IRubyObject recv, IRub
name = name.substring(0, name.length() - slashCount);
}

int index = name.lastIndexOf('/');
if (index == -1) {
// XXX actually only on windows...
index = name.lastIndexOf('\\');
int index = name.lastIndexOf(separatorChar);
if (altSeparator != null) {
index = Math.max(index, name.lastIndexOf(altSeparatorChar));
}

if (!name.equals("/") && index != -1) {
if (!(name.equals(separator) || (altSeparator != null && name.equals(altSeparator))) && index != -1) {
name = name.substring(index + 1);
}

@@ -651,32 +659,57 @@ public static IRubyObject dirname(ThreadContext context, IRubyObject recv, IRuby

static Pattern PROTOCOL_PATTERN = Pattern.compile(URI_PREFIX_STRING + ".*");
public static String dirname(ThreadContext context, String jfilename) {
String name = jfilename.replace('\\', '/');
final Ruby runtime = context.runtime;
final String separator = runtime.getClass("File").getConstant("SEPARATOR").toString();
final char separatorChar = separator.charAt(0);
String altSeparator = null;
char altSeparatorChar = '\0';
final IRubyObject rbAltSeparator = runtime.getClass("File").getConstant("ALT_SEPARATOR");
if (rbAltSeparator != context.nil) {
altSeparator = rbAltSeparator.toString();
altSeparatorChar = altSeparator.charAt(0);
}
String name = jfilename;
if (altSeparator != null) {
name = jfilename.replace(altSeparator, separator);
}
int minPathLength = 1;
boolean trimmedSlashes = false;

boolean startsWithSeparator = false;

if (!name.isEmpty()) {
startsWithSeparator = name.charAt(0) == separatorChar;
}

boolean startsWithUNCOnWindows = Platform.IS_WINDOWS && startsWith(name, separatorChar, separatorChar);

if (startsWithUNCOnWindows) {
minPathLength = 2;
}

boolean startsWithDriveLetterOnWindows = startsWithDriveLetterOnWindows(name);

if (startsWithDriveLetterOnWindows) {
minPathLength = 3;
}

// jar like paths
if (name.contains(".jar!/")) {
int start = name.indexOf("!/") + 1;
if (name.contains(".jar!" + separator)) {
int start = name.indexOf("!" + separator) + 1;
String path = dirname(context, name.substring(start));
if (path.equals(".") || path.equals("/")) path = "";
if (path.equals(".") || path.equals(separator)) path = "";
return name.substring(0, start) + path;
}
// address all the url like paths first
if (PROTOCOL_PATTERN.matcher(name).matches()) {
int start = name.indexOf(":/") + 2;
int start = name.indexOf(":" + separator) + 2;
String path = dirname(context, name.substring(start));
if (path.equals(".")) path = "";
return name.substring(0, start) + path;
}

while (name.length() > minPathLength && name.charAt(name.length() - 1) == '/') {
while (name.length() > minPathLength && name.charAt(name.length() - 1) == separatorChar) {
trimmedSlashes = true;
name = name.substring(0, name.length() - 1);
}
@@ -691,7 +724,7 @@ public static String dirname(ThreadContext context, String jfilename) {
}
} else {
//TODO deal with UNC names
int index = name.lastIndexOf('/');
int index = name.lastIndexOf(separator);

if (index == -1) {
if (startsWithDriveLetterOnWindows) {
@@ -701,7 +734,7 @@ public static String dirname(ThreadContext context, String jfilename) {
}
}
if (index == 0) {
return "/";
return jfilename.substring(0, 1);
}

if (startsWithDriveLetterOnWindows && index == 2) {
@@ -710,24 +743,38 @@ public static String dirname(ThreadContext context, String jfilename) {
index++;
}

if (startsWith(jfilename, '\\', '\\')) {
index = jfilename.length();
String[] split = jfilename.split(Pattern.quote("\\"));
if (split[ split.length - 1 ].indexOf('.') > -1) {
index = jfilename.lastIndexOf('\\');
if (startsWithUNCOnWindows) {
index = jfilename.length();
String[] split = name.split(Pattern.quote(separator));
int pathSectionCount = 0;
for (int i = 0; i < split.length; i++) {
if (!split[i].isEmpty()) {
pathSectionCount += 1;
}

}
if (pathSectionCount > 2) {
index = name.lastIndexOf(separator);
}
}

result = jfilename.substring(0, index);
}

// trim leading slashes
if (startsWithSeparator && result.length() > minPathLength) {
while (
result.length() > minPathLength &&
(result.charAt(minPathLength) == separatorChar ||
(altSeparator != null && result.charAt(minPathLength) == altSeparatorChar))
) {
result = result.substring(1, result.length());
}
}

char endChar;
// trim trailing slashes
while (result.length() > minPathLength) {
endChar = result.charAt(result.length() - 1);
if (endChar == '/' || endChar == '\\') {
if (endChar == separatorChar || (altSeparator != null && endChar == altSeparatorChar)) {
result = result.substring(0, result.length() - 1);
} else {
break;
14 changes: 14 additions & 0 deletions spec/ruby/core/file/basename_spec.rb
Original file line number Diff line number Diff line change
@@ -88,6 +88,20 @@
File.basename("bar.txt.exe", ".txt.exe").should == "bar"
end

it "takes into consideration the platform path separator(s)" do
platform_is_not :windows do
File.basename("C:\\foo\\bar").should == "C:\\foo\\bar"
File.basename("C:/foo/bar").should == "bar"
File.basename("/foo/bar\\baz").should == "bar\\baz"
end

platform_is :windows do
File.basename("C:\\foo\\bar").should == "bar"
File.basename("C:/foo/bar").should == "bar"
File.basename("/foo/bar\\baz").should == "baz"
end
end

it "raises a TypeError if the arguments are not String types" do
lambda { File.basename(nil) }.should raise_error(TypeError)
lambda { File.basename(1) }.should raise_error(TypeError)
5 changes: 5 additions & 0 deletions spec/ruby/core/file/dirname_spec.rb
Original file line number Diff line number Diff line change
@@ -53,6 +53,9 @@
it "returns all the components of filename except the last one (edge cases on non-windows)" do
File.dirname('/////').should == '/'
File.dirname("//foo//").should == "/"
File.dirname('foo\bar').should == '.'
File.dirname('/foo\bar').should == '/'
File.dirname('foo/bar\baz').should == 'foo'
end
end

@@ -90,6 +93,8 @@
File.dirname("\\\\foo\\bar\\baz").should == "\\\\foo\\bar"
File.dirname("\\\\foo").should =="\\\\foo"
File.dirname("\\\\foo\\bar").should =="\\\\foo\\bar"
File.dirname("\\\\\\foo\\bar").should =="\\\\foo\\bar"
File.dirname("\\\\\\foo").should =="\\\\foo"
end

it "returns the return all the components of filename except the last one (forward_slash)" do