Hybrid (native/ruby) pathname library #857

Merged
merged 3 commits into from Jul 6, 2013

Projects

None yet

3 participants

@eregon
Member
eregon commented Jul 5, 2013

This approach is quite similar to how MRI does it.
A good part of the library is still written in Ruby and it would take a considerable effort to translate everything (plus, it might not be very worthy). I think this should be merged in a first step.

The binding @path <=> path Java field is done by setting @path in #initialize, is there a better way?

There are a couple TODOs left, to which some light on it could help me.

Updated version of lib/ruby/1.9/pathname.rb is HEAD of the ruby_1_9_3 branch (only the require line changes from pathname.so to pathname_ext (is there a better naming, possible to differentiate pathname.{rb,jar}?
Should we add back the doc there? (in MRI, it was moved to pathname.c)

About the license, is it copied and adapted rightly?

Tests ($ bin/jruby test/externals/ruby1.9/pathname/test_pathname.rb) give:

263 tests, 520 assertions, 2 failures, 1 errors, 0 skips

The error is due to IO.open not being fully 1.9-compliant.
The first failure is ENOENT not raised with File.realdirpath (I will try to fix this).
The second failure is ENOENT being raised instead of ELOOP (symlink loop).

@headius what do you think?

@eregon eregon commented on the diff Jul 5, 2013
src/org/jruby/ext/pathname/RubyPathname.java
+
+@JRubyClass(name = "Pathname")
+public class RubyPathname extends RubyObject {
+ private RubyString path;
+
+ static void createPathnameClass(Ruby runtime) {
+ RubyClass cPathname = runtime.defineClass("Pathname", runtime.getObject(),
+ PATHNAME_ALLOCATOR);
+
+ cPathname.defineAnnotatedMethods(RubyPathname.class);
+
+ /*cPathname
+ .getVariableTableManager()
+ .getVariableAccessorsForRead()
+ .put("@path",
+ cPathname.getVariableTableManager().getVariableAccessorForWrite("path"));*/
@eregon
eregon Jul 5, 2013 JRuby Team member

Is there a good way to bind the java field with the instance variable?

@headius
headius Jul 6, 2013 JRuby Team member

Unfortunately not. Either use an instance var or a field, and generally only use the instance var if there's significant code in the wild that expects it to be there. The field will usually be faster.

@eregon eregon commented on the diff Jul 5, 2013
src/org/jruby/ext/pathname/RubyPathname.java
+
+ private static ObjectAllocator PATHNAME_ALLOCATOR = new ObjectAllocator() {
+ @Override
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
+ return new RubyPathname(runtime, klass);
+ }
+ };
+
+ public RubyPathname(Ruby runtime, RubyClass metaClass) {
+ super(runtime, metaClass);
+ path = null;
+ }
+
+ public static RubyPathname newInstance(ThreadContext context, RubyClass klass, IRubyObject path) {
+ RubyPathname pathname = new RubyPathname(context.runtime, klass);
+ return (RubyPathname) pathname.initialize(context, path);
@eregon
eregon Jul 5, 2013 JRuby Team member

Is this the standard way to do it?

@headius
headius Jul 6, 2013 JRuby Team member

This all looks pretty standard, yes.

@eregon eregon commented on the diff Jul 5, 2013
src/org/jruby/ext/pathname/RubyPathname.java
+ return context.nil;
+ } else {
+ return files;
+ }
+ }
+
+ @JRubyMethod
+ public IRubyObject opendir(ThreadContext context, Block block) {
+ return context.runtime.getDir().callMethod(context, "open", new IRubyObject[] { path },
+ block);
+ }
+
+ @JRubyMethod
+ public IRubyObject each_entry(ThreadContext context, Block block) {
+ if (block.isGiven()) {
+ // TODO: yield block while iterating
@eregon
eregon Jul 5, 2013 JRuby Team member

It's probably OK for now since even Dir.foreach gets an Array of all entries.

@eregon eregon commented on the diff Jul 5, 2013
src/org/jruby/ext/pathname/RubyPathname.java
+ private static IRubyObject[] insert(IRubyObject[] old, int i, IRubyObject obj) {
+ IRubyObject[] ary = new IRubyObject[old.length + 1];
+ if (i > 0)
+ System.arraycopy(old, 0, ary, 0, i);
+ ary[i] = obj;
+ if (old.length > i)
+ System.arraycopy(old, i, ary, i + 1, old.length - i);
+ return ary;
+ }
+
+ private static RubyArray mapToPathnames(ThreadContext context, IRubyObject ary) {
+ RubyArray paths = ary.convertToArray();
+ for (int i = 0; i < paths.size(); i++) {
+ RubyString path;
+ if (paths.get(i) instanceof String) // TODO
+ path = context.runtime.newString((String) paths.get(i));
@eregon
eregon Jul 5, 2013 JRuby Team member

I did not get how a Java String could be in a RubyArray, maybe I should just use sth else than get(i)?

@headius
headius Jul 6, 2013 JRuby Team member

The implementations of the Java Collection/List/Map interface always attempt to coerce to a "natural" Java object; in this case, that would produce a java.lang.String. Use one of the elt* functions, probably elt() or eltOk().

@headius
Member
headius commented Jul 6, 2013

The PR looks like a good start, and I agree we should merge it. I'll see if I can make that happen, since it's not automatically mergable with recent source tree reorg.

@jrubyci jrubyci merged commit 10d22da into jruby:master Jul 6, 2013

1 check failed

Details default The Travis CI build failed
@headius
Member
headius commented Jul 6, 2013

Merged! Make sure you rebase to the new layout and read BUILDING.md for changes to the dev workflow. Looking good so far!

@eregon eregon added a commit that referenced this pull request Jul 7, 2013
@eregon eregon Pathname hybrid PR #857 fixed 2 examples 161ee3b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment