Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Require identifiers not provided by a module in Racket

Tags:

scheme

racket

Let's say I have some file a.rkt:

#lang racket
(define a 12)

I now want to write some test cases, using the file b.rkt that requires a.rkt:

#lang racket
(require "a.rkt")
a

Is there any way I can get b.rkt to recognize the identifier defined in a.rkt without having to provide it from the first file? (Ideally without having to change the first file at all.)

I don't see anything immediately in the documentation for require/provide.

like image 695
Leif Andersen Avatar asked Dec 06 '15 20:12

Leif Andersen


2 Answers

As Leif mentions, RackUnit's require/expose will allow using unprovided identifiers in other modules, but its own documentation doesn't promise a very strong guarantee:

Note that require/expose can be a bit fragile, especially when mixed with compiled code. Use at your own risk!

Another approach would be to use submodules, which can effectively provide a sanctioned way to export a private API for use in tests or other means.

For example, consider a module that implements a function to test if a string contains a single word:

#lang racket

(provide word?)

(define (word? str)
  (not (ormap space? (string->list str))))

(define (space? c)
  (eq? c #\space))

(This is, perhaps, not the most realistic example, but bear with me.)

It might be useful to test the space? function to ensure it works, but it likely shouldn't be part of the public API. To create an "escape hatch", it's possible to define a submodule that exports this binding:

(module+ for-testing
  (provide space?))

The name for-testing is arbitrary—it could be anything. Either way, it is now possible to require that submodule in another module to get access to the private bindings:

#lang racket

(require rackunit
         (submod "a.rkt" for-testing))

(check-true (space? #\space))
(check-false (space? #\a))

This is something of a safer way to expose identifiers from modules without exposing them to all consumers.

like image 68
Alexis King Avatar answered Nov 05 '22 19:11

Alexis King


You can use require/expose in b.rkt to get access to the binding in a.rkt. b.rkt would look something like this:

#lang racket
(require rackunit)
(require/expose "a.rkt" (a))
a
like image 45
Leif Andersen Avatar answered Nov 05 '22 20:11

Leif Andersen