https://github.com/metametadata/carry
ClojureScript application framework.
https://github.com/metametadata/carry
debugger framework gui mvc react reagent
Last synced: 3 months ago
JSON representation
ClojureScript application framework.
- Host: GitHub
- URL: https://github.com/metametadata/carry
- Owner: metametadata
- License: mit
- Created: 2016-02-18T17:50:32.000Z (almost 10 years ago)
- Default Branch: master
- Last Pushed: 2019-06-21T07:16:55.000Z (over 6 years ago)
- Last Synced: 2025-09-26T21:31:11.637Z (4 months ago)
- Topics: debugger, framework, gui, mvc, react, reagent
- Language: Clojure
- Homepage: https://metametadata.github.io/carry/
- Size: 31.7 MB
- Stars: 149
- Watchers: 11
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Carry
ClojureScript single-page application framework inspired by
[re-frame](https://github.com/Day8/re-frame),
[Elm Architecture](https://guide.elm-lang.org/architecture/),
[Redux](https://github.com/reactjs/redux/) and
[Cerebral](https://github.com/cerebral/cerebral).
Carry provides a structure for making GUI application code easier to modify, debug, test and be worked on by multiple programmers.
The core of the framework is a simple state management library.
UI bindings, routing, debugger, etc. are implemented as separate optional [packages](#packages).
[](https://clojars.org/carry)
[](https://gitter.im/metametadata/carry)
[](https://clojurians.slack.com/messages/carry/)
## Status
Stable. Was used in production.
I now focus on the successor [Aide](https://github.com/metametadata/aide) framework instead.
## Features
* Functional API without globals and macros.
* Agnostic to UI layer: can be effectively used with [Reagent](https://github.com/reagent-project/reagent)
(via [carry-reagent](https://github.com/metametadata/carry/tree/master/contrib/reagent/) package) or
any other view layer that is able to re-render UI in response to app model changes.
* [Time traveling debugger](https://github.com/metametadata/carry/tree/master/contrib/debugger)
inspired by [Redux DevTools](https://github.com/gaearon/redux-devtools) and [Cerebral Debugger](http://www.cerebraljs.com/documentation/the_debugger).
* Live code editing using [Figwheel](https://github.com/bhauman/lein-figwheel) and debugger's replay mode.
* Can work with [Devcards](https://github.com/bhauman/devcards).
* Core library can be also used in Clojure projects.
## Pattern
Carry enforces:
* Separation of presentation code.
* Events as first-class citizens.
* Splitting event handling code into side-effectful and "pure" model updating phases.
* Storing model in a single observable atom.
It also advises to decouple view and view model code in the presentation layer:

* An app is defined by its initial model value, signal handler and action handler.
* All app state is stored inside a single model atom.
* Anyone can read model value at any given time and subscribe to its changes.
* Signal handler performs side effects and dispatches actions.
* Anyone can dispatch a new signal: signal handler, views, timers, etc.
* Typically UI layer dispatches signals on UI events and subscribes to model changes to redraw the GUI when needed.
* Model can be modified only by dispatching actions.
* Only signal handler can dispatch actions.
* Action handler is a pure function which returns a new model value based on an incoming action.
## Example (counter app)
[Demo](https://metametadata.github.com/carry/examples/counter),
[Source code](https://github.com/metametadata/carry/tree/master/examples/counter)
HTML:
```html
Carry • Counter
```
Main file:
```clj
(ns app.core
(:require [counter.core :as counter]
[carry.core :as carry]
[carry-reagent.core :as carry-reagent]
[reagent.core :as r]))
(let [app (carry/app counter/blueprint)
[_ app-view] (carry-reagent/connect app counter/view-model counter/view)]
(r/render app-view (.getElementById js/document "root"))
((:dispatch-signal app) :on-start))
```
UI (using [Reagent](https://github.com/reagent-project/reagent) and [carry-reagent](https://github.com/metametadata/carry/tree/master/contrib/reagent/)):
```clj
(ns counter.core
(:require [cljs.core.match :refer-macros [match]]
[reagent.ratom :refer [reaction]]))
(defn view-model
[model]
{:counter (reaction (str "#" (:val @model)))})
(defn view
[{:keys [counter] :as _view-model} dispatch]
[:p
@counter " "
[:button {:on-click #(dispatch :on-increment)} "+"] " "
[:button {:on-click #(dispatch :on-decrement)} "-"] " "
[:button {:on-click #(dispatch :on-increment-if-odd)} "Increment if odd"] " "
[:button {:on-click #(dispatch :on-increment-async)} "Increment async"]])
```
Blueprint:
```clj
(def -initial-model {:val 0})
(defn -on-signal
[model signal _dispatch-signal dispatch-action]
(match signal
:on-start nil
:on-stop nil
:on-increment
(dispatch-action :increment)
:on-decrement
(dispatch-action :decrement)
:on-increment-if-odd
(when (odd? (:val @model))
(dispatch-action :increment))
:on-increment-async
(.setTimeout js/window #(dispatch-action :increment) 1000)))
(defn -on-action
[model action]
(match action
:increment (update model :val inc)
:decrement (update model :val dec)))
(def blueprint {:initial-model -initial-model
:on-signal -on-signal
:on-action -on-action})
```
## Packages
### UI Bindings
* [carry-reagent](https://github.com/metametadata/carry/tree/master/contrib/reagent/)
(bindings for [Reagent](https://github.com/reagent-project/reagent))
### Middleware
* [carry-atom-sync](https://github.com/metametadata/carry/tree/master/contrib/atom-sync)
(creating a bidirectional sync between an app model and a specified atom-like reference)
* [carry-debugger](https://github.com/metametadata/carry/tree/master/contrib/debugger)
(time traveling debugger)
* [carry-history](https://github.com/metametadata/carry/tree/master/contrib/history)
(working with browser history)
* [carry-logging](https://github.com/metametadata/carry/tree/master/contrib/logging)
(console logging)
* [carry-persistence](https://github.com/metametadata/carry/tree/master/contrib/persistence)
(automatic model saving/loading using browser storage)
* [carry-schema](https://github.com/metametadata/carry/tree/master/contrib/schema)
(model validation using [Schema](https://github.com/plumatic/schema))
## Documentation
More information can be found at [the project site](http://metametadata.github.io/carry/):
* [User Guide](http://metametadata.github.io/carry/user-guide/)
* [Examples](http://metametadata.github.io/carry/examples/)
* [API Reference](http://metametadata.github.io/carry/api/)
* [FAQ](http://metametadata.github.io/carry/faq/)
* [Developer Guide](http://metametadata.github.io/carry/dev-guide/)
## License
Copyright © 2016 Yuri Govorushchenko.
Released under an MIT license.