Back
case (clj)
(source)macro
(case e & clauses)
Takes an expression, and a set of clauses.
Each clause can take the form of either:
test-constant result-expr
(test-constant1 ... test-constantN) result-expr
The test-constants are not evaluated. They must be compile-time
literals, and need not be quoted. If the expression is equal to a
test-constant, the corresponding result-expr is returned. A single
default expression can follow the clauses, and its value will be
returned if no clause matches. If no default expression is provided
and no clause matches, an IllegalArgumentException is thrown.
Unlike cond and condp, case does a constant-time dispatch, the
clauses are not considered sequentially. All manner of constant
expressions are acceptable in case, including numbers, strings,
symbols, keywords, and (Clojure) composites thereof. Note that since
lists are used to group multiple constants that map to the same
expression, a vector can be used to match a list if needed. The
test-constants need not be all of the same type.
Examples
clojure
(deftest division
(is (= clojure.core// /))
(binding [*ns* *ns*]
(eval '(do (ns foo
(:require [clojure.core :as bar])
(:use [clojure.test]))
(is (= clojure.core// bar//))))))
(deftest reader-conditionals
(testing "basic read-cond"
(is (= '[foo-form]
(read-string {:read-cond :allow :features #{:foo}} "[#?(:foo foo-form :bar bar-form)]")))
(is (= '[bar-form]
(read-string {:read-cond :allow :features #{:bar}} "[#?(:foo foo-form :bar bar-form)]")))
(is (= '[foo-form]
(read-string {:read-cond :allow :features #{:foo :bar}} "[#?(:foo foo-form :bar bar-form)]")))
(is (= '[]
(read-string {:read-cond :allow :features #{:baz}} "[#?( :foo foo-form :bar bar-form)]"))))
(testing "environmental features"
(is (= "clojure" #?(:clj "clojure" :cljs "clojurescript" :default "default"))))
(testing "default features"
(is (= "default" #?(:clj-clr "clr" :cljs "cljs" :default "default"))))
(testing "splicing"
(is (= [] [#?@(:clj [])]))
(is (= [:a] [#?@(:clj [:a])]))
(is (= [:a :b] [#?@(:clj [:a :b])]))
(is (= [:a :b :c] [#?@(:clj [:a :b :c])]))
(is (= [:a :b :c] [#?@(:clj [:a :b :c])])))
(testing "nested splicing"
(is (= [:a :b :c :d :e]
[#?@(:clj [:a #?@(:clj [:b #?@(:clj [:c]) :d]):e])]))
(is (= '(+ 1 (+ 2 3))
'(+ #?@(:clj [1 (+ #?@(:clj [2 3]))]))))
(is (= '(+ (+ 2 3) 1)
'(+ #?@(:clj [(+ #?@(:clj [2 3])) 1]))))
(is (= [:a [:b [:c] :d] :e]
[#?@(:clj [:a [#?@(:clj [:b #?@(:clj [[:c]]) :d])] :e])])))
(testing "bypass unknown tagged literals"
(is (= [1 2 3] #?(:cljs #js [1 2 3] :clj [1 2 3])))
(is (= :clojure #?(:foo #some.nonexistent.Record {:x 1} :clj :clojure))))
(testing "error cases"
(is (thrown-with-msg? RuntimeException #"Feature should be a keyword" (read-string {:read-cond :allow} "#?((+ 1 2) :a)")))
(is (thrown-with-msg? RuntimeException #"even number of forms" (read-string {:read-cond :allow} "#?(:cljs :a :clj)")))
(is (thrown-with-msg? RuntimeException #"read-cond-splicing must implement" (read-string {:read-cond :allow} "#?@(:clj :a)")))
(is (thrown-with-msg? RuntimeException #"is reserved" (read-string {:read-cond :allow} "#?@(:foo :a :else :b)")))
(is (thrown-with-msg? RuntimeException #"must be a list" (read-string {:read-cond :allow} "#?[:foo :a :else :b]")))
(is (thrown-with-msg? RuntimeException #"Conditional read not allowed" (read-string {:read-cond :BOGUS} "#?[:clj :a :default nil]")))
(is (thrown-with-msg? RuntimeException #"Conditional read not allowed" (read-string "#?[:clj :a :default nil]")))
(is (thrown-with-msg? RuntimeException #"Reader conditional splicing not allowed at the top level" (read-string {:read-cond :allow} "#?@(:clj [1 2])")))
(is (thrown-with-msg? RuntimeException #"Reader conditional splicing not allowed at the top level" (read-string {:read-cond :allow} "#?@(:clj [1])")))
(is (thrown-with-msg? RuntimeException #"Reader conditional splicing not allowed at the top level" (read-string {:read-cond :allow} "#?@(:clj []) 1"))))
(testing "clj-1698-regression"
(let [opts {:features #{:clj} :read-cond :allow}]
(is (= 1 (read-string opts "#?(:cljs {'a 1 'b 2} :clj 1)")))
(is (= 1 (read-string opts "#?(:cljs (let [{{b :b} :a {d :d} :c} {}]) :clj 1)")))
(is (= '(def m {}) (read-string opts "(def m #?(:cljs ^{:a :b} {} :clj ^{:a :b} {}))")))
(is (= '(def m {}) (read-string opts "(def m #?(:cljs ^{:a :b} {} :clj ^{:a :b} {}))")))
(is (= 1 (read-string opts "#?(:cljs {:a #_:b :c} :clj 1)")))))
(testing "nil expressions"
(is (nil? #?(:default nil)))
(is (nil? #?(:foo :bar :clj nil)))
(is (nil? #?(:clj nil :foo :bar)))
(is (nil? #?(:foo :bar :default nil)))))
clojure/core.async
;; The clojure.core.async namespace contains the public API.
(require '[clojure.core.async :as async :refer :all])
;; Channels can also use custom buffers that have different policies
;; for the "full" case. Two useful examples are provided in the API.
hraberg/deuce
(ns deuce.emacs.casetab
(:use [deuce.emacs-lisp :only (defun defvar)])
(:require [clojure.core :as c]
[deuce.emacs.chartab :as chartab]
[deuce.emacs.data :as data]
[deuce.emacs.fns :as fns])
(:import [deuce.emacs.data CharTable])
(:refer-clojure :exclude []))
(fns/put 'case-table 'char-table-extra-slots 3)
(def ^:private ascii-downcase-table (atom (chartab/make-char-table 'case-table)))
(defun set-standard-case-table (table)
"Select a new standard case table for new buffers.
See `set-case-table' for more info on case tables."
(reset! ascii-downcase-table table))
(defun case-table-p (object)
"Return t if OBJECT is a case table.
See `set-case-table' for more information on these data structures."
(and (data/char-table-p object) (= 'case-table (.purpose ^CharTable object))))
(defun current-case-table ()
"Return the case table of the current buffer."
)
(defun set-case-table (table)
"Select a new case table for the current buffer.
A case table is a char-table which maps characters
to their lower-case equivalents. It also has three \"extra\" slots
which may be additional char-tables or nil.
These slots are called UPCASE, CANONICALIZE and EQUIVALENCES.
UPCASE maps each non-upper-case character to its upper-case equivalent.
(The value in UPCASE for an upper-case character is never used.)
If lower and upper case characters are in 1-1 correspondence,
you may use nil and the upcase table will be deduced from DOWNCASE.
CANONICALIZE maps each character to a canonical equivalent;
any two characters that are related by case-conversion have the same
canonical equivalent character; it may be nil, in which case it is
deduced from DOWNCASE and UPCASE.
EQUIVALENCES is a map that cyclically permutes each equivalence class
(of characters with the same canonical equivalent); it may be nil,
in which case it is deduced from CANONICALIZE."
)
(defun standard-case-table ()
"Return the standard case table.
This is the one used for new buffers."
@ascii-downcase-table)
hraberg/deuce
(ns deuce.emacs.print
(:use [deuce.emacs-lisp :only (defun defvar)])
(:require [clojure.core :as c]
[clojure.string :as s]
[deuce.emacs.buffer :as buffer]
[deuce.emacs.data :as data]
[deuce.emacs.editfns :as editfns]
[deuce.emacs.fns :as fns])
(:refer-clojure :exclude [print]))
(defvar float-output-format nil
"The format descriptor string used to print floats.
This is a %-spec like those accepted by `printf' in C,
but with some restrictions. It must start with the two characters `%.'.
After that comes an integer precision specification,
and then a letter which controls the format.
The letters allowed are `e', `f' and `g'.
Use `e' for exponential notation \"DIG.DIGITSeEXPT\"
Use `f' for decimal point notation \"DIGITS.DIGITS\".
Use `g' to choose the shorter of those two formats for the number at hand.
The precision in any of these cases is the number of digits following
the decimal point. With `f', a precision of 0 means to omit the
decimal point. 0 is not allowed with `e' or `g'.
- a buffer, in which case output is inserted into that buffer at point;
- a marker, in which case output is inserted at marker's position;
- a function, in which case that function is called once for each
character of OBJECT's printed representation;
- a symbol, in which case that symbol's function definition is called; or
- t, in which case the output is displayed in the echo area.
- a buffer, in which case output is inserted into that buffer at point;
- a marker, in which case output is inserted at marker's position;
- a function, in which case that function is called once for each
character of OBJECT's printed representation;
- a symbol, in which case that symbol's function definition is called; or
- t, in which case the output is displayed in the echo area.
- a buffer, in which case output is inserted into that buffer at point;
- a marker, in which case output is inserted at marker's position;
- a function, in which case that function is called once for each
character of OBJECT's printed representation;
- a symbol, in which case that symbol's function definition is called; or
- t, in which case the output is displayed in the echo area.
typedclojure/typedclojure
(ns ^:no-doc typed.ann.clojure
"Type annotations for the base Clojure distribution."
#?(:cljs (:require-macros [typed.ann-macros.clojure :as macros]))
(:require [clojure.core :as cc]
[typed.clojure :as t]
#?(:clj [typed.ann-macros.clojure :as macros])
#?(:clj typed.ann.clojure.jvm) ;; jvm annotations
#?(:clj clojure.core.typed))
#?(:clj
(:import (clojure.lang PersistentHashSet PersistentList
APersistentMap #_IPersistentCollection
#_ITransientSet
IRef)
(java.util Comparator Collection))))
cc/alength [(ReadOnlyArray t/Any) :-> t/AnyInteger]
cc/aclone (t/All [x] [(ReadOnlyArray x) :-> (Array x)])
cc/aget (t/All [x]
(t/IFn [(ReadOnlyArray x)
t/AnyInteger :-> x]
[(ReadOnlyArray (ReadOnlyArray x))
t/AnyInteger t/AnyInteger :-> x]
[(ReadOnlyArray (ReadOnlyArray (ReadOnlyArray x)))
t/AnyInteger t/AnyInteger t/AnyInteger :-> x]
[(ReadOnlyArray (ReadOnlyArray (ReadOnlyArray (ReadOnlyArray x))))
t/AnyInteger t/AnyInteger t/AnyInteger t/AnyInteger :-> x]
; don't support unsound cases
[(ReadOnlyArray (ReadOnlyArray (ReadOnlyArray (ReadOnlyArray (ReadOnlyArray x)))))
t/AnyInteger t/AnyInteger t/AnyInteger t/AnyInteger t/AnyInteger :-> x]))
clojure.string/upper-case [CharSequence :-> t/Str]
clojure.string/blank? [(t/U nil t/Str) :-> t/Bool]
clojure.string/capitalize [t/Str :-> t/Str]
clojure.string/lower-case [t/Str :-> t/Str]
clojure.string/replace [(t/alt (t/cat t/Str t/Str t/Str)
(t/cat t/Str Character Character)
(t/cat t/Str t/Regex (t/U t/Str [t/Str :-> t/Str]))) :-> t/Str]
clojure.string/replace-first [(t/alt (t/cat t/Str t/Str t/Str)
(t/cat t/Str Character Character)
(t/cat t/Str t/Regex (t/U t/Str [t/Str :-> t/Str]))) :-> t/Str]
clojure.string/reverse [t/Str :-> t/Str]
clojure.string/trim [t/Str :-> t/Str]
clojure.string/trimr [t/Str :-> t/Str]
clojure.string/triml [t/Str :-> t/Str]
;should be special cased
cc/not= [(t/+ t/Any) :-> t/Bool]
Flexiana/framework
(ns xiana.interceptor.kebab-camel
(:require
[camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske]
[clojure.core.memoize :as mem]))
(def camel-to-kebab
(fn [resp]
(cske/transform-keys
(mem/fifo csk/->kebab-case {} :fifo/threshold 512) resp)))
(def interceptor
"The purpose is to make Js request compatible with clojure, and response compatible with Javascript.
:request - {:params { "
{:name ::camel-to-kebab-case
:enter (fn [state]
(reduce
(fn [state type-param]
(update-in state [:request type-param] camel-to-kebab))
state
request-type-params))
:leave (fn [state]
(update-in state [:response :body] kebab-to-camel))})