-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d7dab74
commit f8a6c87
Showing
33 changed files
with
3,907 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#lang scheme/base | ||
|
||
(require "generate-lib.scm") | ||
(generate (current-command-line-arguments)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#lang scheme/base | ||
|
||
(require (file "util.scm") | ||
(planet "web.scm" ("soegaard" "web.plt" 2 1)) | ||
(file "web-support.scm") | ||
(file "settings.scm")) | ||
|
||
(provide add-closure! | ||
call-closure | ||
closure-key->url | ||
make-closure-key | ||
body-as-closure-key | ||
body-as-url | ||
handle-closure-in-req | ||
num-closures-in-memory | ||
) | ||
|
||
(define-syntax body-as-closure-key | ||
(syntax-rules () | ||
((_ (req-identifier) body ...) | ||
(add-closure! (lambda (req-identifier) body ...))) | ||
((_ (req-identifier key-identifier) body ...) | ||
(let ((key-identifier (make-closure-key))) | ||
(add-closure! #:key key-identifier | ||
(lambda (req-identifier) body ...)))))) | ||
|
||
;; | ||
;; body-as-url | ||
;; | ||
;; (body-as-url (req) body ...) | ||
;; or | ||
;; (body-as-url (req fn-key) body ...) | ||
;; In the latter form, fn-key is the key that will be used to map to body. | ||
;; This provides a way for the developer to reuse fns in certain situations. | ||
;; | ||
(define-syntax body-as-url | ||
(syntax-rules () | ||
((_ (identifiers ...) body ...) | ||
(closure-key->url (body-as-closure-key (identifiers ...) body ...))))) | ||
|
||
(define (closure-key->url clos-key) | ||
(format "~A?~A=~A" | ||
(setting *WEB_APP_URL*) | ||
(setting *CLOSURE_URL_KEY*) | ||
clos-key)) | ||
|
||
(define-syntax handle-closure-in-req | ||
(syntax-rules () | ||
((_ req no-closure-body ...) | ||
(let ((url-key (setting *CLOSURE_URL_KEY*)) | ||
(binds (request-bindings req))) | ||
(if (exists-binding? url-key binds) | ||
(call-closure (extract-binding/single url-key binds) req) | ||
(begin no-closure-body ...)))))) | ||
|
||
(define CLOSURES (make-hash)) | ||
|
||
(define (make-closure-key) | ||
(random-key-string 20)) | ||
|
||
;; returns the key | ||
(define (add-closure! clos #:key (key #f)) | ||
(let ((key (or key (make-closure-key)))) | ||
(hash-set! CLOSURES key clos) | ||
key)) | ||
|
||
(define (call-closure key req) | ||
((hash-ref CLOSURES key (lambda () | ||
(lambda (req) | ||
(format "Expired or missing function '~A'." key)))) | ||
req)) | ||
|
||
(define (num-closures-in-memory) | ||
(hash-count CLOSURES)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#lang scheme/base | ||
|
||
;; record computations | ||
|
||
(require "record.scm" | ||
"util.scm") | ||
|
||
(provide | ||
sum-recs | ||
) | ||
|
||
(define (sum-recs recs prop-to-sum) | ||
(foldl (lambda (rec acc) | ||
(+ acc (rec-prop rec prop-to-sum))) | ||
0 | ||
recs)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
LP conventions: | ||
|
||
* When a macro introduces new variable identifiers which is available | ||
in a "body" of the form, we surround the identifiers with parens, and | ||
position them just before the body. For example, | ||
|
||
(sessioned-response (sesh req) body-goes-here-and-may-refer-to-sesh-and-req ...) | ||
|
||
Here sesh and req are both identifiers (not expressions bound in the | ||
enclosing environment. The inspiration for this convention is lambda, | ||
in which, in most cases at least, the first argument is a list of | ||
identifiers. | ||
|
||
* When a function takes a single xexpr we often use the identifier | ||
"body". But if the function expects an arbitrary number of xexpr, | ||
then we encourage the use of the identifier "bodies". |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
|
||
LeftParen 1.2 Documentation | ||
|
||
Website: http://leftparen.com | ||
|
||
LeftParen is a framework for quickly creating web apps. It runs on | ||
PLT Scheme v3.99.0.23 or greater. | ||
|
||
1. Installing LeftParen | ||
|
||
You’ll need PLT Scheme v3.99.0.23 or greater installed. Note that this | ||
version is not officially released yet, so you you’ll need to get it from | ||
the pre-release | ||
download page. | ||
|
||
Make sure that mzscheme is in your path. You should be ready | ||
to go if you can do this: | ||
|
||
% mzscheme | ||
Welcome to MzScheme v3.99... | ||
> | ||
|
||
Installing LeftParen proper is done with a PLaneT | ||
require. See Tutorials for an example of this. When you | ||
first issue one of these require commands, you’ll | ||
automatically download the LeftParen files to your local PLaneT cache. | ||
This can sometimes take a few moments, so be prepared to wait a bit. | ||
|
||
2. Tutorials | ||
|
||
|
||
|
||
2.1. Hello, World | ||
|
||
We’re going to make a project called hello-world. Change to the | ||
directory that you’d like to make the project in. Then issue | ||
|
||
% mzscheme -e '(require (planet "bootstrap.scm" ("vegashacker" "leftparen.plt" 1 2)))' project hello-world | ||
|
||
This will create a hello-world project directory for you. In | ||
this directory you’ll find the script directory, which contains | ||
some useful scripts. All paths are relative to this project | ||
directory, so when calling scripts, you always want to be at the | ||
project root. | ||
|
||
% cd hello-world | ||
|
||
We need to make the scripts executable: | ||
|
||
% chmod u+x script/* | ||
|
||
LeftParen has automatically generated everything we need to run our | ||
web app—we just need to start the server (again, you should be at the project root directory): | ||
|
||
% ./script/server | ||
Web server started on port 8765 | ||
Listening on IP address: 127.0.0.1 | ||
Type stop to stop the server and exit | ||
Type restart to restart the server | ||
|
||
Point your browser to http://localhost:8765 and you should see a familiar greeting: | ||
|
||
Hello, World! | ||
|
||
2.2. Blogerton the Blog | ||
|
||
Now let’s try implementing the true "hello world" of web apps—a | ||
blog. First, execute the following commands from the directory in | ||
which you want to create your project directory: | ||
|
||
% mzscheme -e '(require (planet "bootstrap.scm" ("vegashacker" "leftparen.plt" 1 2)))' project blogerton | ||
% cd blogerton | ||
% chmod u+x script/* | ||
|
||
2.2.1. Changes to app.scm | ||
|
||
We need to register a couple of pages in our app. The | ||
index-page was already set up for you, but you’ll need to add | ||
a page to create new posts, and one to view them. Make the define-app call look like this: | ||
|
||
(define-app my-app | ||
(index-page (url "/")) | ||
(create-post-page (url "/post")) | ||
(view-post-page (url "/view/" (string-arg)))) | ||
|
||
2.2.2. Changes to main.scm | ||
|
||
Now we need to define those pages that we declared in app.scm. | ||
|
||
(define-page (index-page req) | ||
`(h1 "Blogerton") | ||
`(p ,(web-link "Create a new post" (page-url create-post-page))) | ||
`(ul ,@(map (lambda (p) `(li ,(paint-blog-post p))) | ||
(load-where '((type . blog-post)) | ||
#:sort-by 'created-at #:compare >)))) | ||
|
||
(define-page (create-post-page req) | ||
(form '((title "Title" text) (body "Body" long-text)) | ||
#:init '((type . blog-post)) | ||
#:on-done (lambda (post) (redirect-to-page view-post-page (rec-id post))))) | ||
|
||
(define-page (view-post-page req post-id) | ||
(paint-blog-post (load-rec post-id #:ensure '((type . blog-post))))) | ||
|
||
(define (paint-blog-post post) | ||
`(div (h2 ,(rec-prop post 'title)) | ||
(p ,(rec-prop post 'body)))) | ||
|
||
2.2.3. Launch Blogerton | ||
|
||
You’re ready for launch. Start the server with | ||
|
||
% ./script/server | ||
|
||
and you should have a basic blogging app, with persistent data, in 19 lines of code. | ||
|
||
3. About/Acknowledgements | ||
|
||
LeftParen was written by Rob Hunter, | ||
but it builds heavily on (and, in fact, often directly incorporates) the work of | ||
Untyped | ||
(instaservlet | ||
and | ||
dispatch), | ||
Jens Axel Soegaard | ||
(web.plt), | ||
and of course, PLT Scheme. |
Oops, something went wrong.