parent
e613f0cade
commit
d8e538d53e
@ -1,46 +0,0 @@
|
|||||||
#lang racket/base
|
|
||||||
(require "define.rkt" "coerce.rkt" "len.rkt" racket/list racket/set racket/sequence racket/stream racket/dict)
|
|
||||||
|
|
||||||
(define (sliceable-container? x)
|
|
||||||
(ormap (λ(proc) (proc x)) (list list? string? symbol? vector? path? (λ(i) (and (not (dict? i)) (sequence? i))))))
|
|
||||||
|
|
||||||
(define (gettable-container? x)
|
|
||||||
(ormap (λ(proc) (proc x)) (list sliceable-container? dict?)))
|
|
||||||
|
|
||||||
|
|
||||||
(define+provide+safe (get container start [end #f])
|
|
||||||
((gettable-container? any/c) ((or/c (and/c integer? positive?) #f)) . ->* . any)
|
|
||||||
|
|
||||||
(define result
|
|
||||||
;; use handler to capture error & print localized error message
|
|
||||||
(with-handlers ([exn:fail? (λ(exn) (error (format "get: couldn't retrieve ~a from ~a" (if end (format "items ~a through ~a" start end) (format "item ~a" start)) container)))])
|
|
||||||
(let ([end (if (and (equal? end #f) (sliceable-container? container)) (add1 start) end)])
|
|
||||||
(cond
|
|
||||||
[(list? container) (for/list ([i (in-range start end)]) (list-ref container i))]
|
|
||||||
[(vector? container) (for/vector ([i (in-range start end)]) (vector-ref container i))]
|
|
||||||
[(string? container) (substring container start end)]
|
|
||||||
[(symbol? container) (->symbol (get (->string container) start end))]
|
|
||||||
[(path? container) (get (explode-path container) start end)]
|
|
||||||
[(dict? container) (dict-ref container start)]
|
|
||||||
[(sequence? container) (get (->list container) start end)]
|
|
||||||
[else (error)]))))
|
|
||||||
|
|
||||||
;; don't return single-item results inside a list
|
|
||||||
;; check for integer because integers don't have length
|
|
||||||
(if (and (not (integer? result)) (= (len result) 1) (sliceable-container? container))
|
|
||||||
(car (->list result))
|
|
||||||
result))
|
|
||||||
|
|
||||||
(define (listlike-container? container)
|
|
||||||
(ormap (λ(pred) (pred container)) (list vector? set? sequence?)))
|
|
||||||
|
|
||||||
(define+provide+safe (in? item container)
|
|
||||||
(any/c any/c . -> . boolean?)
|
|
||||||
(->boolean (cond
|
|
||||||
[(list? container) (member item container)]
|
|
||||||
[(dict? container) (dict-has-key? container item)]
|
|
||||||
[(path? container) (in? (->path item) (explode-path container))]
|
|
||||||
[(stringish? container) (regexp-match (->string item) (->string container))]
|
|
||||||
;; location relevant because dicts and strings are also listlike (= sequences)
|
|
||||||
[(listlike-container? container) (in? item (->list container))]
|
|
||||||
[else #f])))
|
|
@ -1,5 +1,6 @@
|
|||||||
#lang info
|
#lang info
|
||||||
(define collection "sugar")
|
(define collection "sugar")
|
||||||
|
(define version "0.1")
|
||||||
(define deps '("base" "rackunit-lib"))
|
(define deps '("base" "rackunit-lib"))
|
||||||
(define build-deps '("scribble-lib" "racket-doc"))
|
(define build-deps '("scribble-lib" "racket-doc"))
|
||||||
(define scribblings '(("scribblings/sugar.scrbl" ())))
|
(define scribblings '(("scribblings/sugar.scrbl" ())))
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#lang racket/base
|
|
||||||
(require "define.rkt" racket/set racket/sequence)
|
|
||||||
|
|
||||||
(define+provide+safe (len x)
|
|
||||||
((or/c list? vector? set? sequence? string? symbol? path? hash?) . -> . integer?)
|
|
||||||
(cond
|
|
||||||
[(list? x) (length x)]
|
|
||||||
[(string? x) (string-length x)]
|
|
||||||
[(symbol? x) (len (symbol->string x))]
|
|
||||||
[(path? x) (len (path->string x))]
|
|
||||||
[(vector? x) (vector-length x)]
|
|
||||||
[(hash? x) (len (hash-keys x))]
|
|
||||||
[(set? x) (len (set->list x))]
|
|
||||||
[(and (sequence? x) (not (integer? x))) (len (sequence->list x))]
|
|
||||||
[else (error "len: can't calculate length of" x)]))
|
|
@ -1,25 +0,0 @@
|
|||||||
#lang racket/base
|
|
||||||
(require "define.rkt" "coerce.rkt")
|
|
||||||
|
|
||||||
|
|
||||||
(define+provide+safe (starts-with? str starter)
|
|
||||||
(string? string? . -> . coerce/boolean?)
|
|
||||||
(let ([str (->string str)]
|
|
||||||
[starter (->string starter)])
|
|
||||||
(and (<= (string-length starter) (string-length str))
|
|
||||||
(equal? (substring str 0 (string-length starter)) starter))))
|
|
||||||
|
|
||||||
|
|
||||||
(define+provide+safe (ends-with? str ender)
|
|
||||||
(string? string? . -> . coerce/boolean?)
|
|
||||||
(let ([str (->string str)]
|
|
||||||
[ender (->string ender)])
|
|
||||||
(and (<= (string-length ender) (string-length str))
|
|
||||||
(equal? (substring str (- (string-length str) (string-length ender)) (string-length str)) ender))))
|
|
||||||
|
|
||||||
|
|
||||||
(define+provide+safe (capitalized? str)
|
|
||||||
(string? . -> . coerce/boolean?)
|
|
||||||
(let ([str (->string str)])
|
|
||||||
(char-upper-case? (car (string->list str)))))
|
|
||||||
|
|
@ -0,0 +1,86 @@
|
|||||||
|
#lang racket/base
|
||||||
|
(require "../define.rkt" "../coerce.rkt" "len.rkt" racket/list racket/set racket/sequence racket/stream racket/dict)
|
||||||
|
|
||||||
|
(define (sliceable-container? x)
|
||||||
|
(ormap (λ(proc) (proc x)) (list list? string? symbol? vector? path? (λ(i) (and (not (dict? i)) (sequence? i))))))
|
||||||
|
|
||||||
|
(define (gettable-container? x)
|
||||||
|
(ormap (λ(proc) (proc x)) (list sliceable-container? dict?)))
|
||||||
|
|
||||||
|
|
||||||
|
(define+provide+safe (get container start [end #f])
|
||||||
|
((gettable-container? any/c) ((or/c (and/c integer? positive?) #f)) . ->* . any)
|
||||||
|
|
||||||
|
(define result
|
||||||
|
;; use handler to capture error & print localized error message
|
||||||
|
(with-handlers ([exn:fail? (λ(exn) (error (format "get: couldn't retrieve ~a from ~a" (if end (format "items ~a through ~a" start end) (format "item ~a" start)) container)))])
|
||||||
|
(let ([end (if (and (equal? end #f) (sliceable-container? container)) (add1 start) end)])
|
||||||
|
(cond
|
||||||
|
[(list? container) (for/list ([i (in-range start end)]) (list-ref container i))]
|
||||||
|
[(vector? container) (for/vector ([i (in-range start end)]) (vector-ref container i))]
|
||||||
|
[(string? container) (substring container start end)]
|
||||||
|
[(symbol? container) (->symbol (get (->string container) start end))]
|
||||||
|
[(path? container) (get (explode-path container) start end)]
|
||||||
|
[(dict? container) (dict-ref container start)]
|
||||||
|
[(sequence? container) (get (->list container) start end)]
|
||||||
|
[else (error)]))))
|
||||||
|
|
||||||
|
;; don't return single-item results inside a list
|
||||||
|
;; check for integer because integers don't have length
|
||||||
|
(if (and (not (integer? result)) (= (len result) 1) (sliceable-container? container))
|
||||||
|
(car (->list result))
|
||||||
|
result))
|
||||||
|
|
||||||
|
(define (listlike-container? container)
|
||||||
|
(ormap (λ(pred) (pred container)) (list vector? set? sequence?)))
|
||||||
|
|
||||||
|
(define+provide+safe (in? item container)
|
||||||
|
(any/c any/c . -> . boolean?)
|
||||||
|
(->boolean (cond
|
||||||
|
[(list? container) (member item container)]
|
||||||
|
[(dict? container) (dict-has-key? container item)]
|
||||||
|
[(path? container) (in? (->path item) (explode-path container))]
|
||||||
|
[(stringish? container) (regexp-match (->string item) (->string container))]
|
||||||
|
;; location relevant because dicts and strings are also listlike (= sequences)
|
||||||
|
[(listlike-container? container) (in? item (->list container))]
|
||||||
|
[else #f])))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(require rackunit)
|
||||||
|
(check-equal? (get '(0 1 2 3 4 5) 2) 2)
|
||||||
|
(check-exn exn:fail? (λ() (get '(0 1 2 3 4 5) 100))) ; index too big
|
||||||
|
(check-equal? (get `(0 1 ,(list 2) 3 4 5) 2) (list 2))
|
||||||
|
(check-equal? (get '(0 1 2 3 4 5) 0 2) '(0 1))
|
||||||
|
(check-equal? (get (list->vector '(0 1 2 3 4 5)) 2) 2)
|
||||||
|
(check-equal? (get (list->vector'(0 1 2 3 4 5)) 0 2) (list->vector '(0 1)))
|
||||||
|
(check-equal? (get "purple" 2) "r")
|
||||||
|
(check-equal? (get "purple" 0 2) "pu")
|
||||||
|
(check-equal? (get 'purple 2) 'r)
|
||||||
|
(check-equal? (get 'purple 0 2) 'pu)
|
||||||
|
(check-equal? (get (string->path "/root/foo/bar/file.txt") 2) (string->path "foo"))
|
||||||
|
(check-equal? (get (string->path "/root/foo/bar/file.txt") 0 2) (list (string->path "/") (string->path "root")))
|
||||||
|
(check-equal? (get (make-hash `((a . ,(list 1)) (b . ,(list 2)) (c . ,(list 3)))) 'a) (list 1))
|
||||||
|
(check-exn exn:fail? (λ() (get (make-hash `((a . ,(list 1)) (b . ,(list 2)) (c . ,(list 3)))) 'z))) ; nonexistent key
|
||||||
|
|
||||||
|
(check-equal? (get (string->path "/root/foo/bar/file.txt") 1) (string->path "root"))
|
||||||
|
(check-equal? (get (string->path "/root/foo/bar/file.txt") 0 3)
|
||||||
|
(map string->path '("/" "root" "foo")))
|
||||||
|
|
||||||
|
(check-equal? (get (make-hash '((a . 1) (b . 2) (c . 3))) 'b) 2)
|
||||||
|
|
||||||
|
(check-true (2 . in? . '(1 2 3)))
|
||||||
|
(check-false (4 . in? . '(1 2 3)))
|
||||||
|
(check-true (2 . in? . (list->vector '(1 2 3))))
|
||||||
|
(check-false (4 . in? . (list->vector '(1 2 3))))
|
||||||
|
(check-true ('a . in? . (make-hash '((a . 1) (b . 2) (c . 3)))))
|
||||||
|
(check-false ('x . in? . (make-hash '((a . 1) (b . 2) (c . 3)))))
|
||||||
|
(check-true ("o" . in? . "foobar"))
|
||||||
|
(check-false ("z" . in? . "foobar"))
|
||||||
|
(check-true ('o . in? . 'foobar))
|
||||||
|
(check-false ('z . in? . 'foobar))
|
||||||
|
(check-true ("F" . in? . #\F))
|
||||||
|
|
||||||
|
(check-true (in? "foo" (string->path "/root/foo/bar/file.txt")))
|
||||||
|
(check-false (in? "zam" (string->path "/root/foo/bar/file.txt"))))
|
@ -0,0 +1,31 @@
|
|||||||
|
#lang racket/base
|
||||||
|
(require "../define.rkt" racket/set racket/sequence)
|
||||||
|
|
||||||
|
(define+provide+safe (len x)
|
||||||
|
((or/c list? vector? set? sequence? string? symbol? path? hash?) . -> . integer?)
|
||||||
|
(cond
|
||||||
|
[(list? x) (length x)]
|
||||||
|
[(string? x) (string-length x)]
|
||||||
|
[(symbol? x) (len (symbol->string x))]
|
||||||
|
[(path? x) (len (path->string x))]
|
||||||
|
[(vector? x) (vector-length x)]
|
||||||
|
[(hash? x) (len (hash-keys x))]
|
||||||
|
[(set? x) (len (set->list x))]
|
||||||
|
[(and (sequence? x) (not (integer? x))) (len (sequence->list x))]
|
||||||
|
[else (error "len: can't calculate length of" x)]))
|
||||||
|
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(require rackunit)
|
||||||
|
(check-equal? (len '(1 2 3)) 3)
|
||||||
|
(check-not-equal? (len '(1 2)) 3) ; len 2
|
||||||
|
(check-equal? (len "foo") 3)
|
||||||
|
(check-not-equal? (len "fo") 3) ; len 2
|
||||||
|
(check-equal? (len 'foo) 3)
|
||||||
|
(check-not-equal? (len 'fo) 3) ; len 2
|
||||||
|
(check-equal? (len (list->vector '(1 2 3))) 3)
|
||||||
|
(check-not-equal? (len (list->vector '(1 2))) 3) ; len 2
|
||||||
|
(check-equal? (len (set 1 2 3)) 3)
|
||||||
|
(check-not-equal? (len (set 1 2)) 3) ; len 2
|
||||||
|
(check-equal? (len (make-hash '((a . 1) (b . 2) (c . 3)))) 3)
|
||||||
|
(check-not-equal? (len (make-hash '((a . 1) (b . 2)))) 3)) ; len 2
|
@ -1,5 +1,5 @@
|
|||||||
#lang racket/base
|
#lang racket/base
|
||||||
(require "define.rkt" racket/set "coerce.rkt")
|
(require "../define.rkt" racket/set "../coerce.rkt")
|
||||||
|
|
||||||
|
|
||||||
(define+provide+safe (bytecount->string bytecount)
|
(define+provide+safe (bytecount->string bytecount)
|
@ -0,0 +1,37 @@
|
|||||||
|
#lang racket/base
|
||||||
|
(require "../define.rkt" "../coerce.rkt")
|
||||||
|
|
||||||
|
|
||||||
|
(define+provide+safe (starts-with? str starter)
|
||||||
|
(string? string? . -> . coerce/boolean?)
|
||||||
|
(define pat (regexp (format "^~a" (regexp-quote starter))))
|
||||||
|
(and (regexp-match pat (->string str)) #t))
|
||||||
|
|
||||||
|
|
||||||
|
(define+provide+safe (ends-with? str ender)
|
||||||
|
(string? string? . -> . coerce/boolean?)
|
||||||
|
(define pat (regexp (format "~a$" (regexp-quote ender))))
|
||||||
|
(and (regexp-match pat (->string str)) #t))
|
||||||
|
|
||||||
|
|
||||||
|
(define+provide+safe (capitalized? str-in)
|
||||||
|
(string? . -> . coerce/boolean?)
|
||||||
|
(define str (->string str-in))
|
||||||
|
(and (positive? (string-length str))
|
||||||
|
(char-upper-case? (car (string->list (car (regexp-match "." str)))))))
|
||||||
|
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(require rackunit)
|
||||||
|
(check-true (starts-with? "foobar" "foo"))
|
||||||
|
(check-true (starts-with? "foobar" "foobar"))
|
||||||
|
(check-false (starts-with? "foobar" "zam"))
|
||||||
|
(check-false (starts-with? "foobar" "foobars"))
|
||||||
|
(check-false (starts-with? "foo" "."))
|
||||||
|
(check-true (ends-with? "foobar" "bar"))
|
||||||
|
(check-false (ends-with? "foobar" "zam"))
|
||||||
|
(check-true (ends-with? "foobar" "foobar"))
|
||||||
|
(check-false (ends-with? "foobar" "foobars"))
|
||||||
|
(check-true (capitalized? "Brennan"))
|
||||||
|
(check-false (capitalized? "foobar")))
|
||||||
|
|
Loading…
Reference in New Issue