[ANN] fs - file system utilities for Clojure

1,867 views
Skip to first unread message

Miki

unread,
Jan 12, 2011, 3:48:44 PM1/12/11
to clo...@googlegroups.com
[fs "0.2.0-SNAPSHOT"] is out, featuring:

abspath
    Return absolute path
basename
    Return the last part of path
copy
    Copy a file
cwd
    Return the current working directory
delete
    Delete path
directory?
    True if path is a directory
dirname
    Return directory name
executable?
    Check if path is executable
exists?
    Check if path exists
file?
    True if path is a file
glob
    `ls` like operator
join
    Join part to path
listdir
    List files under directory
mkdir
    Create directory
mtime
    File modification time
mkdirs
    Create directory tree
normpath
    Return normalized (canonical) path
readable?
    Check if path is readable
rename
    Rename path
separator
    Path separator
size
    File size
split
    Split path to parts
tempdir
    Create temporary directory
tempfile
    Create temporary file
walk
    Walk over directory structure, calling function on every step
writeable?
    Check if path is writable

Have fun,
--
Miki

László Török

unread,
Jan 12, 2011, 4:35:21 PM1/12/11
to clo...@googlegroups.com

Good stuff, just what I was looking for, can't wait to try...

sent from my mobile device

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

Tim Visher

unread,
Jan 13, 2011, 8:11:45 AM1/13/11
to clo...@googlegroups.com
I'm missing something blindingly obvious. Where can I download this?

gaz jones

unread,
Jan 13, 2011, 8:18:13 AM1/13/11
to clo...@googlegroups.com
probably clojars.org (or by putting [fs "0.2.0-SNAPSHOT"] in your
project.clj if you're using lein...

Meikel Brandmeyer

unread,
Jan 13, 2011, 8:28:16 AM1/13/11
to Clojure
Hi,

On 12 Jan., 21:48, Miki <miki.teb...@gmail.com> wrote:

> [fs "0.2.0-SNAPSHOT"] is out

A SNAPSHOT is "out"? Please don't do this. If it is a release, get rid
of the SNAPSHOT. :(

Sincerely
Meikel

Miki

unread,
Jan 13, 2011, 9:52:02 AM1/13/11
to clo...@googlegroups.com

> [fs "0.2.0-SNAPSHOT"] is out

A SNAPSHOT is "out"? Please don't do this. If it is a release, get rid
of the SNAPSHOT. :(

Done, please use [fs "0.2.0"] :)

All the best,
--
Miki

Miki

unread,
Jan 13, 2011, 9:55:24 AM1/13/11
to clo...@googlegroups.com
>> I'm missing something blindingly obvious. Where can I download this?
> probably clojars.org (or by putting [fs "0.2.0-SNAPSHOT"] in your
> project.clj if you're using lein...
Yup, it's in clojars. However if you prefer to download the jar manually, you can
get it from https://bitbucket.org/tebeka/fs/downloads/fs-0.2.0.jar

Laurent PETIT

unread,
Jan 13, 2011, 9:59:35 AM1/13/11
to clo...@googlegroups.com
2011/1/13 Miki <miki....@gmail.com>


Too bad the artifact name "f" was already taken, and you had to resort to using a sooo long name as "fs" :-p

Just kidding ;)

Steve Miner

unread,
Jan 13, 2011, 10:04:48 AM1/13/11
to clo...@googlegroups.com
Thanks for shaing. I was just about to write several functions along these lines. I have a couple of comments.

First, I suggest that you look at the standard clojure.java.io package for some useful functions that are already in Clojure 1.2. In particular, you could use io/file instead of (File. xxx) in your code to add some flexibility to the kinds of things that can be treated as a "file". I think io/file could replace your fs/join. Also, io/copy is very flexible so it's worth a look, too.

Second, fs is using a singe segment namespace. I remember that there have been some cautions against doing that. (But not everyone agrees.) My understanding is that it's best for Java interop to have a multi-segment namespace. (Reference links below.)

http://clojure.org/libs

> A lib name is a symbol that will typically contain two or more parts separated by periods.

http://groups.google.com/group/clojure-dev/browse_frm/thread/00b1c6971c3b3394

Chas Emerick wrote:
> First, namespacing is good. Your foobar library won't have the same name as my foobar library -- and while you might think "who else would put code in the same oddly-named namespace as mine?", it's a big world out there and an ounce of prevention is worth a pound of cure. More strictly speaking, one cannot use any class in the default package from any Java class that is in a package. That is the practical issue that leads to default package use being nonexistent in the Java space. And, you may not care about Java interop now, but either (a) you might later, or (b) your users might, now. Finally, gen-class will simply not work (last I checked) from a single-segment namespace.


Best Regards,
Steve Miner
steve...@gmail.com

gaz jones

unread,
Jan 13, 2011, 11:45:05 AM1/13/11
to clo...@googlegroups.com
there is also this:

https://github.com/jashmenn/clj-file-utils

which seems to be very similar

Tim Daly

unread,
Jan 13, 2011, 11:54:17 AM1/13/11
to clo...@googlegroups.com
> Second, fs is using a singe segment namespace. I remember that
> there have been some cautions against doing that. (But not everyone
> agrees.) My understanding is that it's best for Java interop to have a
> multi-segment namespace. (Reference links below.)
http://clojure.org/libs
>> A lib name is a symbol that will typically contain two or more parts separated by periods.
> http://groups.google.com/group/clojure-dev/browse_frm/thread/00b1c6971c3b3394
>
> Chas Emerick wrote:
>> First, namespacing is good. Your foobar library won't have the same name as my foobar library -- and while you might think "who else would put code in the same oddly-named namespace as mine?", it's a big world out there and an ounce of prevention is worth a pound of cure. More strictly speaking, one cannot use any class in the default package from any Java class that is in a package. That is the practical issue that leads to default package use being nonexistent in the Java space. And, you may not care about Java interop now, but either (a) you might later, or (b) your users might, now. Finally, gen-class will simply not work (last I checked) from a single-segment namespace.
As a greybeard in the game, this all sounds so familiar.
The point of this post is to suggest that Clojure should
NOT adopt java naming conventions.

Back in the days of Cobol, before it got renamed to Java,
we used to construct hierarchical databases. For those who
don't know about them, they would specifiy the path to every
element in the database in the name of the element. Thus, you
would say
world.country.company.site.disk.dbname.dept.bldg.aisle.office.person
or some such.

It was argued that this was necessary to ensure that
you always got a unique element and that programs would not clash.
It was also very efficient since the worldwide path to a point
was always unique (as opposed to the horribly inefficient idea
of using table and relational algebra to look up stuff at runtime!
Why the ambiguity will cause world confusion and the runtime will
be impossibly long! Just write out the long name! Sigh.)

There are a couple of items worth mentioning. First, notice
that everything is fine until the world changes. Now there
are hardcoded legacy assumptions built into the name (e.g.
the person is in a different building so we have to reformat
the database to pay them). Consider that the Java naming
convention does that... java.sun.com ... who is "sun"?
I never heard of them.

Second, but similar, should I name my classes java.daly.tim.freesource?
Suppose I get married and change my name? Suppose someone with a
similar name writes a package. Does my son have to write
java.jr.daly.tim.freesource?

Third, suppose I refactor my program. Now I have to rename every
class to fit the new hierarchy. But that will break old programs
that use my package. Who could possibly want to refactor deep
enough to shuffle classes?

Fourth, this hierarchical thinking strongly encourages making
functions that are class-specific. Thus you find that java has
hundreds of sorts, one per class.

Fifth, one writes the long.drawn.out.name to satify the
compiler's inability to find anything despite the class name
being unique. In fact, the compiler is insisting that your
class name match the name of the file and it STILL insists
that you use unique names so it doesn't have to search the
filesystem. The side-effects of this are that your class hierarchy
is rigid (see refactoring above), the name assumes a hierarchical
file system, and the ultimate issue... the user has to use an IDE
to find something simple as a sort.

Sixth, programs rarely need to deal with the whole world.
Why would you have qualifiers on a per-company basis just
to guarantee uniqueness of the name of your sort function?

In lisp one ends up with hundreds of functions in the same
namespace. Because the functions are not type-specific
they tend to be very broad and general. It is rare to have
more than one sort and people don't generally write sort
functions since they are too standard.

A simple namespace qualifier, like fs, is sufficient to
handle large, general purpose packages which contain functions
to handle file systems.

Since lisp uses naked functions there is no natural map from
functions to filenames.

In sum, I'm suggesting that it isn't very lispy to use
hierarchical namespace naming conventions.

Tim Daly

Chas Emerick

unread,
Jan 13, 2011, 3:16:22 PM1/13/11
to clo...@googlegroups.com

On Jan 13, 2011, at 11:54 AM, Tim Daly wrote:

> > Second, fs is using a singe segment namespace. I remember that
> > there have been some cautions against doing that. (But not everyone
> > agrees.) My understanding is that it's best for Java interop to have a
> > multi-segment namespace. (Reference links below.) http://clojure.org/libs
>>> A lib name is a symbol that will typically contain two or more parts separated by periods.
>> http://groups.google.com/group/clojure-dev/browse_frm/thread/00b1c6971c3b3394
>>
>> Chas Emerick wrote:
>>> First, namespacing is good. Your foobar library won't have the same name as my foobar library -- and while you might think "who else would put code in the same oddly-named namespace as mine?", it's a big world out there and an ounce of prevention is worth a pound of cure. More strictly speaking, one cannot use any class in the default package from any Java class that is in a package. That is the practical issue that leads to default package use being nonexistent in the Java space. And, you may not care about Java interop now, but either (a) you might later, or (b) your users might, now. Finally, gen-class will simply not work (last I checked) from a single-segment namespace.
> As a greybeard in the game, this all sounds so familiar.
> The point of this post is to suggest that Clojure should
> NOT adopt java naming conventions.

...

> Since lisp uses naked functions there is no natural map from
> functions to filenames.
>
> In sum, I'm suggesting that it isn't very lispy to use
> hierarchical namespace naming conventions.

Just to clarify my position (it's funny to see one's self quoted out of the blue from an old thread!), I'm not at all suggesting "java naming conventions" when it comes to namespacing. (Although I'd note that Clojure *is* a fundamentally hosted language, and so certain idioms do flow from that host; CamelCase naming conventions for records, types, and protocols comes to mind.) No one wants to work with com.foo.bar.baz.factory.factory.factories.Factory, etc.

While there is no natural mapping between functions and filenames, surely there's *some* mapping for every project that won't run afoul of the real issues that truly can crop up with single-segment namespaces[1] but still feels natural to you. Functionally logical grouping of code never goes out of style. I'd humbly submit that single-segment namespaces are a non-solution to any naming problem you'd like to solve (outside of maximal concision perhaps, which I'd suggest is a low-value problem).

Cheers,

- Chas

[1] If you really, really don't care about host interop, and you never, *ever* will, and you're a maestro at naming projects (yup, I'm looking at you, Phil! :-), then maybe single-segment namespaces are OK. Even then, it's worth noting that even e.g. leiningen, robert hooke, etc. don't use single-segment namespaces.

Steve Miner

unread,
Jan 13, 2011, 3:59:48 PM1/13/11
to clo...@googlegroups.com

On Jan 13, 2011, at 3:16 PM, Chas Emerick wrote:

> Just to clarify my position (it's funny to see one's self quoted out of the blue from an old thread!), I'm not at all suggesting "java naming conventions" when it comes to namespacing.

By the way, I didn't mean to put Chas on the spot. Google led me to what seemed like a good quote, and I thought he deserved the credit. Please take that as a compliment.

One suggested compromise (from the old thread) was to use a short first segment so that your namespace is technically multi-segment (good for Java interop), but still short enough to be esthetically pleasing. For example, clj.foo instead of plain foo. Seems like a good compromise to me.

Now, one could say that the problem is in the Clojure compiler. Maybe single segment names should be explicitly disallowed. (They're bad, don't do that.) Or maybe the compiler should silently prepend "us.technomancy." to single-segment namespaces to make the world safe for Java interop with minimal danger of conflicts. That would make everybody happy. :-)

Cheers,
Steve


Chas Emerick

unread,
Jan 13, 2011, 4:43:04 PM1/13/11
to clo...@googlegroups.com

On Jan 13, 2011, at 3:59 PM, Steve Miner wrote:

> On Jan 13, 2011, at 3:16 PM, Chas Emerick wrote:
>
>> Just to clarify my position (it's funny to see one's self quoted out of the blue from an old thread!), I'm not at all suggesting "java naming conventions" when it comes to namespacing.
>
> By the way, I didn't mean to put Chas on the spot. Google led me to what seemed like a good quote, and I thought he deserved the credit. Please take that as a compliment.

I did, thanks. :-)

> One suggested compromise (from the old thread) was to use a short first segment so that your namespace is technically multi-segment (good for Java interop), but still short enough to be esthetically pleasing. For example, clj.foo instead of plain foo. Seems like a good compromise to me.

That seems perfectly fine, as long as the prefix or suffix isn't "standard" -- otherwise, for purposes of runtime differentiation, such namespaces are functionally a single segment. i.e. if the standard is clj.foo or baz.core, then someone else's clj.foo or baz.core will conflict just as well.

FWIW, I use "cemerick" as a prefix for all personal stuff (though I do little programming that is both personal and significant enough to warrant worrying about namespaces). I assume that everyone has their preferred irc/IM/email handle; using it as a prefix seems reasonable to me, anyway.

If your name changes, then modifying some namespaces is surely not the most difficult part of that process!

- Chas

Miki

unread,
Jan 13, 2011, 6:07:30 PM1/13/11
to clo...@googlegroups.com

First, I suggest that you look at the standard clojure.java.io package for some useful functions that are already in Clojure 1.2.  In particular, you could use io/file instead of (File. xxx) in your code to add some flexibility to the kinds of things that can be treated as a "file".  I think io/file could replace your fs/join. Also, io/copy is very flexible so it's worth a look, too.

Yeah, I wasn't aware of the many things in clojure.java.io (used just reader from there). I do plan switch to clojure.java.io soon.
 

Second, fs is using a singe segment namespace.  I remember that there have been some cautions against doing that. (But not everyone agrees.)  My understanding is that it's best for Java interop to have a multi-segment namespace.  (Reference links below.)

(and many other mails in this thread).

Coming from a Python background, single segment namespaces are natural to me and have never been a problem. I added :gen-class and ran "lein compile" and it worked, so I don't see a problem here as well. Changing it to com.mikitebeka.fs or lazy1.fs has too much of an ego trip for me :)

Miki

unread,
Jan 13, 2011, 6:09:50 PM1/13/11
to clo...@googlegroups.com
Wasn't aware of this one, will have a look. At first glance it uses common.io and I tried to depend on clojure only.

Thanks,
--
Miki

Alessio Stalla

unread,
Jan 14, 2011, 4:10:52 AM1/14/11
to clo...@googlegroups.com
On Thursday, January 13, 2011 5:54:17 PM UTC+1, TimDaly wrote:
[snip]

In sum, I'm suggesting that it isn't very lispy to use
hierarchical namespace naming conventions.

I think all you said is very true... *if* the user of a namespace is allowed to change its name (i.e. Common Lisp's RENAME-PACKAGE). In Java, you obviously can't; I don't know Clojure well enough, but I suspect you can't, either. So, in case two third-party namespaces collide, there's no solution. Thus a collision-avoiding naming scheme becomes more important. (Note: I'm not advocating the blind use of Java conventions; in my "Dynaspring" project, which is coded in a mix of Lisp and Java, the Java package is just "dynaspring" and the Lisp one is :spring, because I find it very improbable that someone else will release another library using the same package names and that someone else will use both libraries in his or her project).

Just my .02€
Alessio

Miki

unread,
Jan 14, 2011, 12:06:57 PM1/14/11
to clo...@googlegroups.com

First, I suggest that you look at the standard clojure.java.io package for some useful functions that are already in Clojure 1.2. 

Done in 0.3.0 (as well as some other added functions), thanks again.

Rayne

unread,
Jan 19, 2011, 9:30:39 AM1/19/11
to clo...@googlegroups.com
It isn't nearly as big a deal as you think it is. I'm guessing you have a single file called 'fs.clj' with the namespace 'fs', right?

mkdir src/fs/
mv src/fs.clj src/fs/core.clj

 
and then edit the file and change the namespace to fs.core. Why is that such a big deal? I understand that you're coming from Python, but Clojure isn't, and never will be Python. If you came from COBOL would you want to write your code in all caps? Nobody is asking you to do this for fun. This is a Clojure idiom that everybody uses, and it isn't only for you but for users of your code. 

Miki

unread,
Jan 19, 2011, 12:32:29 PM1/19/11
to clo...@googlegroups.com

It isn't nearly as big a deal as you think it is. I'm guessing you have a single file called 'fs.clj' with the namespace 'fs', right?

mkdir src/fs/
mv src/fs.clj src/fs/core.clj
and then edit the file and change the namespace to fs.core.
I know it's easy to do, I just don't think I should do it.
 
 
Why is that such a big deal?
It's not a big deal. I don't get what's the big deal of doing
    (require 'fs)
    (fs/copy "/some/file" "/some/other/file")

 
I understand that you're coming from Python, but Clojure isn't, and never will be Python. If you came from COBOL would you want to write your code in all caps? Nobody is asking you to do this for fun. This is a Clojure idiom that everybody uses, and it isn't only for you but for users of your code. 
 
Somebody needs to be the anarchist in the group :)
I don't believe in doing things just because everybody else is doing them. And I haven't heard a compelling
reason (IMO) so far to change. When there are logical namespaces, I'll gladly add them. But this is just a bunch of file system
functions. Also I don't see how users of the code suffer from having one short namespace.

I'd appreciate some comments about need functionality, bugs, code reviews and such.

Eric Schulte

unread,
Jan 19, 2011, 1:01:38 PM1/19/11
to clo...@googlegroups.com
Miki <miki....@gmail.com> writes:

>> It isn't nearly as big a deal as you think it is. I'm guessing you have a
>> single file called 'fs.clj' with the namespace 'fs', right?
>>
>> mkdir src/fs/
>> mv src/fs.clj src/fs/core.clj
>>
> and then edit the file and change the namespace to fs.core.
>
> I know it's easy to do, I just don't think I should do it.
>

More power to you, I personally don't particularly care about Java
interop (pretty sure Java has enough file system utilities) and I'd
rather not type ".core" all over the place. If it wasn't for the soft
paternalism of lein I wouldn't user .core at all.

>
> I'd appreciate some comments about need functionality, bugs, code reviews
> and such.
>

I have one question, is there any documentation available for the
functions provided by fs? I would love a place where I could go to scan
the available functions, other than the source code.

Thanks -- Eric

B Smith-Mannschott

unread,
Jan 19, 2011, 3:24:50 PM1/19/11
to clo...@googlegroups.com

This is a retarded 'convention', and it isn't really much of a
convention at that. Just because Clojure itself has a 'core.clj',
doesn't mean everyone else needs one now too. I blame Leiningen's
defaults. For counter-examples, take a look at clojure-contrib. The
only core.clj in there is for proposed additions to clojure.core
itself.

If I were writing a library 'flub', I'd expected the main file the
user is expected to :use to be named flub.clj and supporting files to
be flub/SOMETHING.clj. If I wanted to make sure it was disambiguated,
say if I intended it as a library and not a stand-alone application, I
might call the namespace PREFIX.flub and PREFIX.flub.something, where
PREFIX is something one might reasonably expect to be unique, e.g.
bpsmithmannschott.flub.

// Ben

Meikel Brandmeyer

unread,
Jan 19, 2011, 3:31:45 PM1/19/11
to clo...@googlegroups.com
Hi,

Am 19.01.2011 um 21:24 schrieb B Smith-Mannschott:

> This is a retarded 'convention', and it isn't really much of a
> convention at that. Just because Clojure itself has a 'core.clj',
> doesn't mean everyone else needs one now too. I blame Leiningen's
> defaults. For counter-examples, take a look at clojure-contrib. The
> only core.clj in there is for proposed additions to clojure.core
> itself.

Hmm… Wasn't the „main“ reason of technical nature? Namely classes in the default package? Which cause problems in Java world?

Sincerely
Meikel

Miki

unread,
Jan 19, 2011, 4:10:21 PM1/19/11
to clo...@googlegroups.com

I have one question, is there any documentation available for the
functions provided by fs?  I would love a place where I could go to scan
the available functions, other than the source code.

Adam

unread,
Jan 19, 2011, 2:01:24 PM1/19/11
to clo...@googlegroups.com
There appears to be a bug in "walk" when there is an empty folder somewhere beneath the specified directory.  I've only tested this on Win XP but this triggers a NullPointerException on fs 0.4.0:

    (walk "c:/empty" (fn [& a] true))

No message.
  [Thrown class java.lang.NullPointerException]

Restarts:
 0: [QUIT] Quit to the SLIME top level

Backtrace:
  0: clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:263)
  1: fs$w_file_QMARK_.invoke(fs.clj:192)
  2: fs$walk.invoke(fs.clj:204)
  3: t$eval2410.invoke(NO_SOURCE_FILE:1)
  4: clojure.lang.Compiler.eval(Compiler.java:5424)
  5: clojure.lang.Compiler.eval(Compiler.java:5391)
  6: clojure.core$eval.invoke(core.clj:2382)
  7: swank.commands.basic$eval_region.invoke(basic.clj:47)
      [No Locals]
  8: swank.commands.basic$eval_region.invoke(basic.clj:37)
  9: swank.commands.basic$eval807$listener_eval__808.invoke(basic.clj:71)
 10: clojure.lang.Var.invoke(Var.java:365)
 11: t$eval2408.invoke(NO_SOURCE_FILE)
 12: clojure.lang.Compiler.eval(Compiler.java:5424)
 13: clojure.lang.Compiler.eval(Compiler.java:5391)
 14: clojure.core$eval.invoke(core.clj:2382)
 15: swank.core$eval_in_emacs_package.invoke(core.clj:94)
 16: swank.core$eval_for_emacs.invoke(core.clj:241)
 17: clojure.lang.Var.invoke(Var.java:373)
 18: clojure.lang.AFn.applyToHelper(AFn.java:169)
 19: clojure.lang.Var.applyTo(Var.java:482)
 20: clojure.core$apply.invoke(core.clj:540)
 21: swank.core$eval_from_control.invoke(core.clj:101)
 22: swank.core$eval_loop.invoke(core.clj:106)
 23: swank.core$spawn_repl_thread$fn__489$fn__490.invoke(core.clj:311)
 24: clojure.lang.AFn.applyToHelper(AFn.java:159)
 25: clojure.lang.AFn.applyTo(AFn.java:151)
 26: clojure.core$apply.invoke(core.clj:540)
 27: swank.core$spawn_repl_thread$fn__489.doInvoke(core.clj:308)
 28: clojure.lang.RestFn.invoke(RestFn.java:398)
 29: clojure.lang.AFn.run(AFn.java:24)
 30: java.lang.Thread.run(Unknown Source)

~Adam~

Michael Gardner

unread,
Jan 24, 2011, 11:04:40 AM1/24/11
to clo...@googlegroups.com
On Jan 19, 2011, at 11:32 AM, Miki wrote:

> I'd appreciate some comments about need functionality, bugs, code reviews and such.

Thanks for this useful library. Some suggestions:

-I'd rather (copy-tree src dest) worked like "cp -R src dest" (including when dest doesn't exist) rather than "cp -R src/* dest/".

-It would be nice if functions that create files or dirs (like mkdir and touch) returned the new object's path, to allow chaining.

Miki

unread,
Jan 24, 2011, 6:26:40 PM1/24/11
to clo...@googlegroups.com

-I'd rather (copy-tree src dest) worked like "cp -R src dest" (including when dest doesn't exist) rather than "cp -R src/* dest/".

I agree, working on that.

-It would be nice if functions that create files or dirs (like mkdir and touch) returned the new object's path, to allow chaining.

Done in 0.5.2 (delete, mkdir, mkdirs, touch and chmod)

Miki

unread,
Jan 28, 2011, 12:44:17 AM1/28/11
to clo...@googlegroups.com

-I'd rather (copy-tree src dest) worked like "cp -R src dest" (including when dest doesn't exist) rather than "cp -R src/* dest/".

Done in 0.6.0.

siyu798

unread,
Mar 15, 2011, 5:56:55 PM3/15/11
to clo...@googlegroups.com
Hi Miki,
  We are planning to use this file system utilities, and we need a function to get file extension. Currently we're using apache common for that, but we want to get rid of apache common altogether.  Can you add this functionality to the fs.clj? Thx

Si Yu

Steve Miner

unread,
Mar 16, 2011, 8:52:07 AM3/16/11
to clo...@googlegroups.com
I've been using this to get the extension:

(defn extension [file]
(when file
(let [base (fs/basename file)
dot (.lastIndexOf ^String base ".")]
(when (pos? dot)
(subs base (inc dot))))))

Steve Miner

Miki

unread,
Mar 16, 2011, 3:16:13 PM3/16/11
to clo...@googlegroups.com

  We are planning to use this file system utilities, and we need a function to get file extension. Currently we're using apache common for that, but we want to get rid of apache common altogether.  Can you add this functionality to the fs.clj? Thx

Added in 0.7.1 (thanks to Steve Miner for the implementation detail :)

siyu798

unread,
Mar 17, 2011, 1:07:00 PM3/17/11
to clo...@googlegroups.com
Perfec! Thanks a lot

siyu798

unread,
Mar 18, 2011, 5:52:29 PM3/18/11
to clo...@googlegroups.com
Hi Miki,
  The dirname testcase fails on Window.  Does it make sense that even if it's running on window it should still pass?  In another word, don't you think that it should not convert the separator implicitly?

(deftest dirname-test
  (is (= (dirname "/a/b/c") "/a/b")))

user=> (fs/dirname "/a/b/c")
"\\a\\b"

Thanks,
Si Yu



Miki

unread,
Mar 18, 2011, 6:02:27 PM3/18/11
to clo...@googlegroups.com
Greetings,


  The dirname testcase fails on Window.  Does it make sense that even if it's running on window it should still pass?  In another word, don't you think that it should not convert the separator implicitly?
I agree with you, and I'll try to fix the test. However I don't have access to a windows machine to make sure this work.

You can track this bug at https://bitbucket.org/tebeka/fs/issue/4/dirname-test-fails-on-windows

Miki

unread,
Mar 21, 2011, 5:20:02 PM3/21/11
to clo...@googlegroups.com
I *think* it's fixed, can you test with the latest sources in bitbucket?

siyu798

unread,
Mar 21, 2011, 6:29:42 PM3/21/11
to clo...@googlegroups.com
Miki,
Thanks for the quick response, but I'm not just looking for a fix for the testcase, I'm looking for the dirname function to return the same output regardless of the machine that the code is running on, eg 

(dirname "/a/b/c") should return "/a/b/" on both win and unix

just like the getFullPath method in apache common filenameutils:

Thanks,
Si Yu

Miki

unread,
Mar 21, 2011, 9:54:25 PM3/21/11
to clo...@googlegroups.com
Greetings,


(dirname "/a/b/c") should return "/a/b/" on both win and unix
You can use fs/*separator for that:
     user=> (binding [fs/*separator* ":"] (fs/join "a" "b" "c"))
     "a:b:c"

However users expect the path to be right depending on the OS, meaning \ on windows and / on *nix.

HTH,
--
Miki

Shantanu Kumar

unread,
Mar 22, 2011, 12:47:26 AM3/22/11
to Clojure


On Mar 22, 3:29 am, siyu798 <siyu...@gmail.com> wrote:
> Miki,
> Thanks for the quick response, but I'm not just looking for a fix for the
> testcase, I'm looking for the dirname function to return the same output
> regardless of the machine that the code is running on, eg
>
> (dirname "/a/b/c") should return "/a/b/" on both win and unix

You can write such a function yourself. Irrespective of the platform,
Java works fine with '/' as a separator in the filename. The function
below first converts all '\' to '/' and then splits on '/' to maintain
platform-independence:

https://bitbucket.org/kumarshantanu/clj-miscutil/src/0068da5842c9/src/main/clj/org/bituf/clj_miscutil.clj#cl-580

Btw, this is not in the stable version yet - will be available in the
next GA. (Sorry for the plug, that was not the intention. :-))

Regards,
Shantanu

siyu798

unread,
Mar 22, 2011, 11:12:10 AM3/22/11
to clo...@googlegroups.com
Miki,
  We do have functions to normalize and convert path and I just think the dirname function should not do the conversion.  In fact there's no benefits to do so as /a/b/c on *nix is not equal to \a\b\c in window, same goes for c:\a\b\c in window for c:/a/b/c in *nix.  In 99.99% percent of the time you would have mappings like /A/B/C on *nix is mounted as F: on windows.


Thanks,
Si Yu

Daniel Werner

unread,
Mar 22, 2011, 5:45:28 PM3/22/11
to clo...@googlegroups.com
On 22 March 2011 05:47, Shantanu Kumar <kumar.s...@gmail.com> wrote:
> On Mar 22, 3:29 am, siyu798 <siyu...@gmail.com> wrote:
>> (dirname "/a/b/c") should return "/a/b/" on both win and unix
>
> You can write such a function yourself. Irrespective of the platform,
> Java works fine with '/' as a separator in the filename.

In fact, this is not limited to Java. '/' is a path separator on equal
footing with '\' on Windows (short of UNC paths, regrettably). This
fact is often obscured by applications that make use of some ad-hoc
path mangling and implicitly assume '\' as the only path separator.

Interesting read:
http://en.wikipedia.org/wiki/Path_(computing)#MS-DOS.2FMicrosoft_Windows_style

Jeffrey Schwab

unread,
Mar 23, 2011, 10:21:37 AM3/23/11
to clo...@googlegroups.com
Not so.  Windows commands of the form "someProgram /some/path" often mistake /some/path for command-line switches (like Unix flags).  I had real-world problems with this when trying to run a Rails app on Windows, because of the issue discussed here: http://www.ruby-forum.com/topic/50137

Daniel Werner

unread,
Mar 23, 2011, 2:40:54 PM3/23/11
to clo...@googlegroups.com
On 23 March 2011 15:21, Jeffrey Schwab <je...@schwabcenter.com> wrote:
> Not so.  Windows commands of the form "someProgram /some/path" often mistake
> /some/path for command-line switches (like Unix flags).

Yes, working around this issue is discussed in the Wikipedia article I
linked to.

> I had real-world
> problems with this when trying to run a Rails app on Windows, because of the
> issue discussed here: http://www.ruby-forum.com/topic/50137

Mhh, that sounds dire, especially this comment:

"However, the Unicode Win32API -- which will be used in the future --
does not accept /."

Thanks for bringing it up.

Reply all
Reply to author
Forward
0 new messages