Skip to content

Instantly share code, notes, and snippets.

@samdphillips
Last active November 5, 2019 00:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save samdphillips/abfd8b477d5963e929ec4449815b0a38 to your computer and use it in GitHub Desktop.
Save samdphillips/abfd8b477d5963e929ec4449815b0a38 to your computer and use it in GitHub Desktop.
Using Rebellion in Anger

Rebellion Examples

Here are some "real world" (some day to day one-time tasks from my work) using Rebellion(pkg, github) an infrastructure library for Racket.

#lang racket/base
#|
Given a directory containing a bunch of files with data,
...
#s(db-info "myhostname1" "/var/lib/db/mydatabase" 588969)
...
#s(db-info "myhostname110" "/var/lib/db/mydatabase" 234457)
find the aggregate size per database. We also skip some internal databases.
|#
(require racket/function
racket/match
racket/path
racket/sequence
unstable/match
rebellion/collection/entry
rebellion/collection/hash
rebellion/streaming/reducer
rebellion/streaming/transducer)
(define (combining-into-hash combiner)
(define (update-hash h e)
(define k (entry-key e))
(define v (entry-value e))
(hash-update h k (λ (old) (combiner old v)) (λ () v)))
(make-fold-reducer update-hash empty-hash #:name 'combining-into-hash))
(struct db-info (hostname path size) #:prefab)
(define (db-info-name a-db-info)
(match (db-info-path a-db-info)
[(pregexp #px"/([^/]+)$" (list _ name)) name]))
(define DATA-DIR (build-path (current-directory) "size-data"))
(define (rktd-file? filename)
(bytes=? (path-get-extension filename) #".rktd"))
(define (internal-file? filename)
(match? filename
(regexp #rx"^_")
"kvstore"
"scratch"))
(define (file->records filename)
(with-input-from-file filename
(lambda ()
(sequence->list (in-port read)))))
(transduce (directory-list DATA-DIR #:build? #t)
(filtering rktd-file?)
(append-mapping file->records)
(bisecting db-info-name values)
(filtering-keys (negate internal-file?))
(mapping-values db-info-size)
#:into (combining-into-hash +))
#lang racket/base
#|
Simply parsing an INI-style file into a hash.
|#
(require (for-syntax racket/base
syntax/parse)
racket/function
racket/match
(rename-in rebellion/base/variant
[variant orig:variant])
rebellion/collection/entry
rebellion/collection/hash
rebellion/streaming/reducer
rebellion/streaming/transducer)
(define-match-expander variant
(syntax-parser
[(_ tag:keyword pat)
#'(? variant?
(? (lambda (v) (variant-tagged-as? v 'tag))
(app variant-value pat)))])
(make-rename-transformer #'orig:variant))
(define generate-conf
(make-transducer #:starter
(lambda () (variant #:consume #f))
#:consumer
(match-lambda**
[(#f (variant #:entry _))
(variant #:consume #f)]
[(#f (variant #:section name))
(variant #:consume (list name))]
[(vs (variant #:entry e))
(variant #:consume (cons e vs))]
[(vs (variant #:section name))
(let ([vs (reverse vs)])
(variant #:emit
(cons (entry (car vs) (cdr vs))
name)))])
#:emitter
(match-lambda
[(cons emit name)
(emission (variant #:consume (list name)) emit)])
#:half-closed-emitter
(lambda (state)
(let ([vs (reverse state)])
(half-closed-emission (variant #:finish #f)
(entry (car vs) (cdr vs)))))
#:half-closer
(lambda (state)
(variant #:half-closed-emit state))
#:finisher void))
(define strip-comments
(match-lambda
[(regexp #rx"^([^#]*)#.*$" (list _ data)) data]
[data data]))
(define (empty-string? s)
(regexp-match? #rx"^\\s*$" s))
(define classify-line
(match-lambda
[(regexp #rx"\\[([^]]+)]" (list _ name))
(variant #:section name)]
[(pregexp #px"^(.*?)\\s*=\\s*(\\d+)$" (list _ key value))
(variant #:entry (entry key (string->number value)))]
[(pregexp #px"^(.*?)\\s*=\\s*(.*)$" (list _ key value))
(variant #:entry (entry key value))]))
(define variable-pattern #px"\\$([A-Z_]+)")
(define (expand-variables lookup-hash)
(lambda (input-string)
(regexp-replace variable-pattern
input-string
(lambda (s name)
(hash-ref lookup-hash name (lambda () s))))))
(call-with-input-file "database.conf"
(lambda (inp)
(transduce (in-lines inp)
(mapping strip-comments)
(filtering (negate empty-string?))
(mapping (expand-variables
(hash "DB_PATH" "/var/lib/db")))
(mapping classify-line)
generate-conf
(mapping-values
(lambda (vs)
(reduce-all into-hash vs)))
#:into
into-hash)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment