9 |
10 |
--------------------------------------------------------------------------------
/docs/defining-behaviour-with-functions/index.md:
--------------------------------------------------------------------------------
1 | # Defining behaviours with functions
2 |
3 | Clojure has functions, rather than methods for defining behaviour / "algorithms"
4 |
5 | Clojure design at its most basic comprises:
6 |
7 | - one or more data structures
8 | - functions that process those data-structures
9 |
10 | There is a common saying in Clojure: "Its better to have one data structure and many functions, than many data structures and many functions"
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Exclude all files from root directory
2 | /*
3 |
4 | # ------------------------
5 | # Common project files
6 | !CHANGELOG.md
7 | !README.md
8 | !LICENSE
9 |
10 | # ------------------------
11 | # Include MkDocs files
12 | !docs/
13 | !includes/
14 | !overrides/
15 | !mkdocs.yml
16 |
17 | # ------------------------
18 | # Project automation
19 | !Makefile
20 |
21 | # ------------------------
22 | # Version Control
23 | !.gitignore
24 | !.gitattributes
25 | !.github/
26 |
27 |
--------------------------------------------------------------------------------
/docs/libraries/clojure-core.md:
--------------------------------------------------------------------------------
1 | # Understanding Clojure Libraries: `clojure.core`
2 |
3 | > #### Warning::Very rough draft of an idea
4 | >
5 | > Experimenting with the value of grouping functions in clojure.core to help ensure you are exposed to most of the concepts in Clojure
6 |
7 | # Families of functions
8 |
9 | * List Comprehension (for, while, )
10 | * used to process multiple collections
11 |
12 | * Transformations (map, filter, apply, reduce )
13 | * transform the contents of a collection
14 |
--------------------------------------------------------------------------------
/docs/introduction/concepts/all-bytecode-in-the-end.md:
--------------------------------------------------------------------------------
1 | # Its all Bytecode in the end
2 |
3 | > The REPL is your compiler
4 |
5 | 
6 |
7 | As soon as you evaluate your code in the REPL it is also being compiled in the background into Java Bytecode. So there is no need for a separate build and run phase.
8 |
9 | Injecting code into the running environment provides the means for fast iterative development of code.
10 |
--------------------------------------------------------------------------------
/docs/testing/unit-testing/clojure-test-expectations.md:
--------------------------------------------------------------------------------
1 | # Clojure test Expectations
2 |
3 |
4 |
5 | `clojure.test.expectations` uses the same tooling as `clojure.test` and only depends on that library.
6 |
7 | ## Using a deps.edn alias
8 |
9 | [:fontawesome-solid-book-open: Practicalli Clojure CLI Config](/clojure/clojure-cli/practicalli-config/)
10 |
11 | ## Add dependency
12 |
13 | Edit the deps.edn file for the current project
14 |
--------------------------------------------------------------------------------
/docs/iterate-over-data/filter-remove.md:
--------------------------------------------------------------------------------
1 | # filter and remove
2 |
3 | Use filter and remove with predicate functions, those returning true or false, to create a sub-set of the data.
4 |
5 | filter creates a new collection that contains all the matching values from the predicate function (true).
6 |
7 | `remove` creates a new collection with contains all the values that didn't match the predicate function (false).
8 |
9 | > #### TODO::work in progress, sorry
10 |
11 | ```clojure
12 | (filter odd? [1 2 3 4 5 6 7 8 9])
13 | ```
14 |
--------------------------------------------------------------------------------
/docs/designing-data-structures/with-vectors-of-vectors.md:
--------------------------------------------------------------------------------
1 | # With Vectors of Vectors
2 |
3 | The most frequent use of you will see is in the `project.clj` file, where a vector of vectors is used to model the library dependencies for a project
4 |
5 | ```clojure
6 | [[org.clojure/clojure "1.8.0"]
7 | [org.clojure/core.match "0.3.0-alpha4"]]
8 |
9 | [[org.clojure/clojure "1.6.0"]
10 | [ring "1.4.0-beta2"]
11 | [compojure "1.3.4"]
12 | [hiccup "1.0.5"]]
13 | ```
14 |
15 | > **Fixme** Think of an exercise to create a vector of vectors as a data model
16 |
--------------------------------------------------------------------------------
/.github/config/markdown-link-check.json:
--------------------------------------------------------------------------------
1 | {
2 | "ignorePatterns": [
3 | {
4 | "pattern": "^http://localhost"
5 | },
6 | {
7 | "pattern": "^mailto:*"
8 | },
9 | {
10 | "pattern": "^#*"
11 | },
12 | {
13 | "pattern": "^https://127.0.0.0/"
14 | }
15 | ],
16 | "timeout": "20s",
17 | "retryOn429": true,
18 | "retryCount": 5,
19 | "fallbackRetryDelay": "30s",
20 | "aliveStatusCodes": [
21 | 200,
22 | 206
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/docs/puzzles/random-seat-assignment.md:
--------------------------------------------------------------------------------
1 | # Random Seat assignment
2 |
3 |
4 |
5 | Take a functional / data oriented approach to solving this problem
6 |
7 | ## Description
8 |
9 | You want to randomly assign seating to a number of people for a fixed number of seats. Each seat is represented by an integer number between 1 and 30.
10 |
11 | How do you randomly assign seats without choosing the same seat twice.
12 |
13 | ## Loop / recur approach
14 |
15 | Bad...
16 |
17 | ## recursive function
18 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/iterate-over-values.md:
--------------------------------------------------------------------------------
1 | # iterate Over Values
2 |
3 | This
4 |
5 | > #### Hint::Work in progress
6 |
7 | * loop recur
8 | * reducing functions
9 | * map apply reduce
10 | * partition group-by sort-by
11 |
12 | ## loop recur
13 |
14 | loop recur is a very detailed way of defining a way to iterate over values. map, reduce and apply are commonly used abstractions for iterating over values. They simplify the code (once you are comfortable with them)
15 |
16 | Functions that iterate over values usually treat a string as a sequence of characters.
17 |
--------------------------------------------------------------------------------
/docs/simple-projects/data-transformation/common-english-words.csv:
--------------------------------------------------------------------------------
1 | a,able,about,across,after,all,almost,also,am,among,an,and,any,are,as,at,be,because,been,but,by,can,cannot,could,dear,did,do,does,either,else,ever,every,for,from,get,got,had,has,have,he,her,hers,him,his,how,however,i,if,in,into,is,it,its,just,least,let,like,likely,may,me,might,most,must,my,neither,no,nor,not,of,off,often,on,only,or,other,our,own,rather,said,say,says,she,should,since,so,some,than,that,the,their,them,then,there,these,they,this,tis,to,too,twas,us,wants,was,we,were,what,when,where,which,while,who,whom,why,will,with,would,yet,you,your
2 |
--------------------------------------------------------------------------------
/docs/core.async/clacks-messages/index.md:
--------------------------------------------------------------------------------
1 | # Clacks Messenger with core.async
2 |
3 | > #### TODO::work in progress, sorry
4 | >
5 | > Pull requests are welcome
6 |
7 | In a previous exercise we built a simple encoder/decoder to send messages via the Clacks message service (as designed by Sir Terry Pratchett, RIP).
8 |
9 | Now we will use core.async to create a processing queue between each Clack towers, so we can then model, monitor and visualise a Clacks messenger system with multiple Clacks towers. For additional fun we will enable new Clacks towers to come on line and connect to the existing system.
10 |
--------------------------------------------------------------------------------
/.github/config/gitleaks.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 |
3 | [allowlist]
4 | description = "global allow lists"
5 | paths = [
6 | '''gitleaks.toml''',
7 | '''(.*?)(jpg|gif|doc|docx|zip|xls|pdf|bin|svg|socket)$''',
8 | '''(go.mod|go.sum)$''',
9 | '''gradle.lockfile''',
10 | '''node_modules''',
11 | '''package-lock.json''',
12 | '''pnpm-lock.yaml''',
13 | '''Database.refactorlog''',
14 | '''vendor''',
15 | ]
16 |
17 | [[rules]]
18 | description = "AWS Example API Key"
19 | id = "aws-example-api-key"
20 | regex = '''AKIAIOSFODNN7EXAMPLE'''
21 | keywords = [
22 | "awstoken",
23 | ]
24 |
--------------------------------------------------------------------------------
/docs/designing-data-structures/with-vectors.md:
--------------------------------------------------------------------------------
1 | # With Vectors
2 |
3 | Vectors as the simplest data structure in Clojure to work with. They are very similar to an array in other languages, although they have additional qualities in Clojure.
4 |
5 | Vectors
6 |
7 | * can be of any length
8 | * are indexed so have fast random access
9 | * can contain any types
10 | * are immutable
11 |
12 | !!! NOTE ""
13 | Define a data structure for a simple shopping list with any items you would typically want to buy.
14 |
15 |
16 | ??? EXAMPLE ""
17 | ```clojure
18 | (def shopping-list ["Cerial" "Baked Beans" "Cat food" "Quorn chicken pieces" ])
19 | ```
20 |
--------------------------------------------------------------------------------
/docs/reference/standard-library/regular-expressions/matching-sub-strings.md:
--------------------------------------------------------------------------------
1 | ## Matching sub-strings
2 |
3 | `re-find` returns the first match within the string, using return values similar to re-matches.
4 |
5 | `nil` is returned when the pattern does not find a match.
6 |
7 | ```clojure
8 | (re-find #"pump" "Halloween")
9 | ```
10 |
11 |
12 | A matching pattern without groups returns the matched string
13 |
14 | ```clojure
15 | (re-find #"e+" "Halloween")
16 | ```
17 |
18 |
19 | Match with groups returns a vector of results
20 |
21 | ```clojure
22 | (re-find #"s+(.*)(s+)" "success")
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/docs/clojure-cli/projects/templates/practicalli/application.md:
--------------------------------------------------------------------------------
1 | # Practicalli Application template
2 |
3 | Create a general Clojure application with REPL Reloaded workflow.
4 |
5 |
6 | ## Using the project
7 |
8 | Run the REPL
9 |
10 | ```shell
11 | make repl
12 | ```
13 |
14 | The REPL prompt is displayed using Rebel for a rich UI experience.
15 |
16 | Portal data inspector window is displayed and all evaluation results and mulog events are automatically sent to Portal.
17 |
18 | An nREPL server is running in the background for connecting Clojure aware editors.
19 |
20 |
21 | Run tests (stopping on first failing test)
22 |
23 | ```shell
24 | make test
25 | ```
26 |
--------------------------------------------------------------------------------
/docs/reference/standard-library/sequences.md:
--------------------------------------------------------------------------------
1 | # Standard Library: Sequences
2 |
3 | Functions to create and work with the Clojure sequences, including lists and sequence generators
4 |
5 | ## Sequence access
6 |
7 | | Function | Description |
8 | |-----------|-------------|
9 | | `first` | |
10 | | `second` | |
11 | | `rest` | |
12 | | `last` | |
13 | | `butlast` | |
14 | | `nth` | |
15 |
16 | ## Infinite sequence generators
17 |
18 | | Function | Description |
19 | |-----------|-------------|
20 | | `range` | |
21 | | `cycle` | |
22 | | `iterate` | |
23 |
--------------------------------------------------------------------------------
/docs/modifying-data-structures/index.md:
--------------------------------------------------------------------------------
1 | # Modifying data structures
2 |
3 | Wait, I thought you said that data structures were immutable! So how can we change them then?
4 |
5 | Yes, lists, vectors, maps and sets are all immutable. However, you can get a new data structure that has the changes you want. To make this approach efficient, the new data structure contains only the new data and links back to the existing data structure for shared data elements.
6 |
7 | We will see some of the most common functions that work with data structures in this section. In actuality, everything can be considered a function that works on a data structure though, as that is the language design of clojure.
8 |
--------------------------------------------------------------------------------
/docs/clojure-cli/projects/templates/practicalli/minimal.md:
--------------------------------------------------------------------------------
1 | # Practicalli Minimal Project Template
2 |
3 | A Clojure project with minimal dependencies and example code, useful for experimenting or building a new project from a minimal setup.
4 |
5 |
6 | ## Using the project
7 |
8 | Run the REPL
9 |
10 | ```shell
11 | make repl
12 | ```
13 |
14 | The REPL prompt is displayed using Rebel for a rich UI experience.
15 |
16 | Portal data inspector window is displayed and all evaluation results and mulog events are automatically sent to Portal.
17 |
18 | An nREPL server is running in the background for connecting Clojure aware editors.
19 |
20 |
21 | Run tests (stopping on first failing test)
22 |
23 | ```shell
24 | make test
25 | ```
26 |
--------------------------------------------------------------------------------
/docs/clojure-spec/generative-testing/example-projects/index.md:
--------------------------------------------------------------------------------
1 | # Example projects using Clojure Spec
2 |
3 | | Project | How the project uses Spec |
4 | |----------------------------------------|-----------------------------------------------------------------------------------|
5 | | [seancorfield/next-jdbc](next-jdbc.md) | Data specifications using predicates, function definition argument specifications |
6 |
7 | !!! HINT "More examples welcome"
8 | Other example projects that use interesting features of Spec are most welcome. [Raise an issue on the project issue tracker](https://github.com/practicalli/clojure-practicalli-content/issues) with details.
9 |
--------------------------------------------------------------------------------
/docs/development-environments/index.md:
--------------------------------------------------------------------------------
1 | # Development Environments
2 |
3 | 
4 |
5 | This workshop encourages [LightTable](http://lighttable.com/) & [Leiningen](http://leiningen.org/) as the development environment, as they are the easiest tools to set up.
6 |
7 | Leiningen is the build automation tool used to manage Clojure projects. It will create projects from templates and run our Clojure environment (REPL).
8 |
9 | LightTable is a Clojure aware editor that supports the dynamic workflow of Clojure development in a REPL. LightTable is also written in Clojure (and ClojureScript).
10 |
11 | The following pages will show you how to set up LightTable and Leiningen.
12 |
--------------------------------------------------------------------------------
/docs/simple-projects/data-transformation/index.md:
--------------------------------------------------------------------------------
1 | # Data Transformation
2 |
3 | In a sense all Clojure project are about data transformation, however, these projects will introduce you to many techniques used to transform larger and larger data sets.
4 |
5 | 
6 |
7 | | Project | Topics | Overview |
8 | |-----------------------------------------|-----------------------------|----------------------------------------------------------------------------|
9 | | [Most common word](most-common-word.md) | regex filter re-seq sort-by | Find the most common word in a give book that is not a common English word |
10 |
--------------------------------------------------------------------------------
/docs/clojure-cli/design-journal.md:
--------------------------------------------------------------------------------
1 | # Design Journal
2 |
3 | A design journal captures with code and comments the decisions taken for a project, invaluable to anyone trying to get up to speed with a project.
4 |
5 |
6 | ## Using a design-journal namespace
7 |
8 | A single namespace encourages the journal to flow as the design of the application flows. So onboarding onto a project is essentially reading and evaluating code from top to bottom.
9 |
10 |
11 | ## Using comment blocks
12 |
13 | It is useful to include examples of how you expect key parts of the system to be called and the kind of arguments they receive. Placing these examples in a (comment ,,,) expression ensures they are not accidentally evaluated whilst showing the most important function calls in a particular namespace.
14 |
--------------------------------------------------------------------------------
/docs/clojure-spec/functions/function-definition-specifications.md:
--------------------------------------------------------------------------------
1 | # Function definition specifications
2 |
3 | `clojure.spec.alpha/fdef` defines a specification for a function definition, providing specific specification for
4 |
5 | * arguments passed when calling a function
6 | * return value expected
7 | * relationships between arguments and return value
8 |
9 | ## Examples
10 |
11 | The `practicalli.database-access/new-account-holder` function takes a customer details specification and returns an `account-holder-id` specification.
12 |
13 | !!! EXAMPLE "practicalli.database-access/new-account-holder"
14 | ```
15 | (spec/fdef practicalli.database-access/new-account-holder
16 | :args (spec/cat :customer ::customer-details)
17 | :ret ::account-holder-id)
18 | ```
19 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/recursion-polymorphism.md:
--------------------------------------------------------------------------------
1 | # Recursion & Polymorphism
2 |
3 | > **Fixme** work in progress
4 |
5 | The following `sum` function will calculate the value of adding all the elements in a collection. You can alter the results by adding a starting value to the calculation as a second argument when calling `sum`
6 |
7 | ```clojure
8 | (defn sum
9 | ([vals] (sum vals 0))
10 | ([vals accumulating-total]
11 | (if (empty? vals)
12 | accumulating-total
13 | (sum (rest vals) (+ (first vals) accumulating-total)))))
14 |
15 | (sum [2 7 9 11 13])
16 | (sum [1])
17 | (sum [2 7 9 11 13] 9)
18 | ```
19 |
20 | Rather than duplicate the calculation, the behaviour of calling `sum` with just a collection simply calls `sum` again, this time passing a starting value of zero.
21 |
--------------------------------------------------------------------------------
/docs/clojure-spec/testing/checking arguments.md:
--------------------------------------------------------------------------------
1 | # Checking arguments in function calls with specifications
2 |
3 | ## Instrument functions during development
4 |
5 | Instrumenting a function enables the checking of arguments in a function call against the specification defined in an `fdef` definition of the same name.
6 |
7 | ```clojure
8 | (clojure.spec.test.alpha/instrument `function-name)
9 | ```
10 |
11 | Instrumenting a function swaps the function definition var with a wrapped version of the function definition which includes tests the `:args` spec from the `fdef` expression.
12 |
13 | `unstrument` returns the function definition to the original form and tests for that function are no longer run.
14 |
15 | ## Unit (Specification) testing
16 |
17 | You can generate data for interactive testing with gen/sample.
18 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/literal-values.md:
--------------------------------------------------------------------------------
1 | # Literal values
2 |
3 | Sets can be used as predicate functions returning true if the value is within the set
4 |
5 | Checking valid playing cards
6 |
7 | Define a namespace for the page and require Clojure Spec
8 |
9 | ```clojure
10 | (ns practicalli.clojure
11 | (:require [clojure.spec.alpha :as spec]))
12 | ```
13 |
14 | ```clojure
15 | (spec/valid? #{:club :diamond :heart :spade} :club)
16 | ```
17 |
18 | ```clojure
19 | (spec/valid? #{:club :diamond :heart :spade} 42)
20 | ```
21 |
22 | Answer to the ultimate question?
23 |
24 | ```clojure
25 | (spec/valid? #{42} 42)
26 | ```
27 |
28 | Using sets for literal values is similar to using the `clojure.core/contains?` function with a set collection type.
29 |
30 | ```clojure
31 | (contains? #{:clubs :diamonds :hearts :spades} :hearts )
32 | ```
33 |
--------------------------------------------------------------------------------
/docs/reference/tagged-literals/index.md:
--------------------------------------------------------------------------------
1 | # Tagged Literals
2 |
3 | Frequently used value types are afforded a "tagged literal" syntax. It is similar to a constructor, but this special syntax makes it de/serializable and easier to read at the REPL.
4 |
5 | Tagged literals start with a # followed by a symbol and a literal:
6 |
7 | `#js [...]`- [JavaScript array literal](https://github.com/cljs/api/blob/master/docfiles/syntax/js-literal.md)
8 |
9 | `#js {...}` - [JavaScript object literal](https://github.com/cljs/api/blob/master/docfiles/syntax/js-literal.md)
10 |
11 | `#inst "..."` - [JavaScript date literal](https://github.com/cljs/api/blob/master/docfiles/syntax/inst-literal.md)
12 |
13 | `#uuid "..."` - [UUID literal](uuid.md)
14 |
15 | `#queue [...]` - [queue literal](https://github.com/cljs/api/blob/master/docfiles/syntax/queue-literal.md)
16 |
--------------------------------------------------------------------------------
/docs/data-structures/shared-memory.md:
--------------------------------------------------------------------------------
1 | # Shared memory with Persistent data structures
2 |
3 | The Clojure data structures are immutable, so they initially seem similar to constants rather than variables. Once a collection is created, it cannot be changed. Any functions that run on a collection do not change the collection, instead they return a new collection with the respective changes.
4 |
5 | Creating a new collection each time may seem inefficient, however, the persistent collections use a sharing model. When a new collection is created, it links to all the relevant elements of the original collection and adds any new elements.
6 |
7 | 
8 |
9 | > **Hint** Read the InfoQ article on [An In-Depth Look at Clojure Collections](https://www.infoq.com/articles/in-depth-look-clojure-collections/).
10 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/immutable-values.md:
--------------------------------------------------------------------------------
1 | # Immutable values
2 |
3 | > **Fixme** work in progress
4 |
5 | Values in Clojure include numbers, characters and strings. When you use functions on these values they do not change, instead a new value is returned.
6 |
7 | Lets look at a simple example with a number:
8 |
9 | ```clojure
10 | (def two-little-ducks 22)
11 |
12 | (inc two-little-ducks)
13 | ;; => 23
14 |
15 | two-little-ducks
16 | ;; => 22
17 | ```
18 |
19 | Another example with a string:
20 |
21 | ```clojure
22 | (def message "Strings are immutable")
23 |
24 | (str message "," " " "you cant change them")
25 | ;; => "Strings are immutable, you cant change them"
26 |
27 | message
28 | ;; => "Strings are immutable"
29 | ```
30 |
31 | > **Fixme** Add an exercise
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/clojure-spec/projects/bank-account/unit-tests-with-spec.md:
--------------------------------------------------------------------------------
1 | # Unit tests with specs
2 |
3 | Now that customer data and account-holder data has a specification, we can use the `clojure.spec.alpha/valid?` in the unity test code, as that function returns true or false.
4 |
5 | In this example the result of a call to `register-account-holder` is checked to see if it is valid against the `::account-holder` specification. This simplifies the code needed in unit test assertions, as Clojure spec is doing the work.
6 |
7 | ```clojure
8 | (deftest register-account-holder-test
9 | (testing "Basic registration - happy path"
10 | (is (= (set (keys (SUT/register-account-holder customer-mock)))
11 | (set (keys account-holder))))
12 |
13 | (is (spec/valid? :practicalli.bank-account-spec/account-holder
14 | (SUT/register-account-holder customer-mock) ) )
15 | ))
16 | ```
17 |
--------------------------------------------------------------------------------
/docs/games/index.md:
--------------------------------------------------------------------------------
1 | # Writing Games with Clojure
2 |
3 | > #### TODO::work in progress, sorry
4 | >
5 | > Pull requests are welcome
6 |
7 | Games are driven by events and require state to be managed, so are a good way to explore how to manage state with immutable values.
8 |
9 | For games in Clojure the events are simply function calls and we prefer to pass the state around rather than have a central mutable container for our state.
10 |
11 | This section will contain several games that have been built using a functional approach with immutable data structures.
12 |
13 | * TicTacToe on the command line
14 |
15 | > #### Hint::Games in ClojureScript
16 | >
17 | > There is a section on games in the Practicalli ClojureScript book, including [a TicTacToe game using Reagent](https://practicalli.github.io/clojurescript/reagent-projects/tic-tac-toe/index.html) (react.js style library) and Scalable Vector Graphics (SVG).
18 |
--------------------------------------------------------------------------------
/docs/introduction/five-steps-to-clojure.md:
--------------------------------------------------------------------------------
1 | # 5 Steps to Clojure
2 |
3 | ## Set up your environment
4 |
5 | Install Clojure and a build tool
6 |
7 | Setup a Clojure aware editor
8 |
9 | * Emacs & CIDER - Spacemacs, Doom, Prelude
10 | * Neovim & Conjure
11 | * VSCode & Clover or Calva
12 | * Sublime Text & SublimedClojure
13 |
14 | ## Learn the syntax
15 |
16 | ## Practice the core functions
17 |
18 | * 4clojure.org
19 | * Exercism.io
20 |
21 | ### def / defn / let
22 |
23 | ### map / reduce / apply
24 |
25 | ### for / while / loop / recur
26 |
27 | ## Adopt functional programming practices
28 |
29 | ## Learn the commonly used libraries
30 |
31 | ### Server-side websites
32 |
33 | #### Ring / Compojure / Reitit / Hiccup | Selma
34 |
35 | ### React client-side single page apps
36 |
37 | #### React.js / Om-next / Reagent / Re-frame
38 |
39 | #### core.async
40 |
41 | ### Full Stack apps
42 |
43 | #### Kit Framework
44 |
--------------------------------------------------------------------------------
/docs/reference/standard-library/regular-expressions/string-replace-with-regex.md:
--------------------------------------------------------------------------------
1 | ## String replace with regex pattern
2 |
3 | `clojure.string/replace` takes a string, a pattern and a substring that will replace matching patterns.
4 |
5 | ```clojure
6 | (clojure.string/replace "mississippi" #"i.." "obb")
7 | ```
8 |
9 |
10 | Groups can be referred to in the substring replacement
11 |
12 | ```clojure
13 | (clojure.string/replace "mississippi" #"(i)" "$1$1")
14 | ```
15 |
16 |
17 | Replace with the value of a function applied to the match:
18 |
19 | ```clojure
20 | (clojure.string/replace "mississippi" #"(.)i(.)"
21 | (fn [[_ b a]]
22 | (str (clojure.string/upper-case b)
23 | "--"
24 | (clojure.string/upper-case a))))
25 | "M--SS--SS--Ppi"
26 | ```
27 |
28 | `clojure.string/replace-first` is a variation where just the first occurrence is replaced.
29 |
--------------------------------------------------------------------------------
/docs/reference/standard-library/regular-expressions/string-split-with-regex.md:
--------------------------------------------------------------------------------
1 | ## String splitting using a regex pattern
2 |
3 | `clojure.string/split` takes a string to be split and a pattern to split the string with.
4 |
5 | ```clojure
6 | (clojure.string/split "This is a string that I am splitting." #"\s+")
7 | ["This" "is" "a" "string" "that" "I" "am" "splitting."]
8 | ```
9 |
10 | ## Most common words example
11 |
12 | Extract a list of the most commonly used English words, returned as a string of words that are separated by a comma.
13 |
14 | The `#","` regex pattern splits the string of words to form a collection of individual words, each word being its own string.
15 |
16 | ```clojure
17 | (def common-english-words
18 | (set
19 | (clojure.string/split
20 | (slurp
21 | "http://www.textfixer.com/resources/common-english-words.txt")
22 | #",")))
23 | ```
24 |
25 | TODO: add link to complete example.
26 |
--------------------------------------------------------------------------------
/docs/testing/test-runners/aero.md:
--------------------------------------------------------------------------------
1 | # Aero
2 |
3 | [juxt/aero](https://github.com/juxt/aero) is used to read the kaocha configuration, so reader literals such as #env, #merge, #ref, and #include can be used.
4 |
5 | Set up [profiles for different stages of the development workflow](https://juxt.pro/blog/aero.html), dev, test, prod, etc. Each profile has a different configuration making it very easy to switch
6 |
7 | ```clojure
8 | {:port 8000
9 | :database #profile {:prod "datomic:dev://localhost:4334/my-prod-db2"
10 | :test "datomic:dev://localhost:4334/my-test-db"
11 | :default "datomic:dev://localhost:4334/my-db"}
12 | :known-users [{:name "Alice"} {:name "Betty"}]}
13 | ```
14 |
15 | Then in application startup function or a component lifecycle library (mount, component, integrant) read in a specific profile
16 |
17 | ```clojure
18 | (aero.core/read-config "config.edn" {:profile :prod})
19 | ```
20 |
--------------------------------------------------------------------------------
/docs/simple-projects/tdd-kata/index.md:
--------------------------------------------------------------------------------
1 | # Kata challenges
2 |
3 | A kata is a small challenge that you attempt to solve in different ways, so experiment with your solutions to these challenges.
4 |
5 | Kata are often coupled with Test Driven Development approach.
6 |
7 | | Project | Topics | Overview |
8 | |---------------------------------------------------|--------|--------------------------------------------------------|
9 | | [Recent song-list](recent-song-list.md) | TDD | Keep a list of recent songs played, without duplicates |
10 | | [Salary Slip Generator](salary-slip-generator.md) | TDD | Generate play slips for an employee |
11 |
12 | [Code Kata Website](http://codekata.com/){target=_blank .md-button}
13 |
14 | 
15 |
--------------------------------------------------------------------------------
/docs/clojure-spec/functions/higher-order-functions.md:
--------------------------------------------------------------------------------
1 | # Higher order functions
2 |
3 | Higher order functions are common in Clojure and spec provides fspec to support spec’ing them.
4 |
5 | ```clojure
6 | (defn value-added-tax
7 | [tax-rate]
8 | #(+ (* tax-rate %) %))
9 | ```
10 |
11 | The value-added-tax function returns an anonymous function that adds the value of tax to the given value.
12 |
13 | Define a namespace for the page and require Clojure Spec
14 |
15 | ```clojure
16 | (ns practicalli.clojure
17 | (:require [clojure.spec.alpha :as spec]))
18 | ```
19 |
20 | Declare a function spec for value-added-tax using `clojure.spec.alpha/fspec` for the return value:
21 |
22 | ```clojure
23 | (s/fdef value-added-tax
24 | :args (spec/cat :tax-rate number?)
25 | :ret (spec/fspec :args (s/cat :value number?)
26 | :ret number?))
27 | ```
28 |
29 | The `:ret` specification uses `fspec` to declare that the returning function takes and returns a number.
30 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/immutability.md:
--------------------------------------------------------------------------------
1 | # Immutability
2 |
3 | There is a strong emphasis on immutability in Clojure. Rather than create variables that change, Clojure uses values that do not change.
4 |
5 | Values in Clojure include numbers, characters, strings.
6 |
7 | When functions act on values, a new value is created and returned, rather than modifying the existing value.
8 |
9 | > **TODO** include a diagram to visualise this...
10 |
11 | # Immutabile data structures
12 |
13 | List, Map, Vector and Set are all immutable data structures in Clojure.
14 |
15 | So when you use these data structures with a function, a new data structure is returned.
16 |
17 | > **Hint** When a new data structure is created from an existing data structure, then under the covers the two data structures actually share memory use for any elements that are common. This keeps copies very cheap to create in terms of memory used.
18 |
19 | > See the section on [data structures](/data-structures/) for more details.
20 |
--------------------------------------------------------------------------------
/docs/iterate-over-data/map-fn.md:
--------------------------------------------------------------------------------
1 | # map with fn - anonymous function
2 |
3 | > #### TODO::work in progress, sorry
4 |
5 | ```clojure
6 | (map (fn [arg] (+ arg 5)) [1 2 3 4 5])
7 | ```
8 |
9 | There is a syntactic short-cut for the anonymous function that does not require a name for the arguments
10 |
11 | ```#(+ %1 5)```
12 |
13 | Adding this into our previous expression we can see that its still quite readable and helps keep the code clean.
14 |
15 | ```clojure
16 | (map #(+ arg 5) [1 2 3 4 5])
17 | ```
18 |
19 | > #### Hint::Anonymous function name
20 | >
21 | > Anonymous functions do not have an externally referable name, so must be used in-line with an expression.
22 | >
23 | > The `fn` function can be defined with a name, however, this is only available in the scope of that function definition, the name cannot be used to refer to that function outside of its definition.
24 | >
25 | > Including a name within a `fn` definition enables the function to call itself, therefore creating an anonymous recursive function.
26 |
--------------------------------------------------------------------------------
/docs/using-data-structures/lazy-sequences.md:
--------------------------------------------------------------------------------
1 | # Lazy Sequences
2 |
3 | Sequences are an interface for logical lists, which can be lazy. "Lazy" means that a sequence can define an infinite series, like so:
4 |
5 | ```
6 | (range 4)
7 | ```
8 |
9 | If you evaluate `(range)` just by itself it will return an infinite number of integers, well at least until your computers memory space fills up.
10 |
11 | So we dont blow up our memory and just get the values we want we can use `range` in conjunction with other functions that define how many numbers we actually want.
12 |
13 | For example, if we just wanted the first four numbers from the infinite sequence of `range` we could specify that with the `take` function
14 |
15 | ```
16 | (take 4 (range)) ; (0 1 2 3)
17 | ```
18 |
19 | Here the range function is being lazy, because it will only generate the first 4 numbers in its sequence.
20 |
21 | Clojure (and Lisps in general) often evaluate at the last possible moment, usually when they have been given more specific content.
22 |
--------------------------------------------------------------------------------
/.github/config/lychee.toml:
--------------------------------------------------------------------------------
1 |
2 | # ----------------------------------------
3 | # Base URL or website root directory to check relative URLs.
4 | base = "https://practical.li/clojure/"
5 |
6 | # Only test links with the given schemes (e.g. https).
7 | # Omit to check links with any other scheme.
8 | # At the moment, we support http, https, file, and mailto.
9 | scheme = ["https"]
10 |
11 | # ----------------------------------------
12 | # Exclusions
13 |
14 | # Exclude URLs and mail addresses from checking (supports regex).
15 | exclude = ['^https://127.0.0.0', '^https://www\.linkedin\.com', '^https://web\.archive\.org/web/']
16 |
17 | # Exclude these filesystem paths from getting checked.
18 | exclude_path = ["mkdocs.yml", "overrides", "includes", ".github", ".git"]
19 |
20 | # Exclude all private IPs from checking.
21 | # Equivalent to setting `exclude_private`, `exclude_link_local`, and
22 | # `exclude_loopback` to true.
23 | exclude_all_private = true
24 |
25 | # Check mail addresses
26 | include_mail = false
27 | # ----------------------------------------
28 |
--------------------------------------------------------------------------------
/docs/simple-projects/generate-web-page.md:
--------------------------------------------------------------------------------
1 | # Generate Web Page
2 |
3 | Generate a web page from Clojure code, using Hiccup
4 |
5 | Generate a full HTML webpage with content.
6 |
7 | Add a CSS library (bulma.io, bootstrap) to improve generation
8 |
9 |
10 |
11 | ## Summary
12 |
13 | Generating a web page in Clojure shows how easy it is to structure data and transform that data into other structures.
14 |
15 | Although this kind of project is easy enough to just do in a REPL directly, using a Clojure aware editor with a Clojure project makes changes to the code far simpler, without loosing any of the immediate feedback of the REPL.
16 |
17 | Most Clojure developers use the REPL by evaluating code in the editor showing the source code from the project.
18 |
19 | [:fontawesome-solid-book-open: Practicalli Web Services book](https://practical.li/clojure-web-services/) shows how to build websites, create self-documented API's, manage Web Application servers and use databases to persist data.
20 |
--------------------------------------------------------------------------------
/docs/reference/standard-library/regular-expressions/matching-with-groups.md:
--------------------------------------------------------------------------------
1 | # Matching with regex groups
2 |
3 | `rematches` takes a pattern and compares it with a string.
4 |
5 | If the pattern does not match the string then `nil` is returned to show the function returned a false value.
6 |
7 | ```clojure
8 | (re-matches #"pumpkin" "Halloween pumpkin")
9 | ```
10 |
11 | If there is an exact match and there are no groups (parens) in the regex, then the matched string is returned.
12 |
13 | ```clojure
14 | (re-matches #"pumpkin" "pumpkin")
15 | ```
16 |
17 | If the pattern matches but there are groups, a vector of matching strings is returned. The first element in the vector is the entire match. The remaining elements are the group matches.
18 |
19 | ```clojure
20 | (re-matches #"Halloween(.*)" "Halloween pumpkin")
21 | ```
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/designing-data-structures/index.md:
--------------------------------------------------------------------------------
1 | # Designing Data Structures
2 |
3 | Some common design guides for data structures in Clojure
4 |
5 | # The Basics design approach
6 |
7 | Most data structures in Clojure seem to be created from either vectors or maps or a combination of both. Sets are used where uniqueness of values is important and lists are often used for their lazy properties.
8 |
9 | **Vectors** are the most flexible data structure in Clojure and support none-sequential access as they are indexed.
10 |
11 | **Maps** are really useful for defining semantic meaning to your data structures, helping you create data structures that express the context of the model they represent. Maps give you unordered, arbitrary index arrangement. Access is iteration of key/value pairs or getting a value for a given key.
12 |
13 | **Lists** give you sequential, one-at-a-time arrangement. They allow for efficient iteration, lazy generation, and stack discipline.
14 |
15 | **Sets** give you unordered, unique constraint arrangement. Access is iteration of elements or checking containment.
16 |
--------------------------------------------------------------------------------
/overrides/404.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | {% extends "main.html" %}
7 |
8 |
9 | {% block content %}
10 |
This is not the page you are looking for
11 |
12 |
13 | Sorry we have arrived at a page that does not exist...
14 |
15 |
16 |
17 | Practicalli website are published using Material for MkDocs
18 |
19 |
20 |
21 | Use the Search bar at the top of the page or left navigation to find the relevant content.
22 |
37 |
38 |
39 | {% endblock %}
40 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/functors.md:
--------------------------------------------------------------------------------
1 | # Functors
2 |
3 | > **Fixme** work in progress
4 |
5 | Put simply, a function that takes a value and a function as its arguments, eg `map`. The argument pass as a value is most commonly a collection type (vector, map, string, list).
6 |
7 | > From Wikipedia
8 |
9 | > In mathematics, a functor is a type of mapping between categories which is applied in category theory. Functors can be thought of as homomorphisms between categories. In the category of small categories, functors can be thought of more generally as morphisms.
10 |
11 | A functor applies the given function to each element in the the collection by unpacking and each element from the collection and passing it to the function as an argument. The result from each application of the function from the element of the collection is put into a new collection. This new collection is returned once all elements of the original collection have been processed.
12 |
13 | The function, eg. + is applied in turn to each value and returns a structured value as a result,
14 | eg. a list or vector
15 |
16 | ```
17 | (map inc [1 2 3 4 5])
18 |
19 | (inc 1 )
20 | ```
21 |
--------------------------------------------------------------------------------
/docs/alternative-tools/clojure-cli/evaluate-an-expression.md:
--------------------------------------------------------------------------------
1 | # Evaluating an expression with Clojure CLI tools
2 |
3 | An expression is a piece of Clojure code that can be evaluated and return a result
4 |
5 | This expression calls the `+` function with the arguments `1 2 3 4 5`. As this code works, we get a result.
6 |
7 | ```clojure
8 | (+ 1 2 3 4 5)
9 | ```
10 |
11 |
12 | Using the `-e` option an expression can be passed to the Clojure CLI tools and a value returned
13 |
14 |
15 | ```shell
16 | clojure -e (+ 1 2 3 4 5)
17 | ```
18 |
19 |
20 | ## Expressions returning `nil`
21 |
22 | If the expressing used returns a value of `nil`, a legal value in Clojure, then no result is printed out.
23 |
24 |
25 | ## When to use this?
26 |
27 | `clojure -e` is a quick way to see what an expression does without having to set anything up (although starting a REPL is very little extra effort).
28 |
29 | Using the `-e` option is useful for running simple scripts written in Clojure, especially on servers and remote environments.
30 |
31 | The lack of return value for nil is very useful when using Clojure CLI tools to evaluate Clojure code within another script.
32 |
--------------------------------------------------------------------------------
/docs/reference/clojure-syntax/quick-look-at-types.md:
--------------------------------------------------------------------------------
1 | # A quick look at types
2 |
3 | As we mentioned before, underneath Clojure lurks Java byte code so there are going to be types in Clojure. However, Clojure being a dynamic language, most of the time you can just let Clojure manage the types for you.
4 |
5 | > **Hint** When you run Clojure on a different host platform, eg. .Net or Javascript (via Clojurescript), Clojure will use the types of that host platform.
6 |
7 | Should you want to know the type of something you are working on, you can use two functions, `type` and `class`.
8 |
9 | > **Note** Discover the class or type of some common Clojure code
10 |
11 | ```clojure
12 | (class 1)
13 | (class 1.1)
14 | (class "")
15 | (class true)
16 | (class false)
17 | (class nil)
18 |
19 | (class ())
20 | (class (list 1 2 3 4))
21 | (class (str 2 3 4 5))
22 | (class (+ 22/7))
23 |
24 | (type [1 2 3])
25 | (type {:a 1 :b 2})
26 | (type (take 3 (range 10)))
27 | ```
28 |
29 | 
30 |
31 | > **Hint** If you cant live without static type checking, look at [core.typed](http://typedclojure.org/), a type system for Clojure all in one library
32 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/immutable-local-bindings.md:
--------------------------------------------------------------------------------
1 | # Immutable Local Bindings
2 |
3 | Names can be bound to values & and data structures with either the `def` or `let` function. The `def` binding is global to the namespace, however the `let` function is local to its use.
4 |
5 | > **Hint** The `let` function is typically used to define names within a function definition, or in snippets of code created during repl driven development.
6 |
7 | ```clojure
8 |
9 | (let [five 5]
10 | (str "Within the let expression the value is " five))
11 | ;; => Within the let expression the value is 5
12 |
13 | ;; evaluating the name five outside the let expression returns an error
14 | five
15 | ;; => Unable to resolve symbol: five in this context
16 | ```
17 |
18 | > **Note** Create a local binding called number that represents the value 5 using the `let` function. Increment the number, then print out the value of number.
19 |
20 |
21 | ```clojure
22 | (let [number 5]
23 | (inc number)
24 | (str "The number is still " number))
25 | ```
26 |
27 | So the value that any local binding points to is immutable too.
28 |
29 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/tail-recursion.md:
--------------------------------------------------------------------------------
1 | # Tail recursion
2 |
3 | > **Fixme** work in progress
4 |
5 | If we generate a very large collection we run the risk of blowing our heap space. For example we could use range to generate a very large collection, say a vector containing 10 billion values
6 |
7 | Don't try this example below
8 |
9 | ```clojure
10 | (vec (range 0 9999999999))
11 | ;; this will crash after a short while as it will use up all your heap space
12 | ```
13 |
14 | Using tail call optimisation (tail recursion) allows us to reuse a memory location when we call a function recursively. This tail recursion is not part of the underlying Java Virtual Machine (JVM), so instead Clojure has a specific function called `recur`
15 |
16 | The `recur` function allows the processing of a very large data set without blowing the heap space because the memory space will be reused.
17 |
18 | The `recur` function must be the last expression in order to work.
19 |
20 | ```clojure
21 | (defn sum
22 | ([vals] (sum vals 0))
23 | ([vals accumulating-total]
24 | (if (empty? vals)
25 | accumulating-total
26 | (recur (rest vals) (+ (first vals) accumulating-total)))))
27 |
28 | (sum (vec (range 0 9999999)))
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/core.async/bike-assembly-line/index.md:
--------------------------------------------------------------------------------
1 | # core.async scenario: Bike assembly line
2 |
3 | > #### TODO::work in progress, sorry
4 | >
5 | > Pull requests are welcome
6 |
7 | In this example we are going to use a bicycle assembly line as the process we want to make concurrent. The tasks involved in making our bicycle are:
8 |
9 | * Making the frame
10 | * Painting the wheels
11 | * Making the rims
12 | * Making the wheels (adding hub and spokes to wheels - different hub for front and rear wheels)
13 | * Making the handlebars
14 | * Fitting tyres to the rims (solid rims, so no tubes)
15 | * Attaching the handlebars to the frame
16 | * Attaching wheels to the frame
17 | * Attaching crank to frame
18 | * Attaching peddles to the crank
19 | * Connecting control system wires (gears, breaks)
20 |
21 | ## Current build process
22 |
23 | At the moment, each person creates one bicycle all by themselves. This means they need all sorts of different tools and are switching tasks all the way through assembling the bike.
24 |
25 | We want to move to a more parallel approach, so as we automate this process we will evaluate what actions can be done in parallel and which must be done sequentially (i.e. painting the frame must come after making the frame).
26 |
--------------------------------------------------------------------------------
/docs/data-structures/set.md:
--------------------------------------------------------------------------------
1 | # Set
2 |
3 | A Clojure set is a persistent data structure that holds a unique set of elements. Again the elements can be of any type, however each element must be unique for a valid set.
4 |
5 | > **Note** Explore creating sets from existing collections. Notice what happens if you have duplicate values in the collection. Define sets directly using the `#{}` notation and see what happens if there are duplicate values.
6 |
7 | ```clojure
8 | (set `(1 2 3 4))
9 | (set `(1 2 1 2 3 4))
10 |
11 | #{1 2 3 4}
12 | #{:a :b :c :d}
13 | ;; duplicate key error
14 | #{1 2 3 4 1}
15 | ```
16 |
17 | ## Unique but not ordered
18 |
19 | A set is not ordered by the values it contains. If you need a sorted set then you can use the `sorted-set` function when creating a new set. Or you can run
20 |
21 | ```clojure
22 | (sorted-set 1 4 0 2 9 3 5 3 0 2 7 6 5 5 3 8)
23 |
24 | (sort [9 8 7 6 5])
25 | (sort-by )
26 | ```
27 |
28 | # Looking up values in a set
29 |
30 | ```clojure
31 | (#{:a :b :c} :c)
32 | (#{:a :b :c} :z)
33 | ```
34 |
35 | Sets can also use the `contains?` function to see if a value exists in a set
36 |
37 | ```clojure
38 | (contains?
39 | #{"Palpatine" "Darth Vader" "Boba Fett" "Darth Tyranus"}
40 | "Darth Vader")
41 | ```
42 |
--------------------------------------------------------------------------------
/docs/reference/reader-macros.md:
--------------------------------------------------------------------------------
1 | # Reader Macros
2 |
3 | > #### Todo::Re-write
4 |
5 | This is a collection of reader macros (think syntactic sugar) that are valid in Clojure. These macros are useful for commenting out expressions, defining sets, ...
6 |
7 | Many reader macros start with the character **#**, which is in fact the _Dispatch macro_ that tells the Clojure reader (the thing that takes a file of Clojure text and parses it for consumption in the compiler) to go and look at another read table for the definition of the next character - in essence this allows extending default reader behaviour.
8 |
9 | * **#_** - Discard macro - ignore the next expression. Often used to comment out code, especially when nested inside other expressions
10 |
11 | * **#'** - Var macro - returns the reference to the var. Used to pass the definition of something rather than the result of evaluating it.
12 |
13 | There is a nice list of reader macros in the article: [The weird and wonderful characters of Clojure](https://yobriefca.se/blog/2014/05/19/the-weird-and-wonderful-characters-of-clojure/) by [@kouphax](http://twitter.com/kouphax).
14 |
15 | > **Hint** Reader macros are part of the Clojure language specification, so are different to macros, which can be defined by anyone.
16 |
--------------------------------------------------------------------------------
/docs/clojure-spec/generative-testing/predicate-generators.md:
--------------------------------------------------------------------------------
1 | # Generators for predicate specifications
2 |
3 | Specifications are used to generate a wide range of random data. A generator for the specification is obtained and then data is generated.
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 | ## Predicate generators
17 |
18 | ```clojure
19 | (spec-gen/generate (spec/gen int?))
20 | ```
21 |
22 | ```clojure
23 | (spec-gen/generate (spec/gen nil?))
24 | ```
25 |
26 | ```clojure
27 | (spec-gen/sample (spec/gen string?))
28 | ```
29 |
30 | ```clojure
31 | (spec-gen/generate (spec/gen #{:club :diamond :heart :spade}))
32 | ```
33 |
34 | ```clojure
35 | (spec-gen/sample (spec/gen #{:club :diamond :heart :spade}))
36 | ```
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/first-class-functions.md:
--------------------------------------------------------------------------------
1 | # First Class functions
2 |
3 | Idempotent - given the same input you get the same output
4 |
5 | > ####Note::
6 | > Write an expression to add up the numbers from 1 to 10 and return the overall total.
7 |
8 | ```clojure
9 | (+ 1 2 3 4 5 6 7 8 9 10)
10 | ```
11 |
12 | > ####Note::
13 | > Create an expression to do the same calculation, but without having to write all the numbers. Hint: consider the functions called range and reduce.
14 |
15 | The `range` function generates a sequence of numbers and when given arguments it does so from a specific range. The second number is exclusive, so for 1 to 10 the second argument should be 11.
16 |
17 | ```clojure
18 | (range 1 11)
19 | ```
20 |
21 | Unfortunately we cant just add the result of a range, because it returns a [lazy sequence](lazy-evaluation.html) So `(range)` by itself will create an error
22 |
23 | ```clojure
24 | (+ 1 (range 1 11))
25 | ```
26 |
27 | Using a function called `reduce` we can calculate a single total value from all the numbers in the collection.
28 |
29 | The reduce function take 2 arguments, the first is the function to apply to a data structure, the second is the data structure.
30 |
31 | ```clojure
32 | (reduce + (range 1 11))
33 |
34 | (reduce + (1 2 3 4 5 6 7 8 9 10))
35 | ```
36 |
--------------------------------------------------------------------------------
/docs/coding-challenges/palindrome/index.md:
--------------------------------------------------------------------------------
1 | # Project Palindrome
2 |
3 | In this section we will create a simple Clojure project using Leiningen and build up a palindrome checker step by step.
4 |
5 | We will start with the simplest possible thing we can create and steadily add
6 |
7 | ## What is a Palindrome
8 |
9 | For this project it is assumed that a palindrome is a string of characters from the English alphabet and not any other language or an alphanumeric sequence.
10 |
11 | It is assumed that a palindrome is at least 3 characters long, meaning a single character cannot be a palindrome. If a single character was a palindrome, then any valid sequence would contain at least as many palindromes as characters in that sequence.
12 |
13 | ## Challenge
14 |
15 | Write an algorithm to find the 3 longest unique palindromes in a string. For the 3 longest palindromes, report the palindrome, start index and length in descending order of length. Any tests should be included with the submission.
16 |
17 | For example, the output for string, `"sqrrqabccbatudefggfedvwhijkllkjihxymnnmzpop"` should be:
18 |
19 | ```text
20 | Text: hijkllkjih, Index: 23, Length: 10
21 | Text: defggfed, Index: 13, Length: 8
22 | Text: abccba, Index: 5 Length: 6
23 | ```
24 |
25 | * Check for a palindrome
26 | * Generate a series of palindromes
27 |
--------------------------------------------------------------------------------
/docs/reference/standard-library/regular-expressions/matching-sub-sequences.md:
--------------------------------------------------------------------------------
1 | ## Matching sub-sequences
2 |
3 | `re-seq` returns a lazy seq of all of the matches. The elements of the seq are the results that `re-find` would return.
4 |
5 | ```clojure
6 | (re-seq #"s+" "Helloween")
7 | ```
8 |
9 |
10 | ## Most common word
11 |
12 | `re-seq` is used in the most common word challenge to split a string into individual words.
13 |
14 | Extract from Project Guttenburg the text of The importance of being Earnest by Oscar Wilde. This returns a string of the whole book.
15 |
16 | The book is broken down into a collection of individual words using `re-seq` and a regular expression pattern.
17 |
18 | The collection of words is converted to lower case, so that `The` and `the` are not counted as separate words. `frequencies` returns a collection of tuples, each tuple being a word and a value representing how often it occurs. This collection is sorted by the value in descending order to show the word with the most occurrences at the top.
19 |
20 | ```clojure
21 | (->> (slurp "http://www.gutenberg.org/cache/epub/844/pg844.txt")
22 | (re-seq #"[a-zA-Z0-9|']+")
23 | (map #(clojure.string/lower-case %))
24 | frequencies
25 | (sort-by val dec))
26 | ```
27 |
28 | TODO: add link to complete example.
29 |
--------------------------------------------------------------------------------
/docs/clojure-cli/projects/templates/practicalli/landing-page.md:
--------------------------------------------------------------------------------
1 | # Practicalli Landing Page
2 |
3 | Build simple websites and landing pages using ClojureScript and figwheel-main.
4 |
5 | ```shell
6 | clojure -T:project/create :template landing-page :name practicalli/website-name
7 | ```
8 |
9 |
10 | ## Using the project
11 |
12 | Run the REPL
13 |
14 | ```shell
15 | make repl
16 | ```
17 |
18 | Run tests (stopping on first failing test)
19 |
20 | ```shell
21 | make test
22 | ```
23 |
24 |
25 |
26 | ## Template design
27 |
28 | Configuration files
29 |
30 | - `deps.edn` project dependencies and aliases defining figwheel builds
31 | - `dev.cljs.edn` development build configuration
32 | - `live.cljs.edn` live build configuration (GitHub pages deployment by default)
33 | - `figwheel-main.edn` general figwheel configuration
34 |
35 | Clojure code
36 |
37 | - `src/project/landing-page.clj` compose components to render the website
38 | - `src/project/components.clj` functions that define component and associated helper functions
39 | - `src/project/data.clj` data structure passed in part or whole to each component, via the `landing-page`.
40 |
41 | > `project.data` namespace defines an example data structure as a static value (def). Use an atom to contain the data structure if the data should be updated by components in the project.
42 |
--------------------------------------------------------------------------------
/docs/reference/clojure-syntax/ratios.md:
--------------------------------------------------------------------------------
1 | # Ratios
2 |
3 | In mathematics you need to ensure that you manage precision of your calculations when you are dividing numbers. Once you create a decimal number then everything it touches had a greater potential to becoming a decimal.
4 |
5 | > **Note** Calculate a rough approximation to Pi by dividing 22 by 7
6 |
7 | ```
8 | (/ 22 7)
9 | (class (/ 22 7))
10 | (/ (* 22/7 3) 3)
11 | ```
12 |
13 | 
14 |
15 | If the result of an integer calculation would be a decimal number, then Clojure holds the value as a Ratio. This is one example of lazy evaluation. Rather than calculate the decimal value at some particular precision (number of decimal points). Clojure is saving the calculation until its needed, at which time the specific precision required should be known.
16 |
17 | > **Note** Explore the ratio type further and see how to get a decimal value as the result
18 |
19 | ```clojure
20 | (/ 14 4)
21 | (/ 16 12)
22 | (/ 2)
23 | (/ 22 7.0)
24 | (type (/ 22 7.0))
25 | (float (/ 22 7))
26 | (double (/ 22 7))
27 | ```
28 |
29 | 
30 |
31 | When one or more of the numbers in the division is a decimal, then Clojure will return a decimal value. Or you can coerce a value to a specific decimal type, eg. float or double.
32 |
--------------------------------------------------------------------------------
/overrides/partials/palette.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
37 |
--------------------------------------------------------------------------------
/docs/reference/clojure-syntax/assigning-names.md:
--------------------------------------------------------------------------------
1 | # Assigning Names
2 |
3 | If we have to type the same values over and over, it would be very hard to write a program. What we need are names for values, so we can refer to them in a way we can remember. We do that using `def`.
4 |
5 | ```clojure
6 | (def mangoes 3)
7 | (def oranges 5)
8 | (+ mangoes oranges)
9 | ```
10 |
11 | When you assign a name to a value, that name is called a _symbol_. You can assign more than simple values to symbols. Try the following:
12 |
13 | ```clojure
14 | (def fruit (+ mangoes oranges))
15 | (def average-fruit-amount (/ fruit 2))
16 | average-fruit-amount
17 | ```
18 |
19 | Look at the last line, and see how we can use symbols by themselves to refer to a value.
20 |
21 | > **Note** Take the Clojure syntax you have learnt to far and write a metric/imperial converter
22 |
23 | Take your height in feet and inches and convert it to inches using arithmetic in Clojure.
24 |
25 | Then convert that to centimeters. There are 2.54 centimeters in an inch.
26 |
27 | Lastly, ask two people near you for their height in centimeters. Find the average of your heights.
28 |
29 | > **Note** Bonus: Convert that average back to feet and inches. The feet and the inches will be separate numbers. `(quot x y)` will give you the whole number part when dividing two numbers. `(mod x y)` will give you the remainder when dividing two numbers.
30 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/predicate-functions.md:
--------------------------------------------------------------------------------
1 | # Spec - Predicate functions
2 |
3 | A predicate is a function that returns a true or false value and their names end with `?` by convention.
4 |
5 | ```clojure
6 | (odd? 1)
7 | ```
8 |
9 | ```clojure
10 | (string? "am i a string")
11 | ```
12 |
13 | ```clojure
14 | (int? 2.3)
15 | ```
16 |
17 | ```clojure
18 | (int? 2.3)
19 | ```
20 |
21 | !!! HINT "`clojure.core` predicate functions"
22 | [`clojure.core` defines 80+ predicate functions](/reference/standard-library/predicate-functions.md)
23 |
24 | ## Predicate functions in specs
25 |
26 | Predicate functions can be used as un-named specifications to test values conform.
27 |
28 | Include the `clojure.spec.alpha` namespace to access the spec functions.
29 |
30 | ```clojure
31 | (require '[clojure.spec.alpha :as spec])
32 | ```
33 |
34 | ```clojure
35 | (spec/conform int? 42)
36 | ```
37 |
38 | ```clojure
39 | (spec/conform seq? (range 4))
40 | ```
41 |
42 | ## Custom predicate functions
43 |
44 | Define custom predicate functions with `defn` or `fn` or the short form `#()`
45 |
46 | Using an anonymous function
47 |
48 | ```clojure
49 | (spec/conform (fn [value] (= value 42)) 42)
50 | ```
51 |
52 | When the expression is quite terse, then the short form of an anonymous function is typically used. The `%` represents the value passed as an argument.
53 |
54 | ```clojure
55 | (spec/conform #(= % 42) 42)
56 | ```
57 |
--------------------------------------------------------------------------------
/docs/defining-behaviour-with-functions/calling-functions.md:
--------------------------------------------------------------------------------
1 | # Calling Functions
2 |
3 | To call a function in Clojure you use the name of the function as the first element of a list.
4 |
5 | In this simple example, a function is defined that takes no arguments, then that function is called.
6 |
7 | ```clojure
8 | (defn my-function []
9 | (str "I only return this string"))
10 |
11 | (my-function)
12 | ```
13 |
14 | Functions can be defined to take arguments.
15 |
16 | ## Arity
17 |
18 | This is the term to describe the number of arguments a function takes. This can be a fixed number or variable number of arguments.
19 |
20 | Simple polymorphism can also be used to have one function take different numbers of arguments, as with the `multi-arity` function in the examples below.
21 |
22 | ```clojure
23 | (defn single-arity []
24 | (str "I do not take any arguments"))
25 |
26 | (defn single-arity [argument]
27 | (str "I take 1 argument only"))
28 |
29 | (defn triple-arity [argument1 argument2 argument3]
30 | (str "I take 3 arguments only"))
31 |
32 | (defn multi-arity
33 | ([argument]
34 | (str "I match 1 argument only"))
35 | ([argument1 argument2]
36 | (str "I match when 2 arguments are used")))
37 |
38 | (defn variable-arity [argument & more-arguments]
39 | (str "I assign the first argument to argument,
40 | all other arguments to more-arguments"))
41 | ```
42 |
43 | ---
44 |
--------------------------------------------------------------------------------
/docs/reference/threading-macros.md:
--------------------------------------------------------------------------------
1 | # Reference: Threading macros
2 |
3 | Using the threading macro, the result of every function is passed onto the next function in the list. This can be seen very clearly using ,,, to denote where the value is passed to the next function
4 |
5 | ```clojure
6 | (->
7 | "project.clj"
8 | slurp ,,,
9 | read-string ,,,
10 | (nth ,,, 2))
11 | ```
12 |
13 | > #### Hint::Commas in clojure are whitespace
14 | >
15 | > Commas are simply ignored when the Clojure Reader parses code. Commas are rarely used and only to help human readability of the code
16 |
17 | To make this really simple lets create a contrived example of the threading macro. Here we use the `str` function to join strings together. Each individual `str` function joins its own strings together, passing the resulting string as the first argument to the next function.
18 |
19 | ```clojure
20 | (->
21 | (str "This" " " "is" " ")
22 | (str "the" " " "threading" " " "macro")
23 | (str "in" " " "action."))
24 | ```
25 |
26 | Output
27 |
28 | ```
29 | ;; => "This is the threading macro in action"
30 | ```
31 |
32 | ## Thread-last macro
33 |
34 | Using the thread-last macro, **->>**, the result of a function is passed as the last argument of the next function call. So in another simple series of str function calls, our text comes out backwards.
35 |
36 | ```clojure
37 | (->> " this"
38 | (str " is")
39 | (str " backwards"))
40 | ```
41 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | :memo: Description
2 |
3 |
4 | :white_check_mark: Checklist
5 |
6 | - [ ] Commits should be cryptographically signed (SSH or GPG)
7 |
8 |
9 | ## Practicalli Guidelines
10 |
11 | Please follow these guidelines when submitting a pull request
12 |
13 | - refer to all relevant issues, using `#` followed by the issue number (or paste full link to the issue)
14 | - PR should contain the smallest possible change
15 | - PR should contain a very specific change
16 | - PR should contain only a single commit (squash your commits locally if required)
17 | - Avoid multiple changes across multiple files (raise an issue so we can discuss)
18 | - Avoid a long list of spelling or grammar corrections. These take too long to review and cherry pick.
19 |
20 | ## Submitting articles
21 |
22 | [Create an issue using the article template](https://github.com/practicalli/blog-content/issues/new?assignees=&labels=article&template=article.md&title=Suggested+article+title),
23 | providing as much detail as possible.
24 |
25 | ## Website design
26 |
27 | Suggestions about website design changes are most welcome, especially in terms of usability and accessibility.
28 |
29 | Please raise an issue so we can discuss changes first, especially changes related to aesthetics.
30 |
31 | ## Review process
32 |
33 | All pull requests are reviewed by @practicalli-johnny and feedback provided, usually the same day but please be patient.
34 |
--------------------------------------------------------------------------------
/.github/workflows/changelog-check.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Check CHANGELOG.md file updated for every pull request
3 |
4 | name: Changelog Check
5 | on:
6 | pull_request:
7 | paths-ignore:
8 | - "README.md"
9 | types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
10 |
11 | jobs:
12 | changelog:
13 | name: Changelog Update Check
14 | runs-on: ubuntu-latest
15 | steps:
16 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}"
17 | - run: echo "🐧 Job running on ${{ runner.os }} server"
18 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository"
19 |
20 | # Git Checkout
21 | - name: Checkout Code
22 | uses: actions/checkout@v5
23 | with:
24 | fetch-depth: 0
25 | sparse-checkout: |
26 | docs
27 | overrides
28 | .github
29 | CHANGELOG.md
30 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner."
31 |
32 | # Changelog Enforcer
33 | - name: Changelog Enforcer
34 | uses: dangoslen/changelog-enforcer@v3
35 | with:
36 | changeLogPath: "CHANGELOG.md"
37 | skipLabels: "skip-changelog-check"
38 |
39 | # Summary and status
40 | - run: echo "🎨 Changelog Enforcer quality checks completed"
41 | - run: echo "🍏 Job status is ${{ job.status }}."
42 |
--------------------------------------------------------------------------------
/docs/alternative-tools/clojure-cli/basic-repl.md:
--------------------------------------------------------------------------------
1 | # Basic Terminal REPL UI
2 |
3 | The `clojure` command will start a REPL by default or if given the `--repl` or `-r` argument. The basic repl does not provide history of commands.
4 |
5 | `clj` is a script that wraps the `clojure` command and requires `rlwrap`, an external readline command, to navigate REPL history via the ++arrow-up++ and ++arrow-down++ keys.
6 |
7 | Use `clj` when you want to run a repl (or preferably use [rebel readline](rebel-readline/) instead) and `clojure` for everything else.
8 |
9 | !!! HINT "Rebel Rich Terminal UI"
10 | [rebel readline](/clojure/clojure-cli/repl/) is a terminal REPL UI that provides interactive help, function autocomplete, signature prompts and many other features to provide a very rich REPL experience.
11 |
12 | [:fontawesome-solid-book-open: Practicalli Clojure CLI Config](/clojure/clojure-cli/practicalli-config/) includes the `-M:repl/rebel` alias to run rebel readline REPL.
13 |
14 |
15 | `clj` command in a terminal window starts a Clojure REPL and shows the version of Clojure used. The command does not need to be in a directory containing a Clojure project.
16 |
17 | ```shell
18 | clj
19 | ```
20 |
21 | Type in a Clojure expression at the `=> user` REPL prompt and press ++enter++ to see the result
22 |
23 | ++ctrl+"d"++ to exit the REPL
24 |
25 | 
26 |
--------------------------------------------------------------------------------
/docs/reference/clojure-syntax/naming.md:
--------------------------------------------------------------------------------
1 | # Naming
2 |
3 | ## Naming when requiring other namespaces
4 |
5 | `(require [cheshire.core :refer :all])` is an example of self-inflicted errors, as this library included a `contains?` function that will over-write the `clojure.core/contains?` function when using `:refer :all` or the `(use )` expression.
6 |
7 | This situation is one example of why `:refer :all` and `use` are not recommended and can cause lots of debugging headaches.
8 |
9 | If a namespace is predominantly about using a specific library, then refer specific functions as they are used within the current namespace
10 |
11 | ```clojure
12 | (ns current.namespace
13 | (:require
14 | [cheshire.core :refer [function-name another-function etc]))
15 | ```
16 |
17 | > #### Hint::clj-kondo lint tool shows unused functions
18 | >
19 | > Using clj-kondo
20 |
21 | A classic example is a test namespace that uses clojure core
22 | (ns practicalli.random-function-test
23 | (:require [clojure.test :refer [deftest is testing]]
24 | [practicalli.random-function :as sut]))
25 | Otherwise use a meaningful alias, ideally referring to what that library is doing (which makes it easer to swap out with a different library later on if required). As Cheshire is a JSON related library, then
26 | (ns my.ns
27 | (:require [cheshire.core :as json]))
28 | This gives a context to all the functions called from that library and makes code easier for humans to understand.
29 |
--------------------------------------------------------------------------------
/docs/introduction/concepts/naming-local.md:
--------------------------------------------------------------------------------
1 | # Naming - local scope
2 |
3 | ## Local names in functions
4 |
5 | You can define names for things within the scope of a function using the `let` function.
6 |
7 | ### Example
8 |
9 | You can use the let function to define a simple expression, for which everything will go out of scope once it has been evaluated
10 |
11 | ```
12 | (let [local-name "some value"])
13 | (let [minutes-in-a-day (* 60 60 24)])
14 | ```
15 |
16 | You can also use `let` inside a function to do something with the arguments passed to that function. Here we calculate the hourly-rate from a yearly salary, returning the calculated-rate.
17 |
18 | (defn hourly-rate [yearly-salary weeks-in-year days-in-week]
19 | (let [calculated-rate (/ yearly-salary weeks-in-year days-in-week)]
20 | calculated-rate))
21 |
22 | (hourly-rate 60000 48 5)
23 |
24 | ```
25 |
26 |
27 |
28 | ## Local names in data structures
29 |
30 | When defining a map you are creating a series of key value pairs. The key is essentially a name that represents the value it is paired with. Keys are often defined using a `:keyword`.
31 |
32 | ```clojure
33 | {:radius 10, :pi 22/7 :colour purple}
34 |
35 | (def my-circle {:radius 10, :pi 22/7 :colour purple})
36 | ```
37 |
38 | > **Fixme** This is incorrect, as a Clojure keyword type (a name starting with :) have global scope within a namespace. If the keys were strings, then they would have the scope of just the collection.
39 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/function-composition.md:
--------------------------------------------------------------------------------
1 | # Function Composition
2 |
3 | We have discussed how functional programs are essentially a number of functions that work together, this is called composition (functional composition).
4 |
5 | ```
6 | (let [calculated-value (* 10 (reduce + (map inc (range 5))))]
7 | calculated-value)
8 | ```
9 |
10 | This expression is common in the Lisp & Clojure languages. Occasionally the created expressions can becomes challenging to read. To overcome this parsing complexity, developers often break down a more complex expression into its parts, extracting code into its own function.
11 |
12 | > **Note** Brake down the above example into each expression that gives a value
13 |
14 |
15 |
16 | ```
17 | (range 5)
18 |
19 | (map inc (range 5))
20 |
21 | (reduce + (map inc (range 5)))
22 |
23 | (* 10 (reduce + (map inc (range 5))))
24 |
25 |
26 | ;; Additional examples
27 |
28 | ;; Use a let expression for code that is used more than once in a function
29 |
30 | (let [calculated-value (* 10 (reduce + (map inc (range 5))))]
31 | calculated-value)
32 |
33 | ;; Use defn to define a function for code that multiple functions will call
34 | ;; and generalise the function with arguments
35 |
36 | (defn common-data-calculation
37 | [certainty-factor scope]
38 | (* certainty-factor (reduce + (map inc (range scope)))))
39 | ```
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/defining-specifications.md:
--------------------------------------------------------------------------------
1 | # Defining specifications
2 |
3 | `clojure.spec.alpha/def` binds a name to a specification, just like `clojure.core/def` binds a name to a value.
4 |
5 | Binding a name means specifications are available throughout the code and in other projects if the project is included as a library.
6 |
7 |
8 | ## Naming - fully qualified keywords
9 |
10 | Specification names should use fully qualified keywords, typically using the namespace in which the specification is defined in.
11 |
12 | Define a namespace for the page and require Clojure Spec
13 |
14 | ```clojure
15 | (ns practicalli.clojure.specifications
16 | (:require [clojure.spec.alpha :as spec]))
17 | ```
18 |
19 |
20 | ```clojure
21 | (spec/def :practicalli.clojure.specifications/number number?)
22 | ```
23 |
24 |
25 | ## auto-resolve macro
26 |
27 | `::` double colon is the auto-resolve macro, which will pre-pend the current namespace to the specification keyword. The `::` notation removes the need to edit fully qualified names should a specification be moved to a different namespace.
28 |
29 | ```clojure
30 | (spec/def ::number number?)
31 | ```
32 |
33 | !!! HINT "Fully Qualified keywords"
34 | Using fully qualified keywords ensures they are unique and therefore can be used across all projects.
35 |
36 | Namespaces are usually unique as they include the name of the company or organization behind the code and any project or component names used to organize the code.
37 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/polymorphism.md:
--------------------------------------------------------------------------------
1 | # Polymorphic function definitions
2 |
3 | Polymorphic means many forms.
4 |
5 | The simplest example of polymorphism in Clojure is a function definition that acts differently based on the number of arguments passed.
6 |
7 | Usually you define a function with one set of arguments, either none `[]`, one `[one]` or many `[any number of args]`, using the basic syntax
8 |
9 | ```clojure
10 | (defn name
11 | "I am the doc string to describe the function"
12 | [args]
13 | (str "define your behaviour here"))
14 | ```
15 |
16 | Instead of writing multiple functions with the same name that each take different numbers of arguments, you can use the following polymorphic syntax in Clojure
17 |
18 | ```clojure
19 | (defn name
20 | "I am the doc string to describe the function"
21 | ([]
22 | (str "behaviour with no args"))
23 | ([one]
24 | (str "behaviour with one arg"))
25 | ([one two & args]
26 | (str "behaviour with multiple args")))
27 | ```
28 |
29 | > **Note** Write a simple function called `i-am-polly` that returns a default message when given no arguments and a custom message when given a custom string as an argument
30 |
31 |
32 |
33 | ```clojure
34 | (defn i-am-polly
35 | ([] (i-am-polly "My name is polly"))
36 | ([message] (str message)))
37 |
38 | (i-am-polly)
39 | (i-am-polly "I call different behaviour depending on arguments sent")
40 | ```
41 |
42 |
43 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/index.md:
--------------------------------------------------------------------------------
1 | # Thinking Functionally
2 |
3 | In this section I cover some simple examples of Clojure code to help you think about the concepts involved in functional programming.
4 |
5 | An overview of thinking functionally is also covered in the presentation entitled [Getting into Functional Programming with Clojure](http://www.slideshare.net/jr0cket/cebit-get-into-functional-programming-with-clojure) on slideshare and its accompanying [youtube video](https://www.youtube.com/watch?v=mEfqULqChZs)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | [](https://clojurians.slack.com/messages/practicalli)
14 |
15 | Get a [free Clojurians slack community account](https://clojurians.net/)
16 |
--------------------------------------------------------------------------------
/docs/using-data-structures/destructuring.md:
--------------------------------------------------------------------------------
1 | # Destructuring
2 |
3 | Destructuring is a form of pattern matching that is common in Clojure. Destructuring allow you to pull out the specific elements from a collection.
4 |
5 | Destructuring is commonly used with the `let` method for creating local bindings (locally scoped names).
6 |
7 | ```clojure
8 | (let [[a b c & d :as e] [1 2 3 4 5 6 7]]
9 | [a b c d e])
10 |
11 | (let [[[x1 y1][x2 y2]] [[1 2] [3 4]]]
12 | [x1 y1 x2 y2])
13 |
14 | ;; with strings
15 | (let [[a b & c :as str] "asdjhhfdas"]
16 | [a b c str])
17 |
18 | ;; with maps
19 | (let [{a :a, b :b, c :c, :as m :or {a 2 b 3}} {:a 5 :c 6}]
20 | [a b c m])
21 | ```
22 |
23 | It is often the case that you will want to bind same-named symbols to the map keys. The :keys directive allows you to avoid the redundancy:
24 |
25 | ```clojure
26 | (let [{fred :fred ethel :ethel lucy :lucy} m] )
27 | ```
28 |
29 | This can be written in a shorter form as follows:
30 |
31 | ```clojure
32 | (let [{:keys [fred ethel lucy]} m] )
33 | ```
34 |
35 | As of Clojure 1.6, you can also use prefixed map keys in the map destructuring form:
36 |
37 | ```clojure
38 | (let [m {:x/a 1, :y/b 2}
39 | {:keys [x/a y/b]} m]
40 | (+ a b))
41 | ```
42 |
43 | As shown above, in the case of using prefixed keys, the bound symbol name will be the same as the right-hand side of the prefixed key. You can also use auto-resolved keyword forms in the :keys directive:
44 |
45 | ```clojure
46 | (let [m {::x 42}
47 | {:keys [::x]} m]
48 | x)
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/data-inspector/index.md:
--------------------------------------------------------------------------------
1 | # Clojure Data Inspector tools
2 |
3 | Clojure has a strong focus on built in data structures (list, vector, hash-map, set) to represent information in the system. Tools to inspect data and browse through nested or large data sets are invaluable in understanding what the system is doing.
4 |
5 | There are many `clojure.core` functions that can be used to explore data structures and transform them to produce specific views on data.
6 |
7 | `tap>` and `datafy` provide an elegant way of exploring data, rather than a classic `println` expression.
8 |
9 | Data Inspector tools capture and visualize results from evaluated expressions as well as tools to specifically visualize `tap>` expressions (Reveal, Portal).
10 |
11 | ## Common approaches
12 |
13 | * [:fontawesome-solid-book-open: Portal](portal.md) tool to navigate and visualise data via `tap>` for use with any editor or directly with a REPL prompt
14 | * [:fontawesome-solid-book-open: Clojure inspector](clojure-inspector.md) built-in Java Swing based inspector
15 | * [:fontawesome-solid-book-open: CIDER inspect](https://practical.li/spacemacs/evaluating-clojure/inspect/){target=_blank} Emacs specific tool (Practicalli Spacemacs)
16 |
17 |
18 | !!! TIP "Practicalli recommends Portal"
19 | [:fontawesome-solid-book-open: Portal](portal.md) works with any Clojure connected editor and can inspect `tap>` expressions and automatically inspect all evaluation results over nREPL for a complete REPL history.
20 |
21 | Practicalli sends all log events to Portal using a custom mulog publisher.
22 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/side-effects.md:
--------------------------------------------------------------------------------
1 | # Side effects
2 |
3 | A side effect is something that creates a change outside of the current code scope, or something external that affects the behaviour or result of executing the code in the current scope.
4 |
5 | ## Nondeterministic - the complexity iceberg
6 |
7 | When you have side effects, you cannot reason accurately about a piece of the code.
8 |
9 | In order to understand a piece of code you must look at all possible side effects created in all lines of code to ensure you fully understand the result of executing your code.
10 |
11 | With side effects in your system, complexity is hidden, causing a far greater risk of a dangerous situation.
12 |
13 | ## Side causes - side effects
14 |
15 | You can think about these effects is in two specific areas, **Side Causes** and **Side Effects**
16 |
17 | * **Side Causes** - are where other pieces of code (function) or state change affects the behaviour of a function.
18 |
19 | * **Side Effects** - are where the current code (function) affects the rest of the system
20 |
21 | [](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/theory/side-causes-side-effects.png)
22 |
23 | > #### Hint::Side Causes term
24 | >
25 | > The term of side causes was coined by [Kris Jenkins](https://twitter.com/krisajenkins) in the superb article [What is Functional Programming?](http://blog.jenkster.com/2015/12/what-is-functional-programming.html)
26 |
--------------------------------------------------------------------------------
/docs/clojure-spec/projects/bank-account/rebel-readline.md:
--------------------------------------------------------------------------------
1 | # Using the project in rebel readline
2 |
3 | > #### Hint::TODO: add screenshots using Rebel readline REPL
4 |
5 | Start the rebel REPL
6 |
7 | ```shell
8 | clojure -M:repl/rebel
9 | ```
10 |
11 | Once rebel has started a prompt will be displayed.
12 |
13 | First required the main namespace, containing the functions of the application. This loads the code in that namespace into the REPL.
14 |
15 | ```clojure
16 | (require 'practicalli.banking-on-clojure)
17 | ```
18 |
19 | Now add the specifications for the project
20 |
21 | ```clojure
22 | (require 'practicalli.banking-on-clojure)
23 | ```
24 |
25 | ? When does the TAB completion start to work ?
26 |
27 | Testing the specifications
28 |
29 | First change into the specifications namespace so the fully qualified names of the specs are not required.
30 |
31 | ```clojure
32 | (in-ns 'practicalli.banking-specifications)
33 | ```
34 |
35 | Generate sample data from the specifications
36 |
37 | ```
38 | (spec-gen/sample (spec/gen ::account-id))
39 | ```
40 |
41 | The function specifications and the instrument functions are loaded from the requires, so test by calling the instrumented functions, first with bad data and then with correct data.
42 |
43 | ```clojure
44 | (register-account-holder {})
45 | ```
46 |
47 | Use the specifications to generate good data
48 |
49 | ```clojure
50 | (register-account-holder ::customer-details)
51 | ```
52 |
53 | Run generative tests on functions to check the return and fn values
54 |
55 | ```clojure
56 | (spec-test/check `register-account-holder)
57 | ```
58 |
--------------------------------------------------------------------------------
/docs/modifying-data-structures/lists.md:
--------------------------------------------------------------------------------
1 | # Lists
2 |
3 | You can change lists with the `cons` function, see `(doc cons)` for details
4 |
5 | (cons 5 '(1 2 3 4))
6 |
7 | You will see that `cons` does not change the existing list, it create a new list that contains the number 5 and a link to all the elements of the existing list.
8 |
9 | You can also use cons on vectors `(cons 5 [1 2 3 4])`
10 |
11 | ```
12 | (cons "fish" '("and" "chips"))
13 |
14 | (conj '(1 2 3 4) 5)
15 |
16 | (conj [1 2 3 4] 5)
17 |
18 |
19 | ;; Lets define a simple list and give it a name
20 | (def list-one '(1 2 3))
21 |
22 | ;; the name evaluates to what we expect
23 | list-one
24 |
25 | ;; If we add the number 4 using the cons function, then we
26 | ;; get a new list in return, with 4 added to the front (because thats how lists work with cons)
27 | (cons 4 list-one)
28 |
29 | ;; If we want to keep the result of adding to the list, we can assign it a different name
30 | (def list-two (cons 4 list-one))
31 | ;; and we get the result we want
32 | list-two
33 |
34 | ;; we can also pass the original name we used for the list to the new list
35 | (def list-one (cons 4 list-one))
36 |
37 | ;; If we re-evaluate the definition above, then each time we will get an extra
38 | ;; number 4 added to the list.
39 |
40 | list-one
41 |
42 | ;; Again, this is not changing the original list, we have just moved the name
43 | ;; of the list to point to the new list.
44 | ;; Any other function working with this data structure before reassigning the name
45 | ;; will not be affected by the re-assignment and will use the unchanged list.
46 |
47 | ```
48 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/conform.md:
--------------------------------------------------------------------------------
1 | ## Does a value conform to a specification?
2 |
3 | `clojure.spec.alpha/conform` takes two arguments
4 |
5 | - a specification
6 | - a value to test against the specification
7 |
8 | `:clojure.spec.alpha/invalid` is returned when a value does not conform to a specification.
9 |
10 | If the value does conform to the specification, then the value is returned. This value is referred to as a conformed value.
11 |
12 | ## Require the Clojure spec library
13 |
14 | Set the namespace for the page and require clojure.spec.alpha library, setting the alias to `spec`
15 |
16 | ```clojure
17 | (ns practicalli.clojure.specifications
18 | (:require [clojure.spec.alpha :as spec]))
19 | ```
20 |
21 | ## Using conform
22 |
23 | If the value conforms to the spec, a conformed value is returned
24 |
25 | ```clojure
26 | (spec/conform odd? 101)
27 | ```
28 |
29 |
30 |
31 | When a value does not conform to a spec, the value `:clojure.spec.alpha/invalid` is returned
32 |
33 | ```clojure
34 | (spec/conform even? 101)
35 | ```
36 |
37 |
38 |
39 | ```clojure
40 | (spec/conform integer? 1)
41 | ```
42 |
43 |
44 |
45 | ```clojure
46 | (spec/conform seq? [1 2 3])
47 | ```
48 |
49 |
50 |
51 | ```clojure
52 | (spec/conform seq? (range 10))
53 | ```
54 |
55 |
56 |
57 | ```clojure
58 | (spec/conform map? {})
59 | ```
60 |
61 |
62 |
63 | ```clojure
64 | (spec/conform map? (hash-map :a 1 :b 2))
65 | ```
66 |
67 |
--------------------------------------------------------------------------------
/docs/development-environments/leiningen.md:
--------------------------------------------------------------------------------
1 | # Leiningen Build tool
2 |
3 | [](http://leiningen.org/)
4 |
5 | [leiningen.org](http://leiningen.org/) (pronounced line-ing-en) is a very powerful build automation tool for automating Clojure projects. With Leiningen you can:
6 |
7 | * Create Clojure Projects with templates
8 | * Define and manage dependencies
9 | * Run an interactive Clojure environment (REPL)
10 | * Run unit tests using Clojure.test
11 | * Run your Clojure application
12 | * Create a deployable Clojure application, as Java Jar file
13 | * Deploy a Clojure library to a remote repository
14 |
15 | 
16 |
17 | ## Install Leiningen
18 |
19 | Download the install script from [leiningen.org](http://leiningen.org/) and run the Leiningen script in a terminal
20 |
21 | On Linux and MacOSX, make the script executable first
22 |
23 | chmod a+x lein
24 | ./lein
25 |
26 | > **Hint** I put the `lein` script in `~/bin` directory which is part of my operating system execution path ($PATH). To include the `~/bin` directory in the system path, I add the following code to the `~/.profile` file
27 |
28 |
29 |
30 | ## Testing Leiningen is working
31 |
32 | Test that Leiningen is installed with the following command
33 |
34 | lein version
35 |
36 | Output should look similar to:
37 |
38 | Leiningen 2.6.1 on Java 9-internal OpenJDK 64-Bit Server VM
39 |
--------------------------------------------------------------------------------
/docs/reference/tagged-literals/uuid.md:
--------------------------------------------------------------------------------
1 | # uuid tag literal
2 |
3 | A universally unique identifier (UUID).
4 |
5 | #uuid "8-4-4-4-12" - numbers represent the number of hex digits
6 | #uuid "97bda55b-6175-4c39-9e04-7c0205c709dc" - actual example
7 |
8 | Representing UUIDs with #uuid rather than just a plain string has the following benefits:
9 |
10 | the reader will throw an exception on malformed UUIDs
11 | its UUID type is preserved and shown when serialized to edn.
12 |
13 | ## Creating UUIDs - Clojure
14 |
15 | In Clojure, call the randomUUID method of the java.util.UUID class
16 |
17 | ```
18 | (java.util.UUID/randomUUID)
19 | ```
20 |
21 | This returns a UUID tagged literal.
22 |
23 | ```clojure
24 | (java.util.UUID/randomUUID)
25 | ;; => #uuid "44f3ffd7-6702-4b8a-af25-11bee4b5ec4f"
26 | ```
27 |
28 | Looking at the type we can see its a Java object from the java.util.UUID class:
29 |
30 | ```clojure
31 | (type (java.util.UUID/randomUUID))
32 | ;; => java.util.UUID
33 | ```
34 |
35 | ## Creating UUIDs - ClojureScript
36 |
37 | Randomly generate a UUID in ClojureScript:
38 |
39 | `cljs.core/random-uuid`
40 |
41 | To label a value as a UUID:
42 |
43 | `cljs.core/uuid`
44 |
45 | > #### Hint::uuid does not validate the value
46 | >
47 | > The [ClojureScript documentation](https://github.com/cljs/api/blob/master/docfiles/cljs.core/uuid.md) states that uuid? does not perform validation.
48 |
49 | ## Testing for a uuid
50 |
51 | `uuid?` tests a given value and returns true if it is a uuid tagged literal value.
52 |
53 | `tagged-literal?` is the more general function for any tagged values.
54 |
--------------------------------------------------------------------------------
/docs/clojure-spec/functions/documentation.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | The Clojure `doc` function shows the doc string included in a function definition, eg. `defn` expressions.
4 |
5 | When a specification is defined for a function using `fdef` the specification is included in the output of the Clojure `doc` function.
6 |
7 | Including specification details clarifies the precise way to use the function and the information it expects. When a function has a specification the doc string for that function can focus on the purpose of the function rather than the specific types of data used, as that is covered by the function specification.
8 |
9 | ## Example
10 |
11 | ```clojure
12 | (clojure.repl/doc ::rank)
13 |
14 | ;; :practicalli.card-game-specifications/rank
15 | ;; Spec
16 | ;; (into #{:king :queen :ace :jack} (range 2 11))
17 | ```
18 |
19 | When adding a specification to a function definition, `doc` will also show the specification details along with the function doc-string.
20 |
21 | ## Live example
22 |
23 | Define the namespace and include clojure spec and clojure.repl (which contains the doc function)
24 |
25 | ```clojure
26 | (ns practicalli.clojure
27 | (:require [clojure.repl :as repl]
28 | [clojure.spec.alpha :as spec]))
29 | ```
30 |
31 | Print the documentation for the `map` function
32 |
33 | ```clojure
34 | (repl/doc map)
35 | ```
36 |
37 | Print the documentation for the `:playing-card/suit`
38 |
39 | ```clojure
40 | (clojure.repl/doc :playing-card/suit)
41 | ```
42 |
43 | ```clojure
44 | #{:spade :heart :diamond :club}
45 | ```
46 |
47 | ```clojure
48 | (repl/doc :cat-show:cat-bread)
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/coding-challenges/exercism/space-age.md:
--------------------------------------------------------------------------------
1 | # Space Age
2 |
3 | 
4 |
5 | ## Topics covered
6 |
7 |
8 | !!! HINT "Code for this solution on GitHub"
9 | [practicalli/exercism-clojure-guides](https://github.com/practicalli/exercism-clojure-guides/) contains the design journal and solution to this exercise and many others.
10 |
11 | ## Create the project
12 |
13 | Download the RNA transcription exercise using the exercism CLI tool
14 |
15 | !!! NOTE ""
16 | ```shell
17 | exercism download --exercise=rna-transcription --track=clojure
18 | ```
19 |
20 | !!! HINT "Use the REPL workflow to explore solutions locally"
21 | Open the project in a [Clojure aware editor](/clojure/clojure-editors) and [start a REPL](/clojure/coding-challenges/exercism/#repl-workflow), using a rich comment form to experiment with code to solve the challenge.
22 |
23 |
24 | ## Challenge introduction
25 |
26 | Given an age in seconds, calculate how old someone would be on:
27 |
28 | - Earth: orbital period 365.25 Earth days, or 31557600 seconds
29 | - Mercury: orbital period 0.2408467 Earth years
30 | - Venus: orbital period 0.61519726 Earth years
31 | - Mars: orbital period 1.8808158 Earth years
32 | - Jupiter: orbital period 11.862615 Earth years
33 | - Saturn: orbital period 29.447498 Earth years
34 | - Uranus: orbital period 84.016846 Earth years
35 | - Neptune: orbital period 164.79132 Earth years
36 |
37 | So if you were told someone were 1,000,000,000 seconds old, you should be able to say that they're 31.69 Earth-years old.
38 |
--------------------------------------------------------------------------------
/docs/introduction/concepts/purpose.md:
--------------------------------------------------------------------------------
1 | # When to use Clojure
2 |
3 | Clojure is a general purpose language suitable for any kind of application or service. As Clojure implementations run across multiple technology platforms and operating systems, there are very few barriers to its use.
4 |
5 | So Clojure is great for webapps, data science, big data, finance industry (banking, trading, insurance, etc), devops tools (log analysis, etc) and anything else really.
6 |
7 | There are areas where Clojure obviously excels.
8 |
9 | ## Effective Data Manipulation
10 |
11 | Fundamentally all software systems take in data (in the form of values or events), process or react to that data and return as a result.
12 |
13 | The persistent data structures in Clojure (list, vector, hash-map and set) provide an efficient way to use immutable collections of data.
14 |
15 | The `clojure.core` library contains a vast number of data processing functions in Clojure so data is easily transformed
16 |
17 | ## Highly Scalable
18 |
19 | Clojure code is encouraged to be immutable and functions to be pure, you can run millions of parallel instances of your application or service for massive processing power. These features also vastly simplify concurrent programming.
20 |
21 | ## Reducing Complexity
22 |
23 | Clojure encourages a component design through functional composition, breaking down problems into components
24 |
25 | Clojure and its libraries are all great examples of well designed components and the community strongly encourages this approach.
26 |
27 | > #### Hint::Functional Reactive Programming
28 | >
29 | > You can also use ClojureScript for Functional Reactive programming of client-side apps for browsers and mobile device.
30 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/hierarchical-specifications.md:
--------------------------------------------------------------------------------
1 | # Hierarchical Specifications
2 |
3 | Defining specifications for data that is hierarchical or nested in nature.
4 |
5 | ```clojure
6 | (ns practicalli.clojure
7 | (:require [clojure.spec.alpha :as spec]))
8 | ```
9 |
10 | ## Example hierarchical data
11 |
12 | ```clojure
13 | {:top-level-key {:nested-key "value"}}
14 | ```
15 |
16 | ## Individual specifications
17 |
18 | ```clojure
19 | (spec/def ::first-name string?)
20 | ```
21 |
22 | ```clojure
23 | (spec/def ::last-name string?)
24 | ```
25 |
26 | ```clojure
27 | (spec/def ::residential-address string?)
28 | ```
29 |
30 | ## Composite Specification
31 |
32 | `keys` function combines specifications to form a composite specification in the form of a Clojure hash-map.
33 |
34 | ```clojure
35 | (spec/def ::customer-details
36 | (spec/keys
37 | :req [::first-name ::last-name ::residential-address]))
38 | ```
39 |
40 | ## Hierarchical Specification
41 |
42 | A user account is composed of a user-id and customer details. Rather than include the individual customer details, the composite customer-details specification.
43 |
44 | The `::user-id` specification is as follows
45 |
46 | ```clojure
47 | (spec/def ::user-id uuid?)
48 | ```
49 |
50 | The `::user-account` specification
51 |
52 | ```clojure
53 | (spec/def ::user-account
54 | (spec/keys
55 | :req [::user-id ::customer-details]))
56 | ```
57 |
58 | The following data structure will conform to the specification
59 |
60 | ```clojure
61 | {::user-id #uuid "97bda55b-6175-4c39-9e04-7c0205c709dc"
62 | ::customer-details {::first-name "Jenny"
63 | ::last-name "Jetpack"
64 | ::residential-address "Earth"}}
65 | ```
66 |
--------------------------------------------------------------------------------
/docs/clojure-spec/functions/index.md:
--------------------------------------------------------------------------------
1 | # Specification for function definitions
2 |
3 | Define specifications for your custom functions
4 |
5 | * Additional documentation - argument and return values and the relationship between them.
6 | * Instrumenting functions - checking for correct argument values
7 | * Generative testing - using argument specifications to generate comprehensive test data.
8 |
9 | Many of the functions in `clojure.core` have [specifications](https://github.com/clojure/core.specs.alpha) in the latest version of Clojure. The specifications for clojure.core functions can be found in the [clojure/core.specs.alpha](https://github.com/clojure/core.specs.alpha) repository on GitHub.
10 |
11 | ## clojure.core examples
12 |
13 | Specifications used for the `defn`, `defn-`, `fn` functions in `clojure.core`
14 |
15 | !!! EXAMPLE "clojure.core specification examples"
16 | ```clojure
17 | (s/def ::param-list
18 | (s/and
19 | vector?
20 | (s/cat :params (s/* ::binding-form)
21 | :var-params (s/? (s/cat :ampersand #{'&} :var-form ::binding-form)))))
22 |
23 | (s/def ::params+body
24 | (s/cat :params ::param-list
25 | :body (s/alt :prepost+body (s/cat :prepost map?
26 | :body (s/+ any?))
27 | :body (s/* any?))))
28 |
29 | (s/def ::defn-args
30 | (s/cat :fn-name simple-symbol?
31 | :docstring (s/? string?)
32 | :meta (s/? map?)
33 | :fn-tail (s/alt :arity-1 ::params+body
34 | :arity-n (s/cat :bodies (s/+ (s/spec ::params+body))
35 | :attr-map (s/? map?)))))
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/simple-projects/encode-decode/index.md:
--------------------------------------------------------------------------------
1 | # Encoding and Decoding with Clojure
2 |
3 | 
4 |
5 | Projects that use a range of ciphers, from simple to more complex, to encode and decode text.
6 |
7 | A common approach to encoding and decoding text is to use a dictionary lookup, defined in Clojure as a hash-map. Each key-value pair provides a mapping for encoding and decoding. Looking up a a character as a key in the map provides a value that is the encrypted character.
8 |
9 | These projects show several ways to transform data in Clojure.
10 |
11 | | Project | Topics | Description |
12 | |------------------------------------------------------|------------------|-------------------------------------------------|
13 | | [Boolean names to 0 or 1](convert-boolean-values.md) | hash-map get | Convert boolean values to classic 1 or 0 values |
14 | | [Caesar cipher - ROT13](caesar-cipher rot13.md) | seq cycle zipmap | A simple alphabet rotation cipher |
15 | | [RNA / DNA converter](rna-dna.md) | | Convert between DNA and RNA |
16 | | [Clacks telegram](clacks.md) | | Encoding and decoding messages with Clacks |
17 |
18 | ## Examples of Encoding
19 |
20 | * [Portable Network Graphics for image compression](https://en.wikipedia.org/wiki/Portable_Network_Graphics)
21 | * [Vorbis for music and video compression](https://en.wikipedia.org/wiki/Vorbis) plus several commercial compression encoders
22 | * [Enigma machine - encrypted communications](https://www.google.com/search?q=clojure+enigma+machine)
23 |
--------------------------------------------------------------------------------
/docs/reference/kebab-case.md:
--------------------------------------------------------------------------------
1 | # Clojure names use kebab-case
2 |
3 | 
4 |
5 | kebab-case is a clean, human-readable way to combine the words that would otherwise have spaces.
6 |
7 | Cloure uses kebab-case to combines words with a dash, `-`, rather than a space. e.g. `rock-paper-scissors`, `tic-tac-toe` or `(def db-spec-development {:db-type "h2" :db-name "banking-on-clojure"})`
8 |
9 | kebab-case is used throughout Clojure, including
10 |
11 | * Var names with `def` and function names with `defn`
12 | * Local names with `let`
13 | * Clojure spec names
14 |
15 | kebab-case is used in lisp languages including Clojure. The style is also used in website URLs, e.g. [practicalli.github.io/clojure-webapps](https://practical.li/clojure-web-services/)
16 |
17 | ## Using meaningful names
18 |
19 | To provide greater clarity to human developers, words may be combined for the names used when writing the code. Using multiple words can give greater context in to the purpose of that code.
20 |
21 | Using a combination of meaningful names makes understanding and debugging code far easier.
22 |
23 | ## Spaces characters have special meaning
24 |
25 | Programming languages remove spaces between words because the space character is used as a separator when parsing the code.
26 |
27 | If spaces were not used as a separator for the some other character would be required, adding complexity to the language syntax.
28 |
29 | ## Other Styles
30 |
31 | * camelCase - used in Java and C-style programming languages
32 | * PascalCase - used in the [Pascal programming language][1]
33 | * snake_case - used for `ENVIRONMENT_VARIABLES` and `database_table_names_and_columns`
34 |
35 | [1]: https://en.wikipedia.org/wiki/Pascal_(programming_language)
36 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/and-or-specifications.md:
--------------------------------------------------------------------------------
1 | # Combining specifications with and and or
2 |
3 | `clojure.core/and` function and `clojure.core/or` function can be used to define a specification with multiple parts.
4 |
5 | ## Conform to One or more specifications
6 |
7 | A specification for residential address included either a house number or name. The `clojure.core/or` function allows either type of value to be used and conform to the specification.
8 |
9 | ```clojure
10 | (spec/def ::house-name-number (or string? int?))
11 | ```
12 |
13 | Using `spec/or` then unique keys are required for each possible type of value. Keys are used to explain where a failure occurred if values do not conform to the specification.
14 |
15 | ```clojure
16 | (spec/def ::house-name-number (spec/or :string string?
17 | :number int?))
18 | ```
19 |
20 | If specifications are uses as the options in the `clojure.spec.alpha/or` then those specification names are used as the keys to explain where failure to conform to the specification happened.
21 |
22 | ```clojure
23 |
24 | (spec/def ::social-security-id (spec/or ::social-security-id-uk
25 | ::social-security-id-usa))
26 | ```
27 |
28 |
29 | ## Conform to all specifications
30 |
31 | Create a composite specification using `clojure.spec.alpha/and` when all specifications should be conformed by the values
32 |
33 |
34 | For an arranged banking overdraft limit, the value should be a positive number, that is an integer type and is less than 1000.
35 |
36 | ```clojure
37 | (spec/def ::arranged-overdraft-limit (spec/and pos? int? #(> 1000 %)))
38 | ```
39 |
40 | If a value does not conform to any of the three specifications then the value fails the `::arranged-overdraft-limit` specification.
41 |
--------------------------------------------------------------------------------
/docs/simple-projects/mutating-state/index.md:
--------------------------------------------------------------------------------
1 | # Mutating State in a Controlled way
2 |
3 | Mutating state should be used carefully and sparingly in Clojure (and all other programming languages).
4 |
5 | `atom` is a mutable container that can manage any value. The atom ensures that only one call at a time can affect the value it manages. This is part of the [software transactions memory system](https://clojure.org/reference/refs) in Clojure.
6 |
7 | As the atom is mutable in that the value it manages can be changed, however, this must be done with special commands (swap!, reset!, compare-and-set!, swap-vals!).
8 |
9 | Even though the atom is mutable, the values it manages are not. They are normal immutable (unchangeable) Clojure values.
10 |
11 | `ref` is similar to `atom` and can manage transactions, ensuring that all changes happen or no changes happen.
12 |
13 | | Project | Topics | Overview |
14 | |------------------|-----------------------|-----------------------------------------------------------------------------------------------|
15 | | Mutants assemble | atom swap! reset! | Using an atom to manage state changes |
16 | | Undo/Redo | atom add-watch | Traversing the history of an atom |
17 | | Poker game | atom swap! reset! ref | Simple transaction management using atom and ref in a card game, using constraints on an atom |
18 |
19 | ## References
20 |
21 | * [Atoms](https://clojure.org/reference/atoms) - clojure.org
22 | * [Refs and Transactions](https://clojure.org/reference/refs) - clojure.org
23 | * [Agents](https://clojure.org/reference/agents) - clojure.org
24 |
--------------------------------------------------------------------------------
/.github/workflows/scheduled-version-check.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # ------------------------------------------
3 | # Scheduled check of versions
4 | # - use as non-urgent report on versions
5 | # - Uses POSIX Cron syntax
6 | # - Minute [0,59]
7 | # - Hour [0,23]
8 | # - Day of the month [1,31]
9 | # - Month of the year [1,12]
10 | # - Day of the week ([0,6] with 0=Sunday)
11 | #
12 | # Using liquidz/anta to check:
13 | # - GitHub workflows
14 | # - deps.edn
15 | # ------------------------------------------
16 |
17 | name: "Scheduled Version Check"
18 | on:
19 | schedule:
20 | # - cron: "0 4 * * *" # at 04:04:04 ever day
21 | # - cron: "0 4 * * 5" # at 04:04:04 ever Friday
22 | - cron: "0 4 1 * *" # at 04:04:04 on first day of month
23 | workflow_dispatch: # Run manually via GitHub Actions Workflow page
24 |
25 | jobs:
26 | scheduled-version-check:
27 | name: "Scheduled Version Check"
28 | runs-on: ubuntu-latest
29 | steps:
30 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}"
31 | - run: echo "🐧 Job running on ${{ runner.os }} server"
32 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository"
33 |
34 | - name: Checkout Code
35 | uses: actions/checkout@v5
36 | with:
37 | fetch-depth: 0
38 | sparse-checkout: |
39 | .github
40 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner."
41 | - name: "Antq Check versions"
42 | uses: liquidz/antq-action@main
43 | with:
44 | excludes: ""
45 | skips: "boot clojure-cli pom shadow-cljs leiningen"
46 |
47 | # Summary
48 | - run: echo "🎨 library versions checked with liquidz/antq"
49 | - run: echo "🍏 Job status is ${{ job.status }}."
50 |
--------------------------------------------------------------------------------
/docs/clojure-spec/testing/index.md:
--------------------------------------------------------------------------------
1 | # Testing with Specifications
2 |
3 | > #### TODO::work in progress, sorry
4 |
5 | ## During development
6 |
7 | Create specifications for data and functions
8 |
9 | Selectively instrument function definitions to check function call arguments against the function specification.
10 |
11 | * clojure.spec.test.alpha/instrument - check fdef :args
12 |
13 | ## Unit and integration testing
14 |
15 | Add specification checks along with unit testing and integration testing to provide a very wide range of data values to be tested (with a minimal amount of code).
16 |
17 | * clojure.spec.test.alpha/check - use :args to generate tests to check fdef :ret and :fn
18 |
19 | run a suite of spec-generative tests on an entire ns with `check`. Just one namespace per `check` expression?
20 |
21 | control the number of values check creates for each check expression. As the default is 1000 the checks can take a noticeable time to run (see [practicalli/spec-generative-testing](https://github.com/practicalli/spec-generative-testing))
22 |
23 | Many built-in generators for `clojure.core` data predicates
24 |
25 | composite specifications can build generators upon predicate generators.
26 |
27 | Pass generator-returning functions to spec, supplying generators for things spec does not know about.
28 | Pass an override map to `gen` in order to supply alternative generators for one or more sub-paths of a spec.
29 |
30 | Define your own generators
31 |
32 | ## At run time
33 |
34 | Use specifications for run time checking, typically using `conform` and `valid?` functions.
35 |
36 | Specification are typically the minimal checks required for the system, compared to more extensive checks during test and system integration.
37 |
38 | Create lightweight private specifications for tests that run in the production environment.
39 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/registry.md:
--------------------------------------------------------------------------------
1 | # Registry for unique and re-usable specifications
2 |
3 | So far we have just use predicate functions directly in the code examples.
4 |
5 | Using a registry, specs can be uniquely defined across the whole project. Defining a spec gives that spec a name that has a fully qualified namespace
6 |
7 | Use the spec specific `def` function to bind a new spec name and fully qualified namespace and place it in the registry
8 |
9 | ```clojure
10 | (spec/def :playing-card/suit #{:club :diamond :heart :spade} )
11 | ```
12 |
13 | ```clojure
14 | (spec/conform :playing-card/suit :diamond)
15 | ```
16 |
17 | ```clojure
18 | (spec/def :show-cats/cat-bread #{:abyssinian :birman :chartreau :devon-rex
19 | :domestic-short-hair :domestic-long-hair})
20 | ```
21 |
22 | ## Removing specs from the registry
23 |
24 | Named specifications can be removed from the registry by binding the name to `nil`.
25 |
26 | If specification names are to be refactored, then the original name should be set to `nil` and evaluated, before changing the name. This will ensure stale specifications are not residing in the REPL.
27 |
28 | Here is a named specification as an example
29 |
30 | ```clojure
31 | (spec/def ::unwanted #{:abandoned})
32 | ```
33 |
34 | The specification is evaluated in the REPL (above) and currently works.
35 |
36 | ```clojure
37 | (spec/conform ::unwanted :abandoned)
38 | ```
39 |
40 | Remove this specification from the registry by binding it to nil
41 |
42 | ```clojure
43 | (spec/def ::unwanted nil)
44 | ```
45 |
46 | Now the specification is unavailable
47 |
48 | ```clojure
49 | (spec/conform ::unwanted :abandoned)
50 | ```
51 |
52 | !!! HINT "Registry not persistent"
53 | Restarting the REPL will loose all specification names in the registry as it is not persistent across REPL sessions.
54 |
--------------------------------------------------------------------------------
/.github/workflows/publish-book.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Publish Book
3 | on:
4 | # Manually trigger workflow
5 | workflow_dispatch:
6 |
7 | # Run work flow conditional on linter workflow success
8 | workflow_run:
9 | workflows:
10 | - "MegaLinter"
11 | paths:
12 | - "docs/**"
13 | - "includes/**"
14 | - "overrides/**"
15 | - "mkdocs.yaml"
16 | branches:
17 | - main
18 | types:
19 | - completed
20 |
21 | permissions:
22 | contents: write
23 |
24 | jobs:
25 | publish-book:
26 | name: MkDocs Publish
27 | runs-on: ubuntu-latest
28 | steps:
29 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}"
30 | - run: echo "🐧 Job running on ${{ runner.os }} server"
31 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository"
32 |
33 | - name: Checkout Code
34 | uses: actions/checkout@v5
35 | with:
36 | fetch-depth: 0
37 | sparse-checkout: |
38 | docs
39 | includes
40 | overrides
41 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner."
42 |
43 | - name: Setup Python
44 | uses: actions/setup-python@v6
45 | with:
46 | python-version: 3.x
47 |
48 | - name: Cache
49 | uses: actions/cache@v4
50 | with:
51 | key: ${{ github.ref }}
52 | path: .cache
53 |
54 | - run: pip install mkdocs-material mkdocs-callouts mkdocs-glightbox mkdocs-git-revision-date-localized-plugin mkdocs-redirects pillow cairosvg
55 | - run: mkdocs gh-deploy --force
56 | - run: echo "🐙 ."
57 |
58 | # Summary and status
59 | - run: echo "🎨 MkDocs Publish Book workflow completed"
60 | - run: echo "🍏 Job status is ${{ job.status }}."
61 |
--------------------------------------------------------------------------------
/docs/designing-data-structures/with-maps.md:
--------------------------------------------------------------------------------
1 | # Design with Maps
2 |
3 | Maps allow you to model data with its contextual meaning. The keys of a map can give the context and the values are the specific data.
4 |
5 | !!! NOTE ""
6 | Define a shopping list of items you want, including how many of each item you want to buy
7 |
8 | ??? EXAMPLE ""
9 | ```clojure
10 | (def shopping-list
11 | {"cat food" 10
12 | "soya milk" 4
13 | "bread" 1
14 | "cheese" 2})
15 | ```
16 |
17 | !!! NOTE ""
18 | Define a star-wars characters, eg. luke skywalker, jarjar binks. The star-wars character should include a name and a skill (it doesn't matter what these are).
19 |
20 | > Use the 'get' function to return the value of a given key, eg. name. Use keywords to return a given value if you used keywords for the map keys.
21 |
22 | ??? EXAMPLE ""
23 | In this answer we have defined three different star-wars characters, all using the same map keys.
24 |
25 | ```clojure
26 | (def luke {:name "Luke Skywalker" :skill "Targeting Swamp Rats"})
27 | (def darth {:name "Darth Vader" :skill "Crank phone calls"})
28 | (def jarjar {:name "JarJar Binks" :skill "Upsetting a generation of fans"})
29 | ```
30 |
31 | Lets see what the specific skill luke has
32 |
33 | ```clojure
34 | (get luke :skill)
35 | ```
36 |
37 | When you use a keyword, eg. :name, as the key in a map, then that keyword can be used as a function call on the map to return its associated value. Maps can also act as functions too.
38 |
39 | ```clojure
40 | (:name luke)
41 | (luke :name)
42 | ```
43 |
44 | There are also specific functions that work on maps that give all the `keys` of a map and all the `values` of that map
45 |
46 | ```clojure
47 | (keys luke)
48 | (vals luke)
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/development-environments/java.md:
--------------------------------------------------------------------------------
1 | ## Java - a host platform for Clojure
2 |
3 | [](https://www.java.com)
4 |
5 | You will need to have a Java Runtime Edition (usually installed on most computers by default) to run any Clojure applications. Version 8 is recommended (although version 6 & 7 should work).
6 |
7 | To test if you have Java on your computer, open a command line window and run the command
8 |
9 | java -version
10 |
11 | ## Installing the Java Runtime Edition
12 |
13 | Download and install the latest [Oracle Java SDK](https://www.java.com) (version 1.8 at time of writing).
14 |
15 | Alternatively, install [OpenJDK](http://openjdk.java.net/install/index.html) or [Zulu build of OpenJDK](http://zulu.org/)
16 |
17 | ## Ubuntu
18 |
19 | The OpenJDK is available as a package on Ubuntu and can be installed via the Ubuntu software center or via the command line:
20 |
21 | sudo apt-get install openjdk-8-jre
22 |
23 | ## Why is Java Required
24 |
25 | Clojure was designed as a hosted language, which means it is developed and run on top of Java's Virtual Machine (JVM). However, _its not necessary to learn the Java language to use Clojure_.
26 |
27 | Clojure is compiled into Java bytecode when you evaluate the code. This compilation happens in the background so you dont usually see it happening. For example, if you are using the Clojure REPL then each time you evaluate an expression it is compiled into Java bytecode and then injected into the running REPL and the results are then returned. This all happens pretty instantaneously.
28 |
29 | Most of the current Clojure tooling was developed for Clojure on the JVM, for example Leiningen.
30 |
31 | As Clojure runs on Java you can also use all the other libraries that run on the Java Virtual machine, regardless of whether those libraries were written in Java, Clojure, Scala, JRuby, jython, Groovy, etc.
32 |
--------------------------------------------------------------------------------
/docs/clojure-spec/projects/bank-account/test-functions-against-spec.md:
--------------------------------------------------------------------------------
1 | ## Generative testing with `check`
2 |
3 | `clojure.spec.test.alpha/check` generates 1000 values from the argument section of a function definition specification.
4 |
5 | Pass the name of the function definition that has a specification to the `check` function.
6 |
7 | ```clojure
8 | (spec-test/check ``register-account-holder`)
9 | ```
10 |
11 | ## Limiting the generated data
12 |
13 | 1000 tests can take a noticeable time to run, so check is not as often used during active development, as it would slow down the normal fast feedback cycle with Clojure.
14 |
15 | `check` takes an optional second argument which configures how the function operates. Passing a hash-map as a second argument will set the number of data values generated `{:clojure.spec.test.check/opts {:num-tests 100}}`
16 |
17 | ```clojure
18 | (spec-test/check
19 | `register-account-holder
20 | {:clojure.spec.test.check/opts {:num-tests 100}})
21 | ```
22 |
23 | Configuring `check` to run fewer tests provides a simple way to test multiple values without slowing down the development workflow.
24 |
25 | ## Reporting on Generative testing
26 |
27 | `clojure.spec.test.alpha/summarize-results` will return a brief summary including the total number of results and a count for how many results passed and failed.
28 |
29 | ```clojure
30 | (spec-test/summarize-results
31 | (spec-test/check `register-customer
32 | {:clojure.spec.test.check/opts {:num-tests 10}}))
33 | ```
34 |
35 | Use the threading macro to summarize the results of multiple check operations
36 |
37 | ```clojure
38 | (->> (spec-test/check `register-account-holder)
39 | (spec-test/check `open-current-bank-account)
40 | (spec-test/summarize-results))
41 | ```
42 |
43 | If this expression is bound to a name then it can be called when ever the full suite of `check` generative testing is required.
44 |
--------------------------------------------------------------------------------
/docs/simple-projects/index.md:
--------------------------------------------------------------------------------
1 | # Small Projects
2 |
3 | 
4 |
5 | An effective way to get comfortable with Clojure is to start writing small projects. In this section several small projects are used to walk the audience through how to create and develop a project, as well as learn some Clojure functions and functional programming techniques along the way.
6 |
7 | | Project | Topics | Description |
8 | |-------------------------------------------------------|-----------------------|----------------------------------------------------------------|
9 | | [Random Clojure Function](random-clojure-function.md) | namespace vars | print a random function from the Clojure standard library |
10 | | [Encoding and decoding](encode-decode/) | hash-map dictionaries | transforming messages between one form and another |
11 | | [Data Transformation](data-transformation/) | | transforming larger and larger data sets |
12 | | [Test Driven Development and Kata](tdd-kata/) | Unit testing | Unit testing and solving challenges using different approaches |
13 |
14 | !!! HINT "Create a Clojure project"
15 | [Clojure CLI tools and clj-new](/clojure/clojure-cli/projects/create-from-template/) to create a new Clojure project.
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/valid-q.md:
--------------------------------------------------------------------------------
1 | # Is the value valid?
2 |
3 | `clojure.spec.alpha/valid?` takes two arguments
4 |
5 | - a specification
6 | - a value to test against the specification
7 |
8 | `clojure.spec.alpha/valid?` is a predicate function.
9 |
10 | `true` is returned if the value meets the specification, otherwise `false` is returned.
11 |
12 | ## Require the Clojure spec library
13 |
14 | Set the namespace for the page and require clojure.spec.alpha library, setting the alias to `spec`
15 |
16 | ```clojure
17 | (ns practicalli.clojure.specifications
18 | (:require [clojure.spec.alpha :as spec]))
19 | ```
20 |
21 | ## Using valid?
22 |
23 | If the value is valid then a boolean true is returned. Experiment with different values and [predicate functions](/reference/clojure/predicate-functions.md).
24 |
25 | ```clojure
26 | (spec/valid? even? 180)
27 | ```
28 |
29 |
30 | ```clojure
31 | (spec/valid? string? "Am I a valid string")
32 | ```
33 |
34 |
35 | # using custom predicate functions
36 |
37 | Create `fn` definitions to use as predicate functions. Any function that returns true or false can be used.
38 |
39 | ```clojure
40 | (spec/valid? (fn [value] (> value 1024)) 8080)
41 | ```
42 |
43 | The custom predicate function may also be written in the shorter form of a `fn` definition
44 |
45 | ```clojure
46 | (spec/valid? #(> % 1024) 8080)
47 | ```
48 |
49 | Use `def` to bind names to custom predicate functions if they are used more than once in the code base.
50 |
51 | In this example a name is bound to a function that checks if a port is within the [range of IANA registered networking ports][1].
52 |
53 | ```clojure
54 | (def registered-port-range?
55 | "Network port number within IANA registered port range"
56 | #(and (> % 1024) #(< % 49151) )
57 |
58 | (spec/valid? registered-port-range? 8080)
59 | ```
60 |
61 | [1]: https://en.wikipedia.org/wiki/Port_(computer_networking)#Common_port_numbers
62 |
--------------------------------------------------------------------------------
/docs/games/tictactoe-cli/create-project.md:
--------------------------------------------------------------------------------
1 | # Create a Clojure project
2 | >
3 | > #### TODO::work in progress, sorry
4 |
5 | Create a project for our game.
6 |
7 | {% tabs deps="deps.edn projects", lein="Leiningnen projects" %}
8 |
9 | {% content "deps" %}
10 | Create a new project using `clj-new` alias, found in [:fontawesome-solid-book-open: Practicalli Clojure CLI Config]({{ book.P9IClojureDepsEdn }})
11 |
12 | ```shell
13 | clojure -M:new practicalli/tictactoe-cli
14 | ```
15 |
16 | Open the project in [a Clojure aware editor](/clojure-editors/) or run a rebel REPL
17 |
18 | ```shell
19 | clojure -M:repl/rebel
20 | ```
21 |
22 | Once the rebel REPL is running, load the project and change to the main namespace
23 |
24 | ```clojure
25 | (require 'practicalli/tictactoe-cli)
26 |
27 | (in-ns 'practicalli/tictactoe-cli)
28 | ```
29 |
30 | {% content "lein" %}
31 | The default Leiningen template is suitable fine for the project as no additional libraries are used.
32 |
33 | ```
34 | lein new tictactoe-cli
35 | ```
36 |
37 | > #### Hint::Alternatively clone the github repository
38 | >
39 | > You can also clone the tictactoe-cli game from GitHub
40 |
41 | ```shell
42 | git clone https://github.com/practicalli/tictactoe-cli.git
43 | ```
44 |
45 | ## Updating Clojure version and licence
46 |
47 | In the `project.clj` file I have updated Clojure to version 1.10.0 and changed the licence to be the more open Creative Commons license.
48 |
49 | ```clojure
50 | (defproject tictactoe-cli "0.1.0-SNAPSHOT"
51 | :description "TicTacToe game played on the command line"
52 | :url "https://github.com/practicalli/tictactoe-cli"
53 | :license {:name "Creative Commons Attribution Share-Alike 4.0 International"
54 | :url "https://creativecommons.org"}
55 | :dependencies [[org.clojure/clojure "1.10.0"]])
56 | ```
57 |
58 | I also removed the `license` file and added a brief description of the project to the `README.md` file
59 |
60 | {% endtabs %}
61 |
--------------------------------------------------------------------------------
/docs/reference/naming-conventions.md:
--------------------------------------------------------------------------------
1 | # Naming Conventions
2 |
3 | ## Kebab-case
4 |
5 | Kebab-case is the naming convention for all Clojure function names than contain more than one word. Its name comes from the Shish Kebab style of cooking, where the words are the tofu and vegetables and the dashes are the skewers.
6 |
7 | ```
8 | clj-time
9 | string-parser
10 | display-name
11 | ```
12 |
13 | ## Predicates
14 |
15 | Examples of predicate naming conventions from `clojure.core`
16 |
17 | ```
18 | contains?
19 | empty?
20 | every?
21 | not-empty?
22 | null?
23 | ```
24 |
25 | ## Namespace requires and aliases
26 |
27 | Required libraries should be given a contextually meaningful name as an alias, helping to identify the purpose of functions defined outside of the namespace.
28 |
29 | Giving meaningful context helps code to be understood by any person reading the code. It is also easier to search for usage of functions from that context in the current project.
30 |
31 | Aliases are rarely typed more than once in full as Clojure editors have auto-complete, so there is no benefit to short of single character aliases.
32 |
33 | ```clojure
34 | (ns status-monitor.handler
35 | (:require [hiccup.page :refer :as web-page]
36 | [hiccup.form :refer :as web-form]))
37 | ```
38 |
39 | In very commonly used libraries or very highly used functions through out the code, refer those functions explicitly
40 |
41 | ```clojure
42 | (ns naming.is.hard
43 | (:require [compojure.core :refer [defroutes GET POST]]
44 | [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
45 | ```
46 |
47 | ## Converting functions
48 |
49 | When a function takes values in one format or type and converts them to another
50 |
51 | Examples
52 |
53 | ```
54 | md->html
55 |
56 | map->Record-name ; map factory function of a record -- creates a new record from a map
57 | ->Record-name ; positional factory function of a record -- creates a new record from a list of values
58 | ```
59 |
--------------------------------------------------------------------------------
/docs/reference/standard-library/index.md:
--------------------------------------------------------------------------------
1 | # Clojure Standard Library
2 |
3 | Examples of using the functions from the `clojure.core` namespace and other important functions, macros and special forms that are part of the `org.clojure/clojure` library.
4 |
5 | There are approximately 700 functions and macros available in the `clojure.core` namespace. These are referred to as the Clojure Standard Library.
6 |
7 | !!! HINT "Counting functions in `clojure.core`"
8 | To get an accurate number of functions, call the `ns-publics` function with a namespace name
9 | ```clojure
10 | (count (ns-publics 'clojure.core))
11 | ```
12 | [Random Function](/clojure/simple-projects/random-clojure-function/) is a simple project that prints out a random function from the given namespace, or from clojure.core by default.
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ## Functions, Macros and Special forms
21 |
22 | The majority of times macros and special forms act just like any other defined function (i.e. `fn`, `defn`)
23 |
24 | A macro is a piece of code that evaluates into a function when read by the macro reader, or by the developer using `macroexpand` function. An expanded macro may also contain macros, so expansion could take place several levels (`macroexpand-all`).
25 |
26 | macros are not composable like functions, so functions like `apply` `reduce` `map` cannot use a macro (use a function instead).
27 |
28 | Special forms are built into the Clojure runtime, so will not be found in clojure.core
29 |
30 | - Special forms: `if` `do` `let` `quote` `var` `fn` `loop` `recur` `throw` `try`
31 | - Special forms for Java interop: `.` `new` `set!`
32 |
--------------------------------------------------------------------------------
/docs/clojure-spec/projects/index.md:
--------------------------------------------------------------------------------
1 | # Clojure Spec Projects
2 |
3 | A series of projects showing approaches to using specifications and generating data for testing.
4 |
5 | | Project | Description |
6 | |----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
7 | | [card game](card-game/) | writing specifications and generating data from those specifications |
8 | | banking-on-clojure | simplified online bank account using TDD, data and functional specifications and generative testing |
9 | | [Bonbon card game](https://github.com/katox/bonbon) | A flavorful card game with clojure spec |
10 | | [Genetic Programming With clojure.spec](http://gigasquidsoftware.com/blog/2016/07/18/genetic-programming-with-clojure-dot-spec/) | |
11 | | [ClojureScript game with spec](https://deque.blog/2017/03/14/building-a-clojurescript-game-toughts-on-spec/) | |
12 |
13 | ## References
14 |
15 | * [Practicalli - Clojure Spec playlist](https://www.youtube.com/playlist?list=PLpr9V-R8ZxiBWGAuncfBRYhZtY5-Bp75s) - live coding to define specifications and generative testing
16 |
--------------------------------------------------------------------------------
/docs/designing-data-structures/modeling-alphabet-codes.md:
--------------------------------------------------------------------------------
1 | # Model alphabet codes
2 |
3 | Maps in Clojure are used to model key and value pairs.
4 |
5 | * Keys must be unique within a map.
6 | * A key can be a number, string or keyword.
7 |
8 | Vectors in Clojure are a general data structure that are good for handing any kind of information.
9 |
10 | !!! NOTE "Name a data structure"
11 | Define a name for a data structure where each letter of the alphabet is represented by a 6 digit binary code
12 |
13 |
14 | ??? EXAMPLE "Example solution"
15 | Define a name called `alphabet` that is bound to a map. Each key in the map is a character of the alphabet and each value is a vector of numbers that represent a binary code.
16 |
17 | The map includes a binary code for a full stop and space character, to help create sentences.
18 |
19 | ```clojure
20 | (def alphabet {"A" [0 1 0 0 0 1]
21 | "B" [0 0 1 0 1 0]
22 | "C" [0 1 0 0 1 0]
23 | "D" [1 0 1 0 0 0]
24 | "E" [1 0 1 1 0 0]
25 | "F" [1 1 0 1 0 0]
26 | "G" [1 0 0 1 1 0]
27 | "H" [1 0 1 0 0 1]
28 | "I" [1 1 1 0 0 0]
29 | "J" [0 0 1 1 1 1]
30 | "K" [0 1 0 1 0 1]
31 | "L" [1 1 1 0 0 1]
32 | "M" [1 1 1 0 1 1]
33 | "N" [0 1 1 1 0 1]
34 | "O" [1 1 0 1 1 0]
35 | "P" [1 1 1 1 1 0]
36 | "Q" [1 0 1 1 1 0]
37 | "R" [1 1 1 1 0 0]
38 | "S" [0 1 1 1 1 0]
39 | "T" [1 0 0 1 1 1]
40 | "U" [0 0 1 0 1 1]
41 | "V" [0 1 1 0 0 1]
42 | "W" [1 1 0 1 0 1]
43 | "X" [1 0 1 0 1 0]
44 | "Y" [1 0 0 0 1 1]
45 | "Z" [1 1 0 0 1 1]
46 | "." [1 0 1 1 0 1]
47 | " " [0 0 1 0 0 0]})
48 | ```
49 |
--------------------------------------------------------------------------------
/docs/reference/clojure-syntax/syntax.md:
--------------------------------------------------------------------------------
1 | # Clojure syntax
2 |
3 | Clojure is perceived as having an abundance of `()`, the symbols that represent a list.
4 |
5 | As Clojure is a LISP (List Processing) language then everything is written in the form of a list. This makes Clojure very powerful and also easier to read.
6 |
7 | Using a list structure also demonstrates the data-centric nature of Clojure. Every item in the list has a value, with the first item evaluated by a function call.
8 |
9 | > #### Hint::Parens everywhere
10 | >
11 | > The seemingly abundance of `()` can be confusing until its realized there are fewer "special characters" in Clojure than other languages. Clojure aware editors support matching parens, adding a closed paren when typing an open paren, ensuring it is easy to write correctly formed Clojure.
12 | >
13 | > Syntax differences are a trivial reason to avoid trying Clojure. Syntax aware editors significantly reduce typing by automatically closing parenthesis and eliminating errors due to missing delimiters (ie. no more errors due to missing ; in C-based languages)
14 |
15 | ## Prefix notation
16 |
17 | Instead of having a mix of notations like in many other languages, Clojure uses pre-fix notation entirely.
18 |
19 | In Clojure operators are applied uniformly and there is no room for ambiguity:
20 |
21 | ```clojure
22 | (+ 1 2 3 5 8 13 21)
23 | (+ 1 2 (- 4 1) 5 (* 2 4) 13 (/ 42 2))
24 | (str "Clojure" " uses " "prefix notation")
25 | ```
26 |
27 | In Java and other C-based languages you have to explicitly add operators everywhere and there can be a mixture of notations
28 |
29 | ```java
30 | (1 + 2 + 3 + 5 + 8 + 13 + 21);
31 | (1 + 2 + (- 4 1) + 5 + (* 2 4) + 13 + (/ 42 2));
32 | StringBuffer description = new StringBuffer("C-based languages" + " mix " + "notation");
33 | x+=1;
34 | x++;
35 | x--;
36 | x+=y;
37 | x-=y;
38 | x*=y;
39 | x/=y;
40 | ```
41 |
42 | # References
43 |
44 | * [Clojure Style Guide](https://github.com/bbatsov/clojure-style-guide)
45 |
--------------------------------------------------------------------------------
/docs/development-environments/lighttable.md:
--------------------------------------------------------------------------------
1 | # LightTable
2 |
3 | LightTable is a simple development tool that supports Clojure, ClojureScript, JavaScript and Python languages. The tool is open source and written in Clojure & ClojureScript (with a little JavaScript & CSS)
4 |
5 | 
6 |
7 | # Install Lighttable
8 |
9 | Download [lighttable.com](http://lighttable.com) and follow the suggested instructions:
10 |
11 | **MacOSX**
12 | Install the `lighttable.dmg` file just as any other MacOSX package
13 |
14 | **Linux**
15 | Extract the contents of the downloaded lighttable file to a suitable directory (`/usr/local` or `~/apps`). Add `LightTable` to the system `$PATH`, or add the following script to the system `$PATH`.
16 |
17 |
18 |
19 | **Windows**
20 | Download the windows zip file for LightTable and extract the installer, following the instructions inside the installer.
21 |
22 | ## LightTable configuration
23 |
24 | Lighttable configuration is in the file `user.behaviours`. Open the user behaviours file, `Ctrl-space` and type `user behaviors`. When you save the file, `Ctrl-s`, changes are applied immediately.
25 |
26 | **Sample User Behaviours file**
27 |
28 | Here is a sample of user behaviours file for LightTable
29 |
30 |
31 |
32 | ## Using LightTable
33 |
34 | LightTable has an online tutorial entitled [Getting started with LightTable](http://docs.lighttable.com/tutorials/full/)
35 |
36 | I create a project first with Leiningen, open the project directory in the LightTable workspace and open any files I want to work with. I then connect the open editor window for the file by pressing `Ctrl-Enter` at the end of an expression.
37 |
38 | > **Hint** my approach is documented in the [quick demo section of my Clojure & LightTable slides](http://jr0cket.co.uk/slides/jax-london-2013-light-table.html#/sec-12) from JAXLondon 2013.
39 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/immutable-collections.md:
--------------------------------------------------------------------------------
1 | # Immutable collections
2 |
3 | As we have discussed, immutable data structures cannot be changed. So when you run a function over a collection a copy of that collection is returned. Lets see this by running some code in the REPL.
4 |
5 | > **Note** Define a data structure called `numbers` using a vector. Then write a function that uses the `map` and `inc` function to increment all the numbers in a vector.
6 |
7 | > Then check the current value of the `numbers` data structure by evaluating its name.
8 |
9 |
10 | ```clojure
11 | ;; define the data structure
12 | (defn numbers [1 2 3 4 5])
13 |
14 | ;; increment the numbers
15 | (map inc numbers)
16 |
17 | ;; see the current value of numbers
18 | numbers
19 | ```
20 |
21 |
22 |
23 | > **Note** Use the `conj` function to first add the number `5` to the `numbers` vector from the previous exercise and check the value of `numbers`. Then add the number `6` to the `numbers` vector and check the value of `numbers`.
24 |
25 | > Finally, use the `conj` function to add both `5` and `6` to the `numbers` vector and check the value of `numbers`
26 |
27 |
28 |
29 | ```
30 | (def numbers [1 2 3 4])
31 |
32 | ;; add 5 to the numbers vector
33 | (conj numbers 5)
34 |
35 | ;; check the value of numbers
36 | numbers
37 | ;; => [1 2 3 4]
38 |
39 | ;; add 6 to the numbers vector
40 | (conj numbers 6)
41 |
42 | ;; check the value of numbers
43 | numbers
44 | ;; => [1 2 3 4]
45 |
46 | ;; add 5 and 6 to the numbers vector
47 | (conj numbers 5 6)
48 |
49 | ;; Alternatively, you can use the threading macro to chain two conj function calls
50 | (-> numbers
51 | (conj 5)
52 | (conj 6))
53 |
54 | ;; check the value of numbers
55 | numbers
56 | ;; => [1 2 3 4]
57 | ```
58 |
59 | So even though we have applied several functions on the `numbers` data structure it still has the same value.
60 |
61 |
62 |
--------------------------------------------------------------------------------
/docs/reference/doc-and-source-functions.md:
--------------------------------------------------------------------------------
1 | ## The doc & source functions
2 |
3 | If you are not using a Clojure aware editor or spend a lot of time in the REPL you can also view the documentation of a function by calling the `doc` function and see the source by calling the `source` function.
4 |
5 | To use the `doc` & `source` functions in the REPL you should be in the `user` namespace.
6 |
7 | > **Note** On the command line, start a REPL with the command `lein repl` and then view the documentation for three common functions used in clojure
8 |
9 | Make sure you are in the `user` namespace before calling the `doc` function. If you are in another namespace, either change back using `(ns 'user)` or see the next section on using these functions in another namespace.
10 |
11 | ```clojure
12 | (doc doc)
13 | (doc map)
14 | (doc filter)
15 | (doc cons)
16 |
17 | (source doc)
18 | (source map)
19 | ```
20 |
21 | Here is the doc string for `doc`
22 |
23 | 
24 |
25 | Here is the source code for the `source` function
26 |
27 | 
28 |
29 | > **Hint** As the documentation for a function is part of its definition, by looking at the source of a function you also get the documentation.
30 |
31 | ## Using doc & source function from another namespace
32 |
33 | The `doc` and `source` functions are only included in the `user` namespace. If you switch to another namespace or your editor places you in the current namespace of your project, these functions will not be available unless you including `core.repl` in the current namespace.
34 |
35 | From the REPL, evaluate the expression:
36 |
37 | ```
38 | (use 'clojure.repl)
39 | ```
40 |
41 | You could also `require` the `clojure.repl` library in your own code, however if you have a good editor it should provide these features without including this library. Therefore the following code is shown only as an example and not a recommended approach.
42 |
43 | ```
44 | (ns foobar
45 | (:require [clojure.repl :refer :all]))
46 | ```
47 |
--------------------------------------------------------------------------------
/.github/workflows/scheduled-stale-check.yaml:
--------------------------------------------------------------------------------
1 | # ----------------------------------------
2 | # Scheduled stale issue & pull request check
3 | #
4 | # Adds 'stale' label after a set piece of time,
5 | # then closes stale issues & pull requests a short period after
6 | #
7 | # Using "Close Stale Issues" action
8 | # https://github.com/marketplace/actions/close-stale-issues
9 | # ----------------------------------------
10 |
11 | name: 'Scheduled stale check'
12 | on:
13 | workflow_dispatch:
14 | schedule:
15 | - cron: "0 1 1 * *" # at 01:00 on first day of month
16 |
17 | jobs:
18 | stale:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}"
22 | - run: echo "🐧 Job running on ${{ runner.os }} server"
23 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository"
24 |
25 | - uses: actions/stale@v10
26 | with:
27 | stale-issue-message: 'After 30 days with no activity, the issue was automatically marked stale. Remove stale label or add a comment to prevent the issue being closed in 5 days.'
28 | stale-pr-message: 'After 45 days with no activity, the Pull Request was automatically marked stale. Remove stale label or comment to prevent the PR being closed in 10 days.'
29 | close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
30 | close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.'
31 | days-before-issue-stale: 30
32 | days-before-pr-stale: 45
33 | days-before-issue-close: 5
34 | days-before-pr-close: 10
35 | start-date: '2025-04-05T00:00:00Z' # only affect issues/PRs from date created (ISO 8601 or RFC 2822 format)
36 | any-of-labels: 'future,keep' # labels to keep
37 | exempt-issue-assignees: 'practicalli-johnny'
38 | exempt-pr-assignees: 'practicalli-johnny'
39 |
40 | # Summary
41 | - run: echo "🎨 Issues & Pull Request checked with actions/stale"
42 | - run: echo "🍏 Job status is ${{ job.status }}."
43 |
--------------------------------------------------------------------------------
/docs/reference/clojure-svg/index.md:
--------------------------------------------------------------------------------
1 | # Clojure Scalable Vector Graphics - SVG
2 |
3 | Scalable Vector Graphics, SVG, is an image format for two-dimensional (2D) graphics.
4 |
5 | An SVG image uses data to describe how to draw an image, ensuring that images can shrink and scale easily and retain a high quality image. As images are formed from data, shapes can easily be combined or intersected to form new shapes. Using a data format also means SVG images can be created from code and therefore animated.
6 |
7 | Raster image formats like gif, jpeg and png use a grid of squares called pixels to define an image (also known as a bitmap). Each pixel has a colour and position in an image. When zooming into an image the pixels grow larger distorting the sharpness of an image, referred to as [pixelation](https://en.wikipedia.org/wiki/Pixelation), .Multiple versions of raster images are often created at different resolutions to reduce the loss of quality when viewed at different sizes.
8 |
9 | > #### Hint::Work in progress
10 |
11 | ## Concepts
12 |
13 | - viewbox
14 | - style - border, background, width, height, stoke, fill, draw (path)
15 | - shapes - circle, path
16 |
17 | ## Viewbox
18 |
19 | A [viewbox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) defines a co-ordinate system for the image. Defining a size for the viewbox defining a frame for the image where positions are relative to that frame, irrespective of the size of the image or how that image is scaled.
20 |
21 | A viewbox size should be selected to make the image as simple as possible to define within itself.
22 |
23 | Example: [tictactoe O's and X's and the grid that represents the board](https://practicalli.github.io/clojurescript/reagent-projects/tic-tac-toe/index.html).
24 |
25 | tictactoe O's and X's and the grid that represents the board
26 |
27 | ## Related projects
28 |
29 | - TicTacToe with ClojureScript, Reagent and SVG
30 | - System monitoring
31 | - Practicalli SVG examples library
32 | - Programming SVG with Clojure (TODO)
33 |
34 | ## References
35 |
36 | - [SVG: Scalable Vector Graphics - Mozilla Developer network](https://developer.mozilla.org/en-US/docs/Web/SVG)
37 |
--------------------------------------------------------------------------------
/docs/clojure-spec/projects/bank-account/write-failing-tests.md:
--------------------------------------------------------------------------------
1 | # Write failing tests
2 |
3 | In Test Driven Development style, first write unit tests for the banking functions.
4 |
5 | Edit the `src/practicalli/banking_on_clojure_test.clj` and add `deftest` tests
6 |
7 | ```clojure
8 | (deftest register-account-holder-test
9 | (testing "Basic registration - happy path"
10 | (is (= (set (keys (register-account-holder {})))
11 | (set (keys {:account-id "123" :customer-name "Jenny Jetpack"}))))))
12 | ```
13 |
14 | ## Write a function stub to run the tests
15 |
16 | The tests cannot run unless they call the function to be tested. A common approach it to write a function that returns the argument.
17 |
18 | ```clojure
19 | (defn register-account-holder
20 | "Register a new customer with the bank
21 | Arguments:
22 | - hash-map of customer-details
23 | Return:
24 | - hash-map of an account-holder (adds account id)"
25 |
26 | [customer-details]
27 |
28 | customer-details)
29 | ```
30 |
31 | ## Add mock data
32 |
33 | Define some initial mock data to use with the unit tests
34 |
35 | ```clojure
36 | (def customer-mock
37 | {:first-name "Jenny"
38 | :last-name "Jetpack"
39 | :email-address "jenny@jetpack.org"
40 | :residential-address "42 meaning of life street, Earth"
41 | :postal-code "AB3 0EF"
42 | :social-security-id "123456789"})
43 | ```
44 |
45 | ```clojure
46 | account is a customer with a bank account id added
47 |
48 | (def account-holder-mock
49 | {:account-id #uuid "97bda55b-6175-4c39-9e04-7c0205c709dc"
50 | :first-name "Jenny"
51 | :last-name "Jetpack"
52 | :email-address "jenny@jetpack.org"
53 | :residential-address "42 meaning of life street, Earth"
54 | :postal-code "AB3 0EF"
55 | :social-security-id "123456789"})
56 | ```
57 |
58 | Update the test to use the mock data.
59 |
60 | ```clojure
61 | (deftest register-account-holder-test
62 | (testing "Basic registration - happy path"
63 | (is (= (set (keys (register-account-holder customer-mock)))
64 | (set (keys account-holder-mock))))))
65 | ```
66 |
--------------------------------------------------------------------------------
/docs/core.async/toy-car-assembly-line/index.md:
--------------------------------------------------------------------------------
1 | # core.async example - toy car assembly line
2 |
3 | >####Note::Get the example project and open it in a Clojure REPL
4 | > Clone or download the [Lispcast: Clojure core-async Factory example](https://github.com/ericnormand/lispcast-clojure-core-async)
5 | >
6 | > Open that project in your Clojure editor or run `lein repl` in the top level directory of the project.
7 |
8 | ## The toy car factory
9 |
10 | The toy car factory assembles car parts before distributing them. How can we make this process faster and more scalable?
11 |
12 | ## The current process
13 |
14 | One worker picks out random parts of a car from the parts box until all the parts are collected to assemble the car.
15 |
16 | ## The `time` macro
17 |
18 | We will use the time macro to see how long parts of our code takes to run and help find parts to optimise.
19 |
20 | A simple example would be:
21 |
22 | ```clojure
23 | (time
24 | (map inc (range 0 10000)))
25 | ```
26 |
27 | ## Timing assembly functions
28 |
29 | Investigate the time it takes to carry out the different assembly line tasks
30 |
31 | ```clojure
32 | (time (take-part))
33 |
34 | (time (attach-wheel :body :wheel))
35 |
36 | (time (box-up :body))
37 |
38 | (time (put-in-truck :body))
39 | ```
40 |
41 | And to total time it takes to get a a whole car through the assembly line
42 |
43 | ```clojure
44 | (time (build-car))
45 | ```
46 |
47 | The total time can be longer than the sum of the tasks, as the `take-part` function does not always give the required part needed.
48 |
49 | ## Hiring more workers
50 |
51 | Adding 10 more workers is equivalent to adding 10 processes that run the assembly tasks.
52 |
53 | Lets use a go block for a worker
54 |
55 | ```clojure
56 | (do
57 | (go
58 | (dotimes [number 10]
59 | (println "First go block processing:" number)
60 | (Thread/sleep 1200)))
61 | (go
62 | (dotimes [number 10]
63 | (println "Second go block processing:" number)
64 | (Thread/sleep 1200))))
65 | ```
66 |
67 | These are two separate go blocks, so their is no co-ordination between the two. You can see the println statement from each go block intertwined.
68 |
--------------------------------------------------------------------------------
/docs/simple-projects/split-the-bill.md:
--------------------------------------------------------------------------------
1 | # Split the bill
2 |
3 |
4 |
5 | In a restaurant a group of friends and relatives are having a reunion dinner after a year of not seeing each other.
6 |
7 | Once the meal comes to an end, its time to pay the bill. So how would you write code to split the bill?
8 |
9 | Start with the simplest possible approach, with everyone paying the same.
10 |
11 | ## Create a new Clojure project
12 |
13 | [:fontawesome-solid-book-open: Pracitcalli Clojure CLI Config](/clojure/clojure-cli/practicalli-config/) provides the `:project/create` alias to create projects using deps-new project.
14 |
15 | ```shell
16 | clojure -T:project/create :template app :name practicalli/split-the-bill
17 | ```
18 |
19 | ```clojure
20 | (str "Create code to calculate the bill, including what each person should pay")
21 | ```
22 |
23 | Tke a look at the [Who am I](/community-docs/docs/curriculum/who-am-i) section for ideas on how to model the bill. Also look at [More Than Average](/community-docs/docs/curriculum/more-than-average) for ideas on how to write code to work out how to pay the bill.
24 |
25 | ### Paying what was ordered
26 |
27 | As not everyone had eaten the same amount of food or arrived at the same time, then there was an ask for everyone to pay just what they ordered.
28 |
29 | So create a collection to capture what each person ordered and create an itemised bill so each person knows what they should pay.
30 |
31 | Define a detailed bill based on what each person ordered, then create an itemised bill based on each persons order
32 |
33 | Now it was realised that what everyone ordered is not what everyone ate. So now we need to take the order and create an itemised bill based on what everyone actually ate (lets suspend believe here a little and assume everyone knows exactly what they ate, and is honest about it).
34 |
35 | Define a detailed bill based on what each person ordered, then create an itemised bill based on each person actually ate
36 |
37 | ## Spliting the bill with a Social Group
38 |
39 | Extend the exercise by splitting bills over multiple events and activities with multiple people.
40 |
--------------------------------------------------------------------------------
/docs/iterate-over-data/index.md:
--------------------------------------------------------------------------------
1 | # Iterate over data
2 |
3 | > #### TODO::work in progress, sorry
4 |
5 | Clojure data is typically within one or more of the built in collection types (vector, map, list, set).
6 |
7 | We can use some functions in Clojure core directly on these collection types. Other clojure core functions need a little help.
8 |
9 | ## map
10 |
11 | Used to create a new collection by applying a given function to each element of the collection in turn.
12 |
13 | ```clojure
14 | (map inc [1 2 3])
15 | ```
16 |
17 | If there are multiple collections, map returns a new collection with values created by calling the function with a value from each of the collections. Once map reaches the end of one collection it stops and returns the result.
18 |
19 | ```clojure
20 | (map + [1 2 3] [4 5 6] [7 8 9])
21 | ```
22 |
23 | ## apply
24 |
25 | Used to remove all the values from a collection so they are treated as individual arguments to the function given to apply.
26 |
27 | ```clojure
28 | (= (apply + [1 2 3])
29 | (+ 1 2 3))
30 | ```
31 |
32 | ## reduce
33 |
34 | reduce can be used in a similar way as apply, to transform a collection into a different value.
35 |
36 | reduce can also take an argument referred to as an accumulator, used to keep local state as reduce iterates through the values in the collection.
37 |
38 | A function used with reduce is called a reducing function and is a more abstract approach to loop/recur although its possible to give your reducing function a name so is more reusable.
39 |
40 | ## threading macros
41 |
42 | Write code that reads as a sequential series of function calls, rather that the nested function calls typical in lisp.
43 |
44 | A threading macro is often used to thread a collection through a number of function calls and expressions.
45 |
46 | ## comp
47 |
48 | Compose functions together that work over a collection. It can be seen as a more abstract approach to a threading macro or nested function calls.
49 |
50 | ## transduce
51 |
52 | Used like comp to create a pipeline of function calls, however, each function call or expression must return a transducer (transforming reduction). Many `clojure.core` functions return a transducer if you do not provide the collection argument.
53 |
--------------------------------------------------------------------------------
/docs/introduction/concepts/naming-things.md:
--------------------------------------------------------------------------------
1 | # Naming things - data structures and functions
2 |
3 | The `def` function is used to name data structures in Clojure.
4 |
5 | You can also use `def` to name functions, however it is more common to use `defn` (which is a macro around def) to give a function a name.
6 |
7 | ## Keeping things private
8 |
9 | There is less emphasis on keeping functions and data structures private (compared to Java, C++, C#). If you want to define a function name so that it is only accessible by other functions of the same namespace, you can use the `defn-` function.
10 |
11 | There is no private equivalent for `def` (as of Clojure 1.6) however you can use metadata to specify this
12 |
13 | (def ^:private name data)
14 |
15 | > TODO: check if there is anything new around this or other common practices
16 |
17 | ## Misc - writing a private def macro
18 |
19 | You could write your own macro to create a private `def` called `def-`
20 |
21 | ```clojure
22 | (defmacro def- [item value]
23 | `(def ^{:private true} ~item ~value)
24 | )
25 | ```
26 |
27 | > There are no naming conventions for a private symbol name. As its defined an used within the scope of that one namespace (file), then there is no real need to make a special convention. Private functions will just be called as normal within the namespace and it will be quite clear from the function definition that it is private.
28 |
29 | [Clojure community style guide](https://github.com/bbatsov/clojure-style-guide)
30 |
31 | ## example
32 |
33 | Learning Clojure #4: private functions
34 |
35 |
36 | Sometimes in a Clojure file you just want some helper functions that shouldn’t be exposed outside the namespace. You can create a private function using the special defn- macro instead of defn.
37 |
38 | For instance, create a file foo/bar.clj with a public and a private function:
39 |
40 | (ns foo.bar)
41 | (defn- sq [x] (* x x))
42 | (defn sum-squares [a b] (+ (sq a) (sq b)))
43 |
44 | Then use it from the REPL:
45 |
46 | user=> (use 'foo.bar)
47 | nil
48 | user=> (sum-squares 3 4)
49 | 25
50 | user=> (sq 5)
51 | java.lang.Exception: Unable to resolve symbol: sq in this context (NO_SOURCE_FILE:6)
52 |
--------------------------------------------------------------------------------
/docs/clojure-spec/projects/bank-account/index.md:
--------------------------------------------------------------------------------
1 | # Spec project: Bank Account
2 |
3 | A relatively simple bank account application with data and function specifications, including generative testing data and function instrumentation.
4 |
5 | > #### Hint::Under active development
6 | >
7 | > Developed as part of the [Practicalli study guide live broadcasts](https://www.youtube.com/playlist?list=PLpr9V-R8ZxiBWGAuncfBRYhZtY5-Bp75s)
8 |
9 | ## Create deps.edn project
10 |
11 | Use Clojure CLI and `clj-new`
12 |
13 | ```shell
14 | clojure -M:new app practicalli/banking-on-clojure
15 | ```
16 |
17 | > #### Hint::practicalli/banking-on-clojure repository
18 | >
19 | > [practicalli/banking-on-clojure repository](https://github.com/practicalli/banking-on-clojure-spec) contains the latest code to date for this project.
20 |
21 | ## Outline design of project
22 |
23 | Data Specifications are created for
24 |
25 | * Customer Details ✔
26 | * Account holder ✔
27 | * Bank account
28 | * Multiple Bank accounts
29 | * Credit Card
30 | * Mortgage
31 |
32 | Functions and specifications are created for
33 |
34 | * register-account-holder ✔
35 | * open-credit-account
36 | * open-savings-account
37 | * open-credit-card-account
38 | * open-mortgage-account
39 | * Make a payment
40 | * Send account notification
41 | * Check for overdraft
42 |
43 | ## Development Workflow
44 |
45 | * Write a failing test ✔
46 | * write mock data ✔
47 | * write an function definition that returns the argument ✔
48 | * run tests - tests should fail ✔
49 | * write a spec for the functions argument - customer ✔
50 | * write a spec for the return value ✔
51 | * write a spec for relationship between args and return value
52 | * replace the mock data with generated values from specification ✔
53 | * update functions and make tests pass ✔
54 | * instrument functions
55 | * run specification checks
56 |
57 | ✔
58 |
59 | Images to add
60 |
61 | Running tests that fail on a spec in CIDER
62 | spacemacs-cider-test-spec-fail-banking-on-clojure-project.png
63 |
64 | Running tests that fail on a spec on CircleCI
65 | circle-ci-banking-on-clojure-spec-test-runner-fail-register-account-holder-did-not-conform-to-spec.png
66 |
--------------------------------------------------------------------------------
/docs/reference/jvm/experimental-options.md:
--------------------------------------------------------------------------------
1 | # Reference: JVM Experimental Options
2 |
3 |
4 |
5 | The HotSpot JVM provides the opportunity to try features that may appear in future release, although are currently not production-ready.
6 |
7 | HotSpot JVM experimental features need to be unlocked by specifying the `-XX:+UnlockExperimentalVMOptions` option.
8 |
9 | For example, the ZGC garbage collector in JDK 11 can be accessed using
10 |
11 | ```shell
12 | java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC
13 | ```
14 |
15 | > The ZGC collector became a product option in JDK 15, so is no longer experimental.
16 |
17 | ## Manageable
18 |
19 |
20 |
21 | Show locks held by `java.util.concurrent` classes in a HotSpot JVM thread dump:
22 |
23 | ```shell
24 | java -XX:+UnlockExperimentalVMOptions -XX:+PrintConcurrentLocks
25 | ```
26 |
27 | > These options can be set at runtime via the MXBean API or related JDK tools
28 |
29 | ## Diagnostic
30 |
31 | Accessing advanced diagnostic information about the HotSpot JVM.
32 |
33 | These options require you to use the `-XX:+UnlockDiagnosticVMOptions` option before they can be used.
34 |
35 | View advance compilation optimisations using the `-XX:+LogCompilation` option:
36 |
37 | ```shell
38 | java -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation
39 | ```
40 |
41 | The HotSpot JVM outputs a log file containing details of all the optimisations made by the JIT compilers. Inspect the output to understand which parts of your program were optimized and to identify parts of the program that might not have been optimized as expected.
42 |
43 | The LogCompilation output is verbose but can be visualized in a tool such as JITWatch, which can tell you about method inlining, escape analysis, lock elision, and other optimizations that the HotSpot JVM made to your running code.
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/docs/data-structures/pretty-printing.md:
--------------------------------------------------------------------------------
1 | # Pretty Printing data structures
2 |
3 | Data structures containing small amounts of data are quite human readable, although can benefit from pretty printing to make them very easy for humans to read.
4 |
5 | The larger a data structure becomes, or if a data structure is nested, then there are tools to print out ascii views of the data structures.
6 |
7 | ## Pretty print hash-maps
8 |
9 | ```clojure
10 | (clojure.pprint/pprint
11 | {:account-id 232443344 :account-name "Jenny Jetpack" :balance 9999 :last-update "2021-12-12" :credit-score :aa} )
12 | ```
13 |
14 | Each key is printed on a new line, making the hash-map easier to read, especially when there are a large number of keys
15 |
16 | ```clojure
17 | {:account-id 232443344,
18 | :account-name "Jenny Jetpack",
19 | :balance 9999,
20 | :last-update "2021-12-12",
21 | :credit-score :aa}
22 | ```
23 |
24 | Clojure aware editors can also have an align option when formatting hash-maps, making the results easier to read
25 |
26 | ```clojure
27 | {:account-id 232443344,
28 | :account-name "Jenny Jetpack",
29 | :balance 9999,
30 | :last-update "2021-12-12",
31 | :credit-score :aa}
32 | ```
33 |
34 | > #### Hint::Pretty Print evaluation results
35 | >
36 | > Clojure aware editors should allow the pretty printing of the evaluation results.
37 |
38 | ## Print Table of nested data structures
39 |
40 | Nested data structures can also be shown as a table, especially the common approach of using a vector of hash-maps where each map has the same keys
41 |
42 | ```clojure
43 | (clojure.pprint/print-table
44 | [{:location "Scotland" :total-cases 42826 :total-mortality 9202}
45 | {:location "Wales" :total-cases 50876 :total-mortality 1202}
46 | {:location "England" :total-cases 5440876 :total-mortality 200202}])
47 | ```
48 |
49 | ```none
50 | | :location | :total-cases | :total-mortality |
51 | |-----------+--------------+------------------|
52 | | Scotland | 42826 | 9202 |
53 | | Wales | 50876 | 1202 |
54 | | England | 5440876 | 200202 |
55 | ```
56 |
57 | ## References
58 |
59 | [Data browsers](/clojure-cli/data-browsers/) (Cider Inspector, Portal, Reveal Free) are very useful for larger and nested data structures.
60 |
--------------------------------------------------------------------------------
/docs/using-data-structures/mapping-data-structures.md:
--------------------------------------------------------------------------------
1 | # Mapping functions over data structures
2 |
3 | Map allows you to work over one or more data sets, applying the function to each element of each of the data structures.
4 |
5 | When the data structures are of equal size, then the same sized data structure is returned.
6 |
7 | ```clojure
8 | (map + [1 2 3] [1 2 3])
9 | ;; => (2 4 6)
10 | ```
11 |
12 | If one data structure is smaller, then the function is only applied up to the last element of the smallest data structure.
13 |
14 | ```clojure
15 | (map + [1 2 3] [1 2])
16 | ;; => (2 4)
17 |
18 | (map + [1 2 3] [1])
19 | ;; => (2)
20 |
21 | (map + [1 2 3] [])
22 | ;; => ()
23 |
24 | (map + [1 2 3])
25 | ;; => (1 2 3)
26 | ```
27 |
28 | Lets look at another example. Here we have a pre-defined Fibonacci sequence up to the first 12 values.
29 |
30 | ```clojure
31 | (def fibonacci-sequence [1 2 3 5 8 13 21 34 55 89 144 278])
32 | ```
33 |
34 | If we just want the first 10 values of the sequence, we can use the `take` function.
35 |
36 | ```clojure
37 | (take 10 fibonacci-sequence)
38 | ;; => (1 2 3 5 8 13 21 34 55 89)
39 | ```
40 |
41 | If we want a calculation using the values of the fibonacci-sequence then we can use `map` with a function. In this case we are going to generate a range of Integer numbers from 0-9 using the function `range`. That range of numbers is then multiplied element by element with the corresponding element in the fibonacci-sequence.
42 |
43 | ```clojure
44 | (map * (range 10) fibonacci-sequence)
45 | ;; => (0 2 6 15 32 65 126 238 440 801)
46 | ```
47 |
48 | So,
49 |
50 | - 0 times 1 is 0,
51 | - 1, times 2 is 2,
52 | - 2 times 3 is 6, etc.
53 |
54 | If we evaluate the previous expression part by part, its easier to see what is going on. First lets evaluate the `fibonacci-sequence`
55 |
56 | ```clojure
57 | (map * (range 10) [1 2 3 5 8 13 21 34 55 89 144 278])
58 | ;; => (0 2 6 15 32 65 126 238 440 801)
59 | ```
60 |
61 | Now lets evaluate the `(range 10)` function call
62 |
63 | ```clojure
64 | (map * (0 1 2 3 4 5 6 7 8 9) [1 2 3 5 8 13 21 34 55 89 144 278])
65 | ;; => (0 2 6 15 32 65 126 238 440 801)
66 | ```
67 |
68 | We can see the answer is the same, however by evaluating each part of the expression we get an exact view of what is going to happen with the `map` function.
69 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/index.md:
--------------------------------------------------------------------------------
1 | # Clojure Spec for data
2 |
3 | Specifications can be defined for any data in Clojure, be that simple values or complex data structures. More complex specifications are composed of individual specifications, providing a flexible way to define specifications without building a brittle hierarchy.
4 |
5 | ## What is a specification
6 |
7 | Specifications can be [predicates](predicate-functions.md) (return true or false), [literal values](literal-values.md) in sets and [entity maps](entity-maps.md).
8 |
9 | There are many [predicate functions that come with Clojure](/reference/standard-library/predicate-functions.md) which help speed the creation of specifications. Clojure function definitions (`fn`, `defn`) can be used to define custom predicate functions too.
10 |
11 | ## Do values meet a specification
12 |
13 | The functions use to compare data with a specification are:
14 |
15 | * `conform` - test if data conforms to a specification, returning the conformed value
16 | * `valid?` - predicate to test if data conforms to a specification, returning true of false
17 | * `explain` - explain why a value is not conforming to a specification
18 |
19 | There are variations on explain, that present the results in different formats.
20 |
21 | ## Workflow for data specifications
22 |
23 | Using Clojure Specification is very flexible, they can be used as much or as little as required.
24 |
25 | Typically Specifications are created when data structures are being modeled, which can be done via experimenting in the REPL or taking a test first approach. Either way is viable.
26 |
27 | The generative tests section shows how specifications are used to generate mock data, so creating specifications earlier on in the development process will provide a wider range of data for unit tests and repl experimentation.
28 |
29 |
30 | !!! HINT "Spec and nil values"
31 | Some predicates do not consider `nil` as a valid value, espcially those predicates that check for a specific type
32 |
33 | `spec/nilable` will transform a predicate to use nil
34 |
35 | ```clojure
36 | (spec/valid? string? nil)
37 |
38 | (type "what type am I")
39 | (type nil)
40 |
41 | (spec/valid? (spec/nilable string?) nil)
42 | ```
43 |
44 |
47 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/pure-functions.md:
--------------------------------------------------------------------------------
1 | # Pure functions
2 |
3 | A function is considered pure if does not side effects or is affected by side causes. A pure function does not change any other part of the system and is not affected by any other part of the system.
4 |
5 | When you pass arguments to a function and that function returns a value without interacting with any other part of the system, then that function is considered pure.
6 |
7 | Should something from outside a function be allowed to affect the result of evaluating a function, or if that function be allowed to affect the outside world, then its an impure function.
8 |
9 | 
10 |
11 | So lets look at a simple code example
12 |
13 | > ####Note::Write a pure function that adds two numbers together ?
14 |
15 | ```clojure
16 | (defn add-numbers [number1 number2]
17 | (+ number1 number2))
18 |
19 | (add-numbers 1 2)
20 | ```
21 |
22 | Lets look at each line of this suggested answer
23 |
24 | ```clojure
25 | ;; function takes 2 arguments
26 | ;; function uses both arguments for result
27 | (defn add-numbers [number1 number2]
28 | (+ number1 number2))
29 |
30 | ;; specific values are passed as arguments
31 | (add-numbers 1 2)
32 | ```
33 |
34 | # An example with map
35 |
36 | > **Note** Define a collection called numbers and write a named function that increments each number of the numbers collection.
37 | > Is your function pure or impure ?
38 |
39 | ```clojure
40 | (def numbers '(5 4 3 2 1))
41 |
42 | (defn increment-numbers []
43 | (map inc numbers))
44 |
45 | (increment-numbers)
46 | ```
47 |
48 | The function takes no arguments and is pulling in a value from outside the function. This is a trivial example, but if all your code is like this it would be more complex. If the value pointed to by `numbers` is mutable and changes before the `increment-numbers` function is called then you will get different results.
49 |
50 | Here is a Pure function example
51 |
52 | ```clojure
53 | (def numbers '(5 4 3 2 1))
54 |
55 | (defn increment-numbers [number-collection]
56 | (map inc number-collection))
57 |
58 | (increment-numbers numbers)
59 | ```
60 |
61 | In this example we are explicitly passing the `numbers` collection to the function. The function works on passed value and returns a predictable result.
62 |
--------------------------------------------------------------------------------
/docs/thinking-functionally/recursion.md:
--------------------------------------------------------------------------------
1 | # Recursion
2 |
3 | > **Fixme** work in progress
4 |
5 | Recursion is used greatly in Clojure to iterate through data and as anything can be treated as data in Clojure you can understand why.
6 |
7 | The constructs available in Clojure for recursion include
8 |
9 | * `loop` and `recur`
10 | * Named function that calls itself
11 | * `map`, `reduce`, `filter`, `remove`, etc.
12 | * `for`
13 |
14 | # Recursively calling the same function
15 |
16 | Lets iterate though a collection using recursion by writing a function that calls itself
17 |
18 | ```clojure
19 | (defn recursively-use-a-collection [collection]
20 | (println (first collection))
21 | (if (empty? collection)
22 | (print-str "no more values to process")
23 | (recursively-use-a-collection (rest collection))))
24 |
25 | (recursively-use-a-collection [1 2 3])
26 | ```
27 |
28 | Lets take this recursive approach to create a function that can tell us the length of a collection (list or vector)
29 |
30 | We define a function that takes a collection of an argument. The collection is tested to see if it is empty and if so a zero value is returned. If the collection is not empty, then we
31 |
32 | ```clojure
33 | (defn length [collection]
34 | (if (empty? collection)
35 | 0
36 | (+ 1 (length (rest collection)))))
37 | ;; => #'clojure-through-code.01-basics/length
38 | ```
39 |
40 | If we call the `length` function with an empty collection, then the `empty?` condition will return true and the `if` expression will evaluate the first expression, 0, returning 0.
41 |
42 | ```clojure
43 | (length [])
44 | ;; => 0
45 |
46 | ```
47 |
48 | If we call the `length` function with a collection containing 3 values, then the `empty?` function will return `false` and the `if` function will evaluate the second expression.
49 |
50 | The second expression starts with a simple counter, using the `+` function and the value one
51 |
52 | ```clojure
53 | (length [0 1 2])
54 | ;; => 3
55 |
56 | ```
57 |
58 | ```clojure
59 | (+ 1 (length [1 2]))
60 | (+ 1 (+ 1 (length [2])))
61 | (+ 1 (+ 1 (+ 1 (length []))))
62 | (+ 1 (+ 1 (+ 1 0)))
63 |
64 | (length (range 24))
65 | ;; => 24
66 |
67 | ```
68 |
69 | (defn length [collection]
70 | (kk))
71 |
72 | # Further recursion examples
73 |
74 | Other functions to consider
75 |
76 | * every
77 | * accumulating / accumulative
78 | * keep
79 |
--------------------------------------------------------------------------------
/.github/workflows/megalinter.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # MegaLinter GitHub Action configuration file
3 | # More info at https://megalinter.io
4 | # All variables described in https://megalinter.io/latest/configuration/
5 |
6 | name: MegaLinter
7 | on:
8 | workflow_dispatch:
9 | pull_request:
10 | branches: [main]
11 | push:
12 | branches: [main]
13 |
14 | # Run Linters in parallel
15 | # Cancel running job if new job is triggered
16 | concurrency:
17 | group: "${{ github.ref }}-${{ github.workflow }}"
18 | cancel-in-progress: true
19 |
20 | jobs:
21 | megalinter:
22 | name: MegaLinter
23 | runs-on: ubuntu-latest
24 | steps:
25 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}"
26 | - run: echo "🐧 Job running on ${{ runner.os }} server"
27 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository"
28 |
29 | # Git Checkout
30 | - name: Checkout Code
31 | uses: actions/checkout@v5
32 | with:
33 | fetch-depth: 0
34 | sparse-checkout: |
35 | docs
36 | overrides
37 | .github
38 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner."
39 |
40 | # MegaLinter Configuration
41 | - name: MegaLinter Run
42 | id: ml
43 | ## latest release of major version
44 | uses: oxsecurity/megalinter/flavors/documentation@v9
45 | env:
46 | # ADD CUSTOM ENV VARIABLES OR DEFINE IN MEGALINTER_CONFIG file
47 | MEGALINTER_CONFIG: .github/config/megalinter.yaml
48 |
49 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # report individual linter status
50 | # Validate all source when push on main, else just the git diff with live.
51 | VALIDATE_ALL_CODEBASE: >-
52 | ${{ github.event_name == 'push' && github.ref == 'refs/heads/main'}}
53 |
54 | # Upload MegaLinter artifacts
55 | - name: Archive production artifacts
56 | if: ${{ success() }} || ${{ failure() }}
57 | uses: actions/upload-artifact@v4
58 | with:
59 | name: MegaLinter reports
60 | path: |
61 | megalinter-reports
62 | mega-linter.log
63 |
64 | # Summary and status
65 | - run: echo "🎨 MegaLinter quality checks completed"
66 | - run: echo "🍏 Job status is ${{ job.status }}."
67 |
--------------------------------------------------------------------------------
/docs/clojure-spec/generative-testing/example-projects/next-jdbc.md:
--------------------------------------------------------------------------------
1 | # Projects using Clojure spec - next-jdbc
2 |
3 | The next-jdbc project is a modern low-level Clojure wrapper for JDBC-based access to databases.
4 |
5 | The project defines data specifications using predicates and
6 |
7 | ## Defining specifications
8 |
9 | Specifications are defined within a single file [`src/next/jdbc/specs.clj`](https://github.com/seancorfield/next-jdbc/blob/master/src/next/jdbc/specs.clj).
10 |
11 | Specifications start with `clojure.spec.alpha/def` expressions, using predicate functions as specifications. There is also a custom predicate function called
12 |
13 | Function definition specifications follow, using the `clojure.spec.alpha/fdef` function. The `fdef` functions define the specification for the arguments of each function. The `fdef` function name is the same as the function definition it is defining a specification for.
14 |
15 | ## Instrumenting specifications
16 |
17 | Instrumenting functions provides automatic checking that argument in a function call conforms to the specification.
18 |
19 | Rather than write individual expressions to instrument each function, a var called `fns-with-specs` contains a collection of names for all the `fdef` function definition specifications.
20 |
21 | ```clojure
22 | (def ^:private fns-with-specs
23 | [`jdbc/get-datasource
24 | `jdbc/get-connection
25 | `jdbc/prepare
26 | `jdbc/plan
27 | `jdbc/execute!
28 | `jdbc/execute-one!
29 | `jdbc/transact
30 | `jdbc/with-transaction
31 | `connection/->pool
32 | `prepare/execute-batch!
33 | `prepare/set-parameters
34 | `prepare/statement
35 | `sql/insert!
36 | `sql/insert-multi!
37 | `sql/query
38 | `sql/find-by-keys
39 | `sql/get-by-id
40 | `sql/update!
41 | `sql/delete!])
42 | ```
43 |
44 | Instrument all the functions by passing `fns-with-specs` as an argument to the `clojure.spec.test.alpha/instrument` function.
45 |
46 | This call is wrapped in a simple handler function for convenience.
47 |
48 | ```clojure
49 | (defn instrument []
50 | (clojure.spec.test.alpha/instrument fns-with-specs))
51 |
52 | ```
53 |
54 | To remove the checking of argument specifications, `clojure.spec.test.alpha/unstrument` is passed `fns-with-specs`, again wrapped in a convinced function.
55 |
56 | ```clojure
57 | (defn unstrument []
58 | (clojure.spec.test.alpha/unstrument fns-with-specs))
59 | ```
60 |
--------------------------------------------------------------------------------
/docs/clojure-cli/projects/package/index.md:
--------------------------------------------------------------------------------
1 | # Package with Clojure tools.build
2 |
3 | The [:globe_with_meridians: Clojure.org tools.build project](https://clojure.org/guides/tools_build) is used to build jar files to deploy libraries and uberjar files to run deployed projects (e.g. in Docker containers or directly on an Operating System with Java JVM installed).
4 |
5 | [Clojure tools.build](tools-build.md) is a library to define build related tasks using Clojure code.
6 |
7 |
8 | !!! HINT "Practicalli Project Templates includes tools.build configuration"
9 | Clojure projects created with [Practicalli Project Templates](https://practical.li/clojure/clojure-cli/projects/templates/practicalli/) include a `build.clj` configuration to build an uberjar of the project.
10 |
11 | The `make build-jar` runs the `clojure -T:build jar` command to build an uberjar.
12 |
13 |
14 | ??? HINT "Java ARchive - jar file"
15 | A `.jar` file is a zip archive of the project containing all the files for running a Clojure project. The archive should contain metatdata files such as Manifest and pom.xml and can contain Clojure sources or compiled class files from the project (or both).
16 |
17 | An ubjerjar is `.jar` file that also contains all the project dependencies including Clojure. The uberjar is a self-contained file that can be easily deployed and requires only a Java run-time (Java Virtual Machine), using the `java -jar project-uberjar.jar` command, with the option to pass arguments to the Uberjar also.
18 |
19 |
20 | === "Practicalli Project Build tasks"
21 | [:fontawesome-solid-book-open: Practicalli Project templates](/clojure/clojure-cli/projects/templates/) include a `build.clj` configuration with `jar` and `uberjar` tasks.
22 |
23 | Create a runnable Clojure archive
24 |
25 | !!! NOTE ""
26 | ```shell
27 | clojure -T:project/build uberjar
28 | ```
29 |
30 | Create a Clojure library archive
31 |
32 | !!! NOTE ""
33 | ```shell
34 | clojure -T:project/build jar
35 | ```
36 |
37 | === "Clojure tools.build"
38 |
39 | [tools.build](tools-build.md) provides an API for pragmatically defining tasks to build Clojure projects.
40 |
41 | Create a `build.clj` configuration with tasks for building a library jar or runable uberjar.
42 |
43 | [:fontawesome-solid-book-open: Define build.clj configuration for tools.build](tools-build.md){target=_blank .md-button}
44 |
--------------------------------------------------------------------------------
/docs/clojure-spec/generative-testing/index.md:
--------------------------------------------------------------------------------
1 | # Generative testing with Spec and Spec Test
2 |
3 | Clojure spec has been used so far to create specifications for both data and functions.
4 |
5 | Now spec and spec test libraries are used not just validity checking, but also to generate random samples of the data that can be used for extensive testing.
6 |
7 | Generative testing provides a far more effective alternative to unit testing.
8 |
9 | `clojure.spec.test/check/instrument` verifies that calls to a function satisfy the function's specification, the `:arg` in `fdef`.
10 |
11 | `clojure.spec.test/check` function generates 1000 data values to be used as the inputs to a function, checks that the invocation of the function satisfies its specification, the `:ret` and `:fn` in `fdef`. The argument specification, `:arg` in `fdef` is used to generate a wide range of results, which are more capable of finding edge cases that fail.
12 |
13 |
14 |
15 |
16 |
17 |
18 | ## Example: card game
19 |
20 | [practicalli/spec-generative-testing](https://github.com/practicalli/spec-generative-testing) is a simple card game with specifications that are used for basic generative testing.
21 |
22 |
23 |
24 |
25 |
26 |
27 | ## References
28 |
29 | * [Clojure.org guides: Spec - Generators](https://clojure.org/guides/spec#_generators)
30 | * [API reference: clojure.spec.gen.alpha](https://clojure.github.io/spec.alpha/clojure.spec.gen.alpha-api.html)
31 | * [API reference: clojure.spec.test.alpha](https://clojure.github.io/spec.alpha/clojure.spec.test.alpha-api.html)
32 | * [Video: How to do Stateful Property Testing in Clojure?](https://www.youtube.com/watch?v=xw8ZFU8CGdA)
33 |
34 |
45 |
--------------------------------------------------------------------------------
/docs/introduction/concepts/what-is-functional-programming.md:
--------------------------------------------------------------------------------
1 | # What is Functional Programming
2 |
3 | Functional programming can seem quite different from imperative programming used in languages like C, C++ and Java.
4 |
5 | Imperative languages may seem easier initially, as defining one step after another is familiar approach to many things in live. As the scale of a system grows, so does complexity. Imperative languages applied object oriented design to manage complexity with varied rates of success.
6 |
7 | When shared mutable state is common in an OO design, then a system quickly becomes complex and very difficult to reason about.
8 |
9 | Functional programming is actually simpler that the OO approach, although initially it may be unfamiliar and not considered as easy. As systems grow in complexity, the building blocks are still simple and deterministic, creating a system that is far easier to reason about.
10 |
11 | ## Imperative programming languages
12 |
13 | In Imperative languages code is written that specifies a **sequential of instructions** that complete a task. These instructions typically **modifies program state** until the desired result is achieved.
14 |
15 | Variables typically represent **memory addresses that are mutable** (can be changed) by default.
16 |
17 | 
18 |
19 | ## Functional programming languages
20 |
21 | Individual tasks are small and achieved by passing data to a function which returns a result.
22 |
23 | Functions are **composed** together to form more complex tasks and satisfy larger business logic. These composed functions pass the result of their evaluation to the next function, until all functions in the composition have been evaluated.
24 |
25 | The entire functional program can be thought of as a single function defined in terms of smaller ones.
26 |
27 | Program execution is an **evaluation of expressions**, with the nesting structure of function composition determining program flow.
28 |
29 | Data is **immutable** and cannot be change once created. Changes are expressed as new values, with complex values [sharing common values](/data-structures/shared-memory.md) for efficiency.
30 |
31 | 
32 |
--------------------------------------------------------------------------------
/docs/continuous-integration/index.md:
--------------------------------------------------------------------------------
1 | # Continuous Integration
2 |
3 | 
4 |
5 | Topics to be covered in this section include:
6 |
7 | - [ ] Continuous Integration services
8 | - [X] [Circle CI](circle-ci/)
9 | - [X] [GitHub Workflow](github-workflow/)
10 | - [ ] GitLab CI
11 | - [ ] Configure deployment pipelines
12 | - [ ] Manage environment variables
13 | - [ ] Security & Secrets
14 | - [ ] Deployment
15 | - [X] Amazon AWS
16 | - [X] Render.com
17 |
18 | !!! Hint "CircleCI example in Practicalli Clojure Web Services"
19 | [Banking on Clojure](https://practical.li/clojure-web-services/projects/banking-on-clojure/continuous-integration/){target=_blank} is an example of Continuous Integration using CircleCI, with LambdaIsland/Kaocha as the test runner and Heroku as the deployment pipeline.
20 |
21 | ## 12 Factor approach
22 |
23 | Following the [12 factor principles](https://12factor.net/){target=_blank}, the deployment is driven by source code to multiple environments.
24 |
25 | ## CircleCI service
26 |
27 | Use Yaml language to write CI workflows and tasks, using Docker images as a consistent run-time environment
28 |
29 | A commercial service with [a generous free Cloud plan](https://circleci.com/pricing/){target=_blank} - (6,000 minutes), providing highly optomises container images to run tasks efficiently. The CircleCI Clojure images contain Clojure CLI, Leiningen and Babashka pre-installed.
30 |
31 | [CircleCI Orbs](https://circleci.com/orbs/){target=_blank} package up common configuration and tools, greatly simplifying the configuration and maintenance required.
32 |
33 | [CircleCI Clojure language guide](https://circleci.com/docs/2.0/language-clojure/){target=_blank .md-button}
34 |
35 | ## GitHub Workflow
36 |
37 | Use Yaml language to write CI workflows and tasks.
38 |
39 | A commercial service with a modest free plan (2,000 minutes) for open source projects. GitHub Marketplace contains a wide range of Actions, including [Clojure related actions](https://github.com/marketplace?type=actions&query=clojure+){target=_blank}, simplifying the configuration of CI.
40 |
41 | [Setup Clojure](https://github.com/marketplace/actions/setup-clojure){target=_blank} provides Clojure CLI, Leinigen and boot tools for use within the CI workflow
42 |
43 | [GitHub Actions overview](https://github.com/features/actions){target=_blank .md-button}
44 |
--------------------------------------------------------------------------------
/docs/automation/index.md:
--------------------------------------------------------------------------------
1 | # Automation
2 |
3 | Automation tools can provide a consistent command line interface across a wide range of projects.
4 |
5 | Whilst the Clojure CLI is a very extensible tool that flexibility can also add some complexity to its command line interface.
6 |
7 | Automation tools abstract the command line to provide a consistent and simple user experience whilst keeping underlying flexibility.
8 |
9 | !!! HINT "Practicalli recommends make"
10 | A Makefile is not reliant on programming language knowledge so has no barrier to those who are unfamiliar with the Clojure language.
11 |
12 | Make is useful when working with mixed language teams to create a unified tool and command line across a wide range of projects.
13 |
14 |
15 | ## Automation tooling
16 |
17 | * [Make](make.md) - ubiquitous task automation tool, programming language agnostic
18 | * Shell Scripts
19 | * Babashka - create task automation tool with Clojure
20 |
21 |
22 | ## Make
23 |
24 | Make is very simple to use and has a long history as a build tool and wider task automation tool.
25 |
26 | Task are defined in a `Makefile` and task can depend on each other. Any commands or combination of commands that run on the command line can be used as make tasks.
27 |
28 | make provides tab completion of tasks defined in the Makefile without additional configuration.
29 |
30 | `make` is available for all operating systems.
31 |
32 | !!! HINT "Practicalli Project Templates include Makefile"
33 | Creating new projects with `:project/create` and [Practicalli Project Templates](/clojure/clojure-cli/projects/templates/) provide a Makefile with a wide range of common tasks for Clojure development.
34 |
35 |
36 | ### Shell Scripts
37 |
38 | Shell scripts provide a very common way to create a relatively ubiquitous approach to running tools, even across multiple Shell implementations (Bash, Zsh, fish, etc.) and operating systems.
39 |
40 | Shell scripting language is very powerful especially for manipulation of the operating system, although scripts require development and maintenance.
41 |
42 |
43 | ## Babashka
44 |
45 | Write automation scripts with Clojure code using the [Babashka task runner](https://book.babashka.org/#tasks){target=_blank}
46 |
47 | Babashka can use a wide range of Clojure functions and libraries, although as a general script tool then additional coding and maintenance may be reqiured compared to a dedicated tool.
48 |
49 | [Babashka task runner](https://book.babashka.org/#tasks){target=_blank .md-button}
50 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/explain.md:
--------------------------------------------------------------------------------
1 | # Explaining non-conforming values
2 |
3 | `clojure.spec.alpha/explain` describes why a value does not satisfy a specification.
4 |
5 | `clojure.spec.alpha/explain` takes two arguments
6 |
7 | - a specification
8 | - a value to test against the specification
9 |
10 | `Success` string is sent to standard out if the value meets the specification
11 |
12 | A string explaining where the value deviates from the specification is sent to standard out if the value does not meet the specification.
13 |
14 | There are several variations on the explain function for different situations
15 |
16 | - `explain` - sends the return value to the standard out / REPL
17 | - `explain-str` - returns a human readable result.
18 | - `explain-data` - returns a data structure of the error to be processed by other code
19 |
20 | ## Example of a failing value
21 |
22 | First define a namespace and require the Clojure Spec namespace
23 |
24 | ```clojure
25 | (ns practicalli.clojure.specifications
26 | (:require [clojure.spec.alpha :as spec]))
27 |
28 | (spec/def ::meaning-of-life #(= 42 %))
29 | ```
30 |
31 | Given the following specification
32 |
33 | ```clojure
34 | (spec/explain ::meaning-of-life 24)
35 | ```
36 |
37 | Using the value `24` with that specification will fail. Using explain we can see why
38 |
39 | ```clojure
40 | (spec/def ::meaning-of-life-int-or-string
41 | (spec/or :integer #(= 42 %)
42 | :string #(= "forty two" %)))
43 | ```
44 |
45 | In this case explain returned the
46 |
47 | - value being checked against the spec
48 | - result of that check (failed)
49 | - predicate used to check the value
50 | - spec name used to check the value
51 |
52 | Notice that the value failed on the first condition, `:integer`, then stopped without checking the second, `:string`. The `spec/and` macro works the same as `clojure.core/and` in that is stops as soon as something fails.
53 |
54 | ```clojure
55 | (spec/explain ::meaning-of-life-int-or-string 24)
56 | ```
57 |
58 | In this case we still have the value checked, the result and the predicate
59 | More information is provided as to where in the spec the value failed
60 | `:at` shows the path in the spec where the failure occurred, very useful for nested structures
61 | This shows the value of naming your specs descriptively
62 |
63 |
64 | ## Explain with a string
65 |
66 | rather than send information to the system out
67 |
68 | ```clojure
69 | (spec/explain-str ::meaning-of-life 24)
70 | ```
71 |
72 |
73 | ```clojure
74 | (spec/explain-data ::meaning-of-life 24)
75 | ```
76 |
--------------------------------------------------------------------------------
/docs/clojure-spec/organising-specs.md:
--------------------------------------------------------------------------------
1 | # Organizing Specifications
2 |
3 | Data and function definition specifications are typically placed in a dedicated `specification` namespaces, e.g `src/domain/project/specification.clj`.
4 |
5 | Add the data specifications (`spec/def`), custom predicate functions and function specifications (`spec/fdef`) to the `specifications` namespace.
6 |
7 | Specifications for an architecture layer can be organised next to the namespaces managing the layer, e.g. database.
8 |
9 | Migrate specifications to a library once they are applicable to multiple projects.
10 |
11 |
12 |
13 |
14 | ## Instrumenting functions
15 |
16 | Add `spec-test/instrument` expressions to the `specifications` file, after the `spec/fdef` expressions.
17 |
18 | Rather than create individual expressions, create a `clojure.core/def` to contain a collection of all the `spec/fdef` expressions. This list can then be used to `instrument` and `unstrument` all the `spec/fdef` specifications.
19 |
20 | ```clojure
21 | (def ^:private function-specifications
22 | [`card-game/deal-cards
23 | `card-game/winning-player])
24 | ```
25 |
26 | Write simple helper functions to wrap the instrumenting of function specifications
27 |
28 | ```clojure
29 | (defn instrument-all-functions
30 | []
31 | (spec-test/instrument function-specifications))
32 |
33 | (defn unstrument-all-functions
34 | []
35 | (spec-test/unstrument function-specifications))
36 | ```
37 |
38 | ## Unit testing
39 |
40 | Specifications can be incorporated into the existing unit tests, so it is sensible to keep them under the corresponding `test` directory files.
41 |
42 | ## Generative testing
43 |
44 | Using `spec-test/check` will generate 1000 data values for each expression, so by default these tests will take far longer that other tests.
45 |
46 | Configuring generative tests to only generate a small number of values will make `spec-test/check` expressions return almost instantaneously. In this example, only 10 data values are generated
47 |
48 | ```clojure
49 | (spec-test/check `deal-cards
50 | {:clojure.spec.test.check/opts {:num-tests 10}})
51 | ```
52 |
53 | Generative testing with small generators can be run regularly during development without impacting fast feedback.
54 |
55 | [:fontawesome-solid-book-open: Testing with Clojure Spec](/clojure/clojure-spec/testing/){.md-button}
56 |
--------------------------------------------------------------------------------
/docs/reference/creative-coding/index.md:
--------------------------------------------------------------------------------
1 | # Creative coding with Clojure
2 |
3 | Clojure is a very versatile language and can generate data visualizations and graphics from data.
4 |
5 | * [Quil](http://quil.info/){target=_blank} - generate 2D graphics and animations
6 | * [Thi.ng](http://thi.ng/){target=_blank} - computational design tools
7 | * [play.cljc](https://github.com/oakes/play-cljc){target=_blank} - making games (OpenGL and WebGL)
8 | * [Oz](https://github.com/metasoarous/oz){target=_blank} - data visualization and scientific document processing library (see [practicalli/oz-visualisations](https://github.com/practicalli/oz-visualisations){target=_blank} for examples)
9 |
10 | ## Scalable Vector Graphics
11 |
12 | Clojure can generate [Scalable Vector Graphics (SVG)](https://en.wikipedia.org/wiki/Scalable_Vector_Graphics) as they are represented as data. SVG images are _drawn_ from a collection of points and paths. SVG images keep their quality when made larger or smaller. Using SVG images for the web and responsive design is highly recommended.
13 |
14 | This example of an SVG image is made from:
15 |
16 | * a green circle and a smaller blue circle
17 | * a white curvy path
18 |
19 | ```clojure
20 | (defn concentric-circles []
21 | [:svg {:style {:border "1px solid"
22 | :background "white"
23 | :width "150px"
24 | :height "150px"}}
25 | [:circle {:r 50, :cx 75, :cy 75, :fill "green"}]
26 | [:circle {:r 30, :cx 75, :cy 75, :fill "blue"}]
27 | [:path {:stroke-width 12
28 | :stroke "white"
29 | :fill "none"
30 | :d "M 30,40 C 100,40 50,110 120,110"}]])
31 | ```
32 |
33 | Add the following path to the above code to make a curvy lambda symbol
34 |
35 | ```clojure
36 | [:path {:stroke-width 12
37 | :stroke "white"
38 | :fill "none"
39 | :d "M 75,75 C 50,90 50,110 35,110"}]
40 | ```
41 |
42 | The complete solution:
43 |
44 | ```clojure
45 | (defn concentric-circles []
46 | [:svg {:style {:border "1px solid"
47 | :background "white"
48 | :width "150px"
49 | :height "150px"}}
50 | [:circle {:r 50, :cx 75, :cy 75, :fill "green"}]
51 | [:circle {:r 30, :cx 75, :cy 75, :fill "blue"}]
52 | [:path {:stroke-width 12
53 | :stroke "white"
54 | :fill "none"
55 | :d "M 30,40 C 100,40 50,110 120,110"}]
56 | [:path {:stroke-width 12
57 | :stroke "white"
58 | :fill "none"
59 | :d "M 75,75 C 50,90 50,110 35,110"}]])
60 | ```
61 |
--------------------------------------------------------------------------------
/docs/clojure-spec/data/composite-specifications.md:
--------------------------------------------------------------------------------
1 | # Composing Specifications
2 |
3 | No spec is an island
4 |
5 | Composing individual specifications is an effective way to build larger abstractions in specifications without creating fixed hierarchical structures that are harder to refactor.
6 |
7 | Require specification namespace to the page
8 |
9 | ```clojure
10 | (ns practicalli.clojure
11 | (:require [clojure.spec.alpha :as spec]))
12 | ```
13 |
14 |
15 | `spec/and` is used when all specifications should be true.
16 |
17 | ```clojure
18 | (spec/def ::meaning-of-life
19 | (spec/and int?
20 | even?
21 | #(= 42 %)))
22 | ```
23 |
24 | `spec/or` is use when one or more specifications should be true
25 |
26 | ```clojure
27 | (spec/def ::meaning-of-life-int-or-string
28 | (spec/or :integer #(= 42 %)
29 | :string #(= "forty two" %)))
30 | ```
31 |
32 | Each condition in the spec is annotated with a label for each conditional branches.
33 |
34 | Labels are included in the return result from `spec/explain` when values do not conform to a specification, providing context as to why a value failed the specification.
35 |
36 | When an or is conformed, it returns a vector with the condition name and conformed value.
37 |
38 |
39 | ```clojure
40 | (spec/conform ::meaning-of-life-int-or-string 42)
41 | ```
42 |
43 | ```clojure
44 | (spec/conform ::meaning-of-life-int-or-string "forty two")
45 | ```
46 |
47 |
48 | ```clojure
49 | (spec/conform ::meaning-of-life-int-or-string :entropy)
50 | ```
51 |
52 |
53 | ```clojure
54 | (spec/explain ::meaning-of-life-int-or-string :entropy)
55 | ```
56 |
57 |
58 | ## Individual specifications
59 |
60 | Before composing a more abstract specification, first define individual specifications
61 |
62 | ```clojure
63 | (spec/def ::first-name string?)
64 | ```
65 |
66 | ```clojure
67 | (spec/def ::last-name string?)
68 | ```
69 |
70 | ```clojure
71 | (spec/def ::residential-address string?)
72 | ```
73 |
74 |
75 | ## Composing hash-map specification
76 |
77 | The individual specifications can now be composed into a single specification.
78 |
79 | `keys` function combines specifications to form a composite specification in the form of a Clojure hash-map.
80 |
81 | ```clojure
82 | (spec/def ::customer-details
83 | (spec/keys
84 | :req [::first-name ::last-name ::residential-address]))
85 | ```
86 |
87 | Use the composite specification with a value
88 |
89 | ```clojure
90 | (spec/conform ::customer-details
91 | {::first-name "Jenny"
92 | ::last-name "Jetpack"
93 | ::residential-address "42 meaning of life street, Earth"})
94 | ```
95 |
--------------------------------------------------------------------------------
/docs/testing/test-runners/example-projects.md:
--------------------------------------------------------------------------------
1 | # Example projects
2 |
3 | * [TDD Kata: Recent Song-list](/simple-projects/tdd-kata/recent-song-list.md) - simple tests examples
4 | * [Codewars: Rock Paper Scissors (lizard spock) solution](https://github.com/practicalli/codewars-guides/tree/develop/rock-paper-scissors) - `and` examples
5 | * [practicalli/numbers-to-words](https://github.com/practicalli/numbers-to-words) - overly verbose example, ripe for refactor
6 | * [practicalli/codewars-guides](https://github.com/practicalli/codewars-guides) - deps.edn projects
7 | * [practicalli/exercism-clojure-guides](https://github.com/practicalli/exercism-clojure-guides) - Leiningen projects
8 |
9 | ## Sean Corfield - user manager
10 |
11 | [User manager](https://github.com/seancorfield/usermanager-example) has unit tests that also include an embedded database. Tests can run with the Cognitect Labs test runner.
12 |
13 | `:test` alias includes the test path and a dependency for the H2 database
14 |
15 | Cognitect Labs test runner included in the project `deps.edn` file as `:runner`
16 |
17 | `clojure -M:test:runner` will run the Cognitect Labs runner and include the dependency to run the in-memory database used for the tests.
18 |
19 | ### Using koacha with Sean Corfield user manager
20 |
21 | Adding a `test.edn` file is not sufficient for testing this project with lambdaisland/kaocha, as the H2 dependency is also needed.
22 |
23 | Create a `bin/koacha` script and add the extra alias
24 |
25 | ```shell
26 | #!/usr/bin/env bash
27 | clojure -M:test:test-runner-kaocha "$@"
28 | ```
29 |
30 |
31 |
32 |
33 | ## Status Monitor
34 |
35 | [Status monitor](https://github.com/jr0cket/webapp-status-monitor) is a Leiningen project.
36 |
37 | Include a `:kaocha` profile in the `project.clj` file, adding the koacha dependency. The `:kaocha` alias sets the main namespace and uses the kaocha profile.
38 |
39 | ```clojure
40 | {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
41 | [ring/ring-mock "0.3.2"]]}
42 | :kaocha {:dependencies [[lambdaisland/kaocha "1.0.632"]]}}
43 | :aliases {"kaocha" ["with-profile" "+kaocha" "run" "-m" "kaocha.runner"]}
44 | ```
45 |
46 | `lein kaocha` will run all the tests
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------