-
Notifications
You must be signed in to change notification settings - Fork 9
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
Showing
10 changed files
with
1,508 additions
and
153 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
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
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
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,6 @@ | ||
{:cljdoc.doc/tree [["Readme" {:file "README.md"}] | ||
["Changelog" {:file "CHANGELOG.md"}] | ||
["Overview" {:file "doc/overview.md"}] | ||
["Object Extraction" {:file "doc/object.md"}] | ||
["Recursive Beans" {:file "doc/recursive.md"}] | ||
["Key Mapping" {:file "doc/key-mapping.md"}]} |
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,32 @@ | ||
# Key Mapping | ||
|
||
By default, the map produced by `bean` keywordizes the keys. If instead you pass `:keywordize-keys` `false`, | ||
string keys will be produced: | ||
|
||
```clojure | ||
(bean #js {:a 1, :b 2, "c/d" 3, "e f" 4} :keywordize-keys false) | ||
;; => {"a" 1, "b" 2, "c/d" 3, "e f" 4} | ||
``` | ||
|
||
In either of these modes, `bean` is meant to interoperate with JavaScript objects | ||
via property names that will not be renamed by Google Closure Compiler. | ||
|
||
You can control the key to property name mapping by supplying both `:key->prop` and `:prop->key`. | ||
|
||
The following example mimics the behavior of ClojureScript's JavaScript object literal syntax, where | ||
keywords are used only if properties can be represented as simple keywords: | ||
|
||
```clojure | ||
(defn prop->key [prop] | ||
(cond-> prop | ||
(some? (re-matches #"[A-Za-z_\*\+\?!\-'][\w\*\+\?!\-']*" prop)) keyword)) | ||
|
||
(defn key->prop [key] | ||
(cond | ||
(simple-keyword? key) (name key) | ||
(and (string? key) (string? (prop->key key))) key | ||
:else nil)) | ||
|
||
(bean #js {:a 1, :b 2, "c/d" 3, "e f" 4} :prop->key prop->key :key->prop key->prop) | ||
;; => {:a 1, :b 2, "c/d" 3, "e f" 4} | ||
``` |
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,64 @@ | ||
# Object Extraction | ||
|
||
Where possible, operations such as `assoc` and `conj` on a bean produce a new bean. | ||
|
||
In these cases, the `bean?` predicate will be satisfied on the result. If so, `object` | ||
can be used to extract the wrapped JavaScript object from the bean: | ||
|
||
```clojure | ||
(require '[cljs-bean.core :refer [bean bean? object]]) | ||
|
||
(assoc (bean #js {:a 1}) :b 2) | ||
;; => {:a 1, :b 2} | ||
|
||
(bean? *1) | ||
;; => true | ||
|
||
(object *2) | ||
;; => #js {:a 1, :b 2} | ||
``` | ||
|
||
This enables flexible and efficient ways to create JavaScript objects | ||
using Clojure idioms, without having to reach for `clj->js`. | ||
|
||
For example, the following builds a JavaScript object, setting its property values: | ||
|
||
```clojure | ||
(let [m {:a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7, :h 8}] | ||
(object (into (bean) (filter (comp odd? val)) m))) | ||
;; => #js {:a 1, :c 3, :e 5, :g 7} | ||
``` | ||
|
||
The example above is particularly efficient because no intermediate sequence is | ||
generated and—owing to transients support in beans—the properties are set by | ||
mutating a single object instance. | ||
|
||
It is not possible for `assoc` or `conj` to produce a bean if, for example, a string key is | ||
added to a bean configured to keywordize keys: | ||
|
||
```clojure | ||
(assoc (bean #js {:a 1}) "b" 2 :c 3) | ||
;; => {:a 1, "b" 2, :c 3} | ||
|
||
(bean? *1) | ||
;; => false | ||
``` | ||
|
||
The `->js` converter will automatically check and employ the fast-path | ||
constant time conversion where possible, falling back to `clj->js` if not. | ||
|
||
Since `->clj` and `->js` are recursive, they can be used as simplified | ||
drop-in replacements for `js->clj` and `clj->js`, taking the fast path | ||
where possible. | ||
|
||
In the following example, a thin wrapper produced by `->clj` allows the | ||
use of `update-in` to produce a new JavaScript object, which is accessed | ||
via `->js`: | ||
|
||
```clojure | ||
(require '[cljs-bean.core :refer [->clj ->js]]) | ||
|
||
(let [o #js {:a #js {:b 1}}] | ||
(-> o ->clj (update-in [:a :b] inc) ->js)) | ||
;; #js {:a #js {:b 2}} | ||
``` |
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,43 @@ | ||
# Overview | ||
|
||
The `bean` function produces a thin wrapper over JavaScript objects, implementing the map abstraction: | ||
|
||
```clojure | ||
(require '[cljs-bean.core :refer [bean]]) | ||
|
||
(bean #js {:a 1, :b 2}) | ||
;; {:a 1, :b 2} | ||
``` | ||
|
||
If a bean is going to be retained, the object passed | ||
should be effectively immutable, as the resulting bean is backed by the object. | ||
|
||
By default, the `bean` function behaves like Clojure’s in that it is not recursive: | ||
|
||
```clojure | ||
(bean #js {:a 1, :obj #js {:x 13, :y 17}, :arr #js [1 2 3]}) | ||
;; {:a 1, :obj #js {:x 13, :y 17}, :arr #js [1 2 3]} | ||
``` | ||
|
||
On the other hand, CLSJ Bean provides `->clj` and `->js` converters, which _are_ recursive. | ||
|
||
```clojure | ||
(require '[cljs-bean.core :refer [->clj ->js]]) | ||
|
||
(->clj #js {:a 1, :obj #js {:x 13, :y 17}, :arr #js [1 2 3]}) | ||
;; {:a 1, :obj {:x 13, :y 17}, :arr [1 2 3]} | ||
``` | ||
|
||
You can update an object produced by `->clj` | ||
|
||
```clojure | ||
(-> *1 (update-in [:obj :y] inc) (update :arr pop)) | ||
;; {:a 1, :obj {:x 13, :y 18}, :arr [1 2]} | ||
``` | ||
|
||
and the result above can be converted back to JavaScript via a constant time call to `->js`: | ||
|
||
```clojure | ||
(->js *1) | ||
;; #js {:a 1, :obj #js {:x 13, :y 18}, :arr #js [1 2]} | ||
``` |
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,22 @@ | ||
# Recursive Beans | ||
|
||
By default, the `bean` function behaves like Clojure’s in that it is not recursive: | ||
|
||
```clojure | ||
(bean #js {:a 1, :obj #js {:x 13, :y 17} :vec #js [1 2 3]}) | ||
;; => {:a 1, :obj #js {:x 13, :y 17} :vec #js [1 2 3]} | ||
``` | ||
|
||
Beans can be made to behave more like `js->clj` by supplying `:recursive` `true`: | ||
|
||
```clojure | ||
(bean #js {:a 1, :obj #js {:x 13, :y 17} :vec #js [1 2 3]} :recursive true) | ||
;; => {:a 1, :obj {:x 13, :y 17} :vec [1 2 3]} | ||
``` | ||
|
||
The `->clj` converter, when applied to JavaScript objects, automatically supplies `:recursive true`, so the above can be simplified to | ||
|
||
```clojure | ||
(->clj #js {:a 1, :obj #js {:x 13, :y 17} :vec #js [1 2 3]}) | ||
;; => {:a 1, :obj {:x 13, :y 17} :vec [1 2 3]} | ||
``` |
Oops, something went wrong.