[racket] Require macros

From: Eduardo Bellani (ebellani at gmail.com)
Date: Wed Jan 12 13:55:26 EST 2011

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hey Ryan, many thanks for the response, it helped a great deal in
crafting what I needed.

I still have to grok completely why things work the way they do in this
case, but alas, I have a working prototype. Here it is in case someone
has some use for it. My inspiration for this was rails use of directory
and filenames conventions in case someone is wondering. So you must have
a symmetric directory tree for your app and your tests.

;; auxiliary.rkt
(require rackunit
         racket/require-syntax
         rackunit/text-ui)

(provide (all-from-out rackunit)
         (all-from-out rackunit/text-ui)
         test)

(define-require-syntax (test stx)
  (let*-values ([(base filename must-be-dir?)
                 (split-path
                  (resolved-module-path-name
                   (current-module-declare-name)))]
                [(type-base type-path must-be-dir?) (split-path base)]
                [(resolved-name type)
                 (values (path->string filename)
                         (path->string type-path))]
                [(cleaned-name)
                 (substring resolved-name
                            0 (- (string-length resolved-name) 9))])
    (syntax-case stx (me)
      [(test me)
       (datum->syntax stx
                      (string-append
                       "../../app/" type "/"
                       cleaned-name
                       ".rkt"))]
      [(test relpath)
       (datum->syntax stx
                      (string-append
                       "../../app/" type "/"
                       (syntax-e #'relpath)
                       ".rkt"))])))

;;target-test.rkt
(require "../auxiliary.rkt"
         (test "another-file")
         (test me))



On 01/11/2011 08:38 PM, Ryan Culpepper wrote:
> On 01/11/2011 09:08 AM, Eduardo Bellani wrote:
>> Hello list.
>>
>> I am having a bit of a pain with trying to create a custom require
>> syntax. I am trying to save some typing in an MVC like application by
>> building some macros to recognize in the test files where the files to
>> be tested are.
>>
>> I have 2 doubts I think, one is how to retrieve the module name for the
>> my-model-test macro and the other is how to make those macros work in
>> in the require form as the target-test.rkt file tries to do.
>>
>> BTW, I have looked at the require Macros section of the docs, but so far
>> to no avail.
>>
>> For illustration, here is my (broken) code:
>>
>> ;; auxiliary.rkt
>> #lang racket
>>
>> (require rackunit
>>           racket/require-syntax
>>           rackunit/text-ui)
>>
>> (provide (all-from-out rackunit)
>>           (all-from-out rackunit/text-ui)
>>           models-test
>>           my-model-test)
>>
>> (define-syntax my-model-test
>>    (syntax-rules ()
>>      [(_)
>>       (string-append "../app/model/" *MODULE-NAME*)]))
>>
>>
>> (define-syntax models-test
>>    (syntax-rules ()
>>      [(_ model-name ...)
>>       (values (string-append "../app/model/" model-name) ...)]))
>>
>>
>>
>>
>> ;;target-test.rkt
>> (require "../auxiliary.rkt"
>>           (model-test "a-model")
>>           (my-model-test))
>>
>>
>> Any ideas?
> 
> First, you need to use define-require-syntax:
> 
>   (define-require-syntax from-model ___)
> 
> Next, since you want to compute the new path at compile time, you can't
> use syntax-rules. If you do, then you'll return the string-append
> expression as if it were a require form; but it isn't, and you'll get an
> error.
> 
>   (define-require-syntax (from-model stx)
>     (syntax-case stx ()
>       [(from-model relpath)
>        (string? (syntax-e #'relpath))  ;; only relative path, ie strings
>        ___]))
> 
> Finally, you want to append the given string to a common prefix:
> 
>   (string-append "../app/model/" (syntax-e #'relpath))
> 
> But that's a string, and your require macro must return a syntax object.
> And since require is essentially a non-hygienic binding form that binds
> names based on the lexical context of the require subforms, you get the
> lexical context right. The right lexical context in this case is the
> same as the original require form, stx:
> 
>   (datum->syntax stx
>                  (string-append "../app/model/" (syntax-e #'relpath)))
> 
> Then use it thus:
> 
>   (require (from-model "some-file.rkt")
>            (from-model "another-file.rkt"))
> 
> Ryan


- -- 
Eduardo Bellani

omnia mutantur, nihil interit.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk0t+R4ACgkQSbLl0kCTjGnzcACfYVt5hlOFGp4or0EtBFJHfZuB
YdoAn23G8S007nVUwY8dHEnmEDyCSjfP
=A4d+
-----END PGP SIGNATURE-----


Posted on the users mailing list.