All Projects → escherize → Tracks

escherize / Tracks

Licence: epl-1.0
Programming with shapes

Programming Languages

clojure
4091 projects
clojurescript
191 projects

Projects that are alternatives of or similar to Tracks

Morphi
Shapes for SwiftUI ♡☾
Stars: ✭ 54 (-64.24%)
Mutual labels:  shape
Shapes
📐 Net standard geometry/shape manipulation library, can be used to merge / split shapes
Stars: ✭ 95 (-37.09%)
Mutual labels:  shape
Filestack React
Official React component for Filestack - API and content management system that makes it easy to add powerful file uploading and transformation capabilities to any web or mobile application.
Stars: ✭ 131 (-13.25%)
Mutual labels:  transformations
Phidl
Python GDS layout and CAD geometry creation
Stars: ✭ 56 (-62.91%)
Mutual labels:  shape
Ffimageloading
Image loading, caching & transforming library for Xamarin and Windows
Stars: ✭ 1,288 (+752.98%)
Mutual labels:  transformations
Serverless Sharp
Serverless image optimizer for S3, Lambda, and Cloudfront
Stars: ✭ 102 (-32.45%)
Mutual labels:  transformations
View shaper
A library to help create shaped views and layouts in Android
Stars: ✭ 42 (-72.19%)
Mutual labels:  shape
Marlin Renderer
Marlin is the FAST Java2D antialiasing rasterizer derived from OpenJDK Pisces (shape)
Stars: ✭ 146 (-3.31%)
Mutual labels:  shape
Sketch Make Long Shadow
A plugin for Sketch to create long shadows of a user defined length from a shape.
Stars: ✭ 92 (-39.07%)
Mutual labels:  shape
Easyreact
Are you confused by the functors, applicatives, and monads in RxSwift and ReactiveCocoa? It doesn't matter, the concepts are so complicated that not many developers actually use them in normal projects. Is there an easy-to-use way to use reactive programming? EasyReact is born for this reason.
Stars: ✭ 1,616 (+970.2%)
Mutual labels:  transformations
Stetl
Stetl, Streaming ETL, is a lightweight geospatial processing and ETL framework written in Python.
Stars: ✭ 64 (-57.62%)
Mutual labels:  transformations
Ng2 Konva
Angular & Canvas - JavaScript library for drawing complex canvas graphics using Angular.
Stars: ✭ 78 (-48.34%)
Mutual labels:  shape
Shapeshifter
🐺 Generate relational schemas, PropTypes, Flow aliases, and TypeScript interfaces from JSON or GraphQL schematic files.
Stars: ✭ 105 (-30.46%)
Mutual labels:  shape
Optimus
🤖 Id obfuscation based on Knuth's multiplicative hashing method for PHP.
Stars: ✭ 1,084 (+617.88%)
Mutual labels:  transformations
Pytransform3d
3D transformations for Python
Stars: ✭ 133 (-11.92%)
Mutual labels:  transformations
Metamorph
Morphing mod for Minecraft 1.12.2
Stars: ✭ 52 (-65.56%)
Mutual labels:  transformations
Sketch React
render sketch(v43+) file as react component
Stars: ✭ 98 (-35.1%)
Mutual labels:  shape
Bull
BULL - Bean Utils Light Library
Stars: ✭ 150 (-0.66%)
Mutual labels:  transformations
Androidutillib
🔥 旨在打造一款属于Android开发的强大工具库:内置各种开发必备工具类、Dialog封装、组件重写等
Stars: ✭ 143 (-5.3%)
Mutual labels:  shape
Hm
Idiomatic Ruby hash transformations
Stars: ✭ 121 (-19.87%)
Mutual labels:  transformations

tracks

Example based coding

Converging Tracks Build Status

We become what we behold. We shape our tools, and thereafter our tools shape us.

― Marshall McLuhan

Usage

Add the following line to your leiningen dependencies:

Clojars Project

Require tracks in your namespace header:

(:require [tracks.core :as t :refer [track]])

Rationale

This is a library to handle shapes. What's a shape?

shape n.
    - the correct or original form or contours of something.
    - an example of something that has a particular form.

shape v.
    - to give definite form, organization, or character to.

It's common to grapple with deeply nested arguments whose shapes are difficult to know without running the code. The data we love, tho pure and immutable can be nested and complex. This approach removes the cognitive burden needed to understand our datastructures.

Examples

deftrack example:

Instead of describing how to do a transformation, tracks allows the user to create those transformations declaratively. This makes writing code that takes one shape and transforms them to another dead simple.

Let's consider this data as our input. Typically this shape needs to be 'reverse-engineered' by reading and understanding code with get-in, destructuring, and other such operations.

(def buyer-information-map
  {:buyer-info
   {:is-guest true
    :primary-contact {:name {:first-name "Bob" :last-name "Ross"}
                      :phone {:complete-number "123123123"}
                      :email {:email-address "[email protected]"}}}})

Next, Let's create a function that takes this particular shape and returns another representing a notification for a customer.

(require '[tracks.core :as t :refer [deftrack]])

(deftrack notify-buyer
  {:buyer-info {:is-guest guest?                                    ;; 1
                :primary-contact {:name {:first-name firstname
                                         :last-name lastname}
                                  :phone {:complete-number phone}
                                  :email {:email-address email}}}}
  (when guest?                                                      ;; 2
    {:command :send-notification
     :address email
     :phone phone
     :text (str "Hi, " firstname " " lastname)}))
;; => #function[user/notify-buyer]

(notify-buyer buyer-information-map)
;; => {:command :send-notification
;;     :address "[email protected]"
;;     :phone "123123123"
;;     :text "Hi, Bob Ross"}
  1. deftrack expects data of this shape
  2. deftrack returns this value

What is going on here?

For every symbol in the binding form to deftrack (1 above), deftrack generates a program to seamlessly write the get / get-in / assoc-in / assoc / etc. sort of accessing code and allows you to focus on your data.

Destructuring

You may be thinking to yourself: Clojure already has destructuring! That's true, let's compare using deftrack against defn style destructuring:

(deftrack notify-buyer
  {:buyer-info {:is-guest guest?
                :primary-contact {:name {:first-name firstname
                                         :last-name lastname}
                                  :phone {:complete-number phone}
                                  :email {:email-address email}}}}
  (when guest?
    {:command :send-notification
     :address email
     :phone phone
     :text (str "Hi, " firstname " " lastname)}))

(defn notify-buyer-2 [{{guest? :is-guest,
                        {{firstname :first-name, lastname :last-name} :name,
                         {phone :complete-number} :phone,
                         {email :email-address} :email}
                        :primary-contact}
                       :buyer-info}]
  (when guest?
    {:command :send-notification
     :address email
     :phone phone
     :text (str "Hi, " firstname " " lastname)}))

I think you'd agree which of those is easier to read.

deftrack metadata

deftrack plays nice with arglists metadata, enabling your editor to explain what sort of shape a function created with deftrack takes.

(deftrack move-some-keys
  {:a a :b b :c c :d {:e e}}
  {:a b :b c :c e :d {:e a}})

(move-some-keys {:a 1 :b 2 :c 3 :d {:e 4}})
;; => {:a 2, :b 3, :c 4, :d {:e 1}}

(:arglists (meta #'move-some-keys))
;; => ([{a :a, b :b, c :c, {e :e} :d}])

Since we don't like to read deeply destructured arglists, deftracks also goes one step further, and includes what shape your function expects. (Todo: make this work with editors).

(:tracks/expects (meta #'move-some-keys))
;; => {:a a, :b b, :c c, :d {:e e}}

let example

For more flexible flowing of data, here's tracks/let, which allows for the same data-oriented style but with multiple arguments, etc.

(require '[tracks.core :as t :refer [deftrack]])

;; Please Notice: you usually don't get to see what some-data looks like! :)
(def some-data
  {:more-info {:price-for-this-order 10}
   :order-info {:amount-bought-from-my-company 3}})

;;in another part of your program:


;; you can use t/let:
(t/let [{:more-info {:price-for-this-order price}
         :order-info {:amount-bought-from-my-company quantity}} some-data]
  (* price quantity))
;;=> 30

;; or you can use deftrack:
(deftrack calculate-price-for-order
  {:more-info {:price-for-this-order price}
   :order-info {:amount-bought-from-my-company quantity}}
  (* price quantity))

(calculate-price-for-order some-data)
;;=> 30

Arbitrary nesting levels

Deep contemplation about deeply nested shapes is the old way.

(deftrack deeptx
  {0 zero
   1 one
   2 two
   3 three} ;; <- deeptx takes a map with this shape
  {:a zero
   :b {:c one
       :d {:e two
           :f {:g three}}}} ;; <- deeptx then returns one with this shape
  )

(deeptx {0 "first" 1 "second" 2 "third" 3 "fourth"})
;;=> {:a "first", :b {:c "second", :d {:e "third", :f {:g "fourth"}}}}

Complex leaf values

Let's simulate a game where there's an active player, and all other players wait in a queue to become the active one. Once a player has played their turn, they naturally go to the back of the queue.


;;; Setup the function that moves around players,
;;; no matter what datastructure the players are
;;; represented as:

(deftrack move-players
  {:active-player p1 :players [p2 p3 p4]}
  {:active-player p2 :players [p3 p4 p1]})

;;; Here's the datastructure that represents the state of the game.
;;; Notice that the players are more than scalar values!

(defonce game (atom {:active-player {:name "A"}
                     :players [{:name "B"}
                               {:name "C"}
                               {:name "D"}]}))

(swap! game move-players)
;;=>  {:active-player {:name "B"}
;;     :players [{:name "C"}
;;               {:name "D"}
;;               {:name "A"}]}

(swap! game move-players)
;;=>  {:active-player {:name "C"}
;;     :players [{:name "D"}
;;               {:name "A"}
;;               {:name "B"}]}


(swap! game move-players)
;;=>  {:active-player {:name "D"}
;;     :players [{:name "A"}
;;               {:name "B"}
;;               {:name "C"}]}

Multiple endpoints

Like a train track, sometimes one track can split into many. With track the values can be duplicated.

(deftrack one-to-many {:clone-me x} {:a x :b {:c [x x]}})

(one-to-many {:clone-me "?"})

;;=> {:a "?", :b {:c ["?" "?"]}}

Want more examples?

Check the test namespace!

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].