Requiring a file that is in a directory containing a dot

I was trying to require a file that is inside a directory via a relative path. Surprisingly, this did not work, but resulted in an error. For example, I have the file dir.dot/x.rkt (the content does not matter). When typing (require "dir.dot/x.rkt"), I get the following error:

string:1:9: require: bad module-path string
  at: "dir.dot/x.rkt"
  in: (require "dir.dot/x.rkt")
 [,bt for context]

If I change into the directory and require the file it works. I would not have expected this behavior; is there a reason for this?

2 Likes

Hi, @nik.

Interesting. First time coming across this. A quick scan of the docs would have me believe that (file ...) is what you might be looking for.

As an example, I have top/path/requiring-file.rkt and then top/some.dir/some-file.rkt.

The requiring file can reference the some-file.rkt just fine using this:

(require (file "../some.dir/some-file.rkt"))

I am on Windows 11 for this test, if that makes any difference.

I hope that helps.

Yes, that seems to do the trick; thank you. I'm a bit surprised that this other option exists as I don't really understand why the two cases are treated differently. (And the docs only mention the user expansion.)

The restriction is documented under the rel-string section for module paths.

The path cannot be empty or contain a leading or trailing slash, path elements before than [sic] the last one cannot include a file suffix (i.e., a . in an element other than . or ..), and the only allowed characters are ASCII letters, ASCII digits, -, +, _, ., /, and % (emphasis mine).

The reason may be historical.

2 Likes

Not relevant to the specific question you're asking, but related:

When using relative filepaths, define-runtime-path is a big help. It constructs an absolute path from a relative path starting from the current file so that you don't need to worry about what the current directory is at any given moment:

#lang racket

(require racket/runtime-path)

(define-runtime-path here ".") ;; 'here' is relative to this file                                   

(println (build-path "." "foo"))
(println (build-path here "foo"))

Output on my machine:

#<path:./foo>
#<path:/Users/dstorrs/projects/racket-pkgs/sudoku-maker/./foo>

(define-runtime-path is used for application code, not for a require line.)

2 Likes

This is speculation rather than an answer, but I wouldn't be surprised to discover that this could be a problem (or perhaps "bad interaction") with the way that file extensions are handled on certain platforms, possibly including Windows.

I'd be slightly leery of using define-runtime-path to require racket files; it seems probable to me that you'd be disrupting the ability of packages to overlap on collections.

That is an excellent point. I'm glad you pointed it out. :stuck_out_tongue:

If you want to use the require-based resolution but get access to a path in a way to declares a dependency, you can use something like this:

(define-runtime-path racket/list.rkt '(lib "list.rkt" "racket"))

There's also a variant for dynamic-libraries (that I have no real experience with, tho).