Giter Club home page Giter Club logo

clj-foundation's Introduction

DEPRECATED clj-foundation

Why clj-foundation?

clj-foundation supplies namespaces making additional simple things easy and hard things possible in Clojure that are intended for use across all Clojure projects at Brad's Deals.

  • Enhances the core language in resonable, useful, and conservative ways.
  • Enables programming using a monadic style without requiring explicit monad types.
  • Describes, specifies, and illustrates best practices at Brad's Deals for working in Clojure.
  • The only dependencies are Clojure, Potemkin, and Schema in order to minimize adoption friction.

Other Clojure foundational libraries that compliment this one

High-quality domain-specific libraries complimenting this

Features

The folowing is a small sample of clj-foundation's features:

Math

  • A Mixed Number type
  • Time conversions to/from milliseconds
  • (str (millis/->dmhs elapsed-time)) => e.g.: "5 days 2 hours 3 minutes 2 seconds"
  • A Nothing type that behaves like the identity value for Maps, Seqs, and Strings and is distinct from nil.
  • Functions converting identity values of various types/operations to and from nil.

Ever had to declare a map containing the result of let variable bindings? Now you can do that in one step with let-map.

(let-map [meaning 42
          secrets (io/read-file "/etc/passwd")])
==>
{:meaning 42
 :secrets "nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false\nroot:*:0:0:System Administrator:/var/root:/bin/sh\n...."}

Data/error processing enhancements and timeout handling.

;; Replace a nil value with a default
(replace-nil (:first-name customer) "John")

;; Returns value if non-nil else throws IllegalArgumentException naming the nil value
(not-nil (:first-name customer) "First name")

;; Expect a condition specified by a predicate to become true within timeout-millis.
;; Throws IllegalStateException on failure with the specified message.
(expect-within
  (millis/<-seconds 5)
  (fn [] (= (meaning-of-life) 42))
  "Couldn't compute the meaning of life.")

;; Retry x times, with millis puase interval a specified function that is failure-prone
(retry 5 (millis/<-seconds 10) some-unreliable-io-operation)

A string interpolation language that is intentionally dumb about the syntax of its hosting language.

;; Given:
(def content "Say hello to ${NAME}")

;; Then:
(templates/subst<- content :NAME "Jack")
==>
"Say hello to Jack"

(subst<- content :ZIP "46989")
==>
ExceptionInfo Not found: '${NAME}'  clojure.core/ex-info

(interpolation-vars content)
==>
(:NAME)
  • Interpolation variables are resolved from the following places with the following precedence:
    • Java system variables (e.g.: java -DNAME='Jack' com.foo.bar.YourMainProgram)
    • Operating system environment variables
    • Any key/value variables specified in code.

Extensions to Clojure's file input functions

;; Return a Jar resource as a string
(resource-as-string "config.txt")

;; Return a Jar resource as a string, but allow the ALT_CONFIG_LOCATION Java system or O/S environment
;; variable to redirect reading to an external configuration file instead.
(resource-as-string "ALT_CONFIG_LOCATION" "config.txt")

;; Return a Jar resource as a string, interpolating any template variables inside the Jar resource
;; using the supplied interpolation variables and the override rules defined by the template language.
(read-template "config.properties" :NAME "Jack")

;; Return a Jar resource as a string, possibly overridden by the environment variable ALT_CONFIG_LOCATION
;; per the template engine's precedence rules.  Any template variables in the file will also be substuted
;; using the supplied key/value pairs and/or matching environment variables per the template engine's
;; precedence rules.
(read-template "ALT_CONFIG_LOCATION" "config.properties" :NAME "Jack")

And more...

  • Easier serialization / deserialization in various formats. Currently supports binary and EDN formats. Optionally can use the template language to support substitution variables inside EDN files.
  • A let-map form similar to "let" that returns its names and values as a Map--for those times the values of subsequent keys in a Map depend on the values of prior ones.
  • Simple named implementations of design patterns familiar to Java developers, particularaly Singleton.

Deployment/usage

Leiningen coordinates

:user {:repositories [["jitpack" "https://jitpack.io"]]

       :dependencies [[com.github.shopsmart/clj-foundation "version"]]}

where "version" currently is "Release".

Maven coordinates

<repositories>
  <repository>
    <id>jitpack.io</id>
    <name>Jitpack repo</name>
    <url>https://jitpack.io</url>
  </repository>
</repositories>
  • GroupId: com.github.shopsmart
  • ArtifactId: clj-foundation
  • Version: Release

Manual build/test

# Build
$ lein jar

# Test
$ lein with-profile test test

Definition of Done for 1.0 release

  • On APIs - While 1.0 will be a major release with some inevitable API breakage, we will strive:

    • To maintain API compatiblity with prior releases to the greatest extent possible
    • To remove duplicated functionality (which may contradict the API compatibility principle)
    • To maintain API compatibility with code copied from internal Brad's Deals projects to the greatest extent possible.
    • Clear naming convention for namespaces that are provisional (non-frozen, WIP) API.
  • Known tech debt that may influence APIs

    • Consider migrating db.clj's local configuration mechanism to config.clj (and then make an instance of the generic implementation inside db.clj)
  • Target Clojure 1.9

    • All functions will have type information supplied via Clojure 1.9 specs.
    • Functions currently using plumatic/schema to specify type constraints will be migrated to Specs
  • On testing

    • All functions will be unit tested using a style designed to illustrate behavior under failure modes as well as happy path scenarios.
    • We will collectively agree on a style of testing that seems to hit the sweet spot between overspecification and underspecification.
      • (Details are not set in stone but definitely up for negotiation)
    • When defects are detected, we will first reproduce the defect's root cause using a failing test case that will prevent the defect from reoccurring without the test notifying us.
    • Generative testing with Specs
    • Integrate kbitz (suggest Clojure idioms), some Clojure linting library; if it's easy to make these available to clients of clj-foundation, do so.
  • Debug library

    • dbg, ppdbg macros
    • trace?
  • Documentation

    • Machine generate as much as possible?
  • Make clj_infrastructure as a separate library

    • Move db.clj there?
    • Abstract db.clj API using monads at the foundation layer and implement for relational, nosql, etc. in infrastructure?

Provisional ideas for 1.0

  • Figure out how to isolate namespaces and their dependencies at the classpath level, including runtime reloading and evolution semantics after the fashion of OSGi at the REPL or in a running application.
  • Update and include clojure.osgi for clean deployment into OSGi frameworks?
  • Deploy to Clojars?

License

Copyright © 2015, 2016 by ShopSmart, LLC. Licensed under the Eclipse Public License v1.0.

Authors

  • David Orme
  • Levi Dixon

clj-foundation's People

Contributors

coconutpalm avatar mike-carey avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

coconutpalm

clj-foundation's Issues

db/def*, db/query, db/execute! should cache their PreparedStatement

Create an internal sql-fn API that accepts the ::SQL-FN, current connection, and PreparedStatement and returns a closure over atoms containing the connection and PreparedStatement. When this function is executed it should reuse the PreparedStatement from prior invocations if the connection is still the same.

Then update defquery, defstatement, query, and execute! to use this helper.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.