~subsetpark/bagatto

e81a8b06d4bb5032f6d360980a4864c5fff634c2 — Zach Smith 3 months ago ddbda53 v0.3.0
Reintegrate repl module
5 files changed, 150 insertions(+), 124 deletions(-)

M MANUAL.md
M api.md
M bagatto.janet
M main.janet
M project.janet
M MANUAL.md => MANUAL.md +48 -12
@@ 20,6 20,42 @@ ultimately specify the **path** and **contents** of one or more
files. Bagatto will then ensure the presence of each file path and
ensure that its contents are as specified.

## REPL Mode

We can enter a REPL environment that allows us to explore the index
module by using the `--repl` flag to `bag`. This enters a Janet REPL
with three helper functions injected: `eval-data`, `eval-site`, and
`write-site`. These represent the three main steps of executing
Bagatto: generating site data, generating site "write specifications",
and writing the specified files.

Here's a short example using the `basic-site` demo:

```clj
code-src/bagatto/demo/basic-site [master !] ⊕ bag --repl index.janet 
repl:1:> (eval-data data)
Reading config data spec...
Reading pages data spec...
Reading css data spec...
Beginning 3 jobs...
Loaded config
Loading pages...
[pages] Loading 2 files
Loading css (styles.css)...
Finished jobs.
@{:config {:author "Z. D. Smith" 
           :description "A minimal website" 
           :title "Bagatto Demo"} 
  :pages @[@{:basename "about" 
             :path "pages/about.md" 
             :contents @"..."} 
           @{:basename "bagatto" 
             :path "pages/bagatto.md" 
             :contents @"..."}] 
  :css @{:path "styles.css" 
         :contents @"..."}}
```

## The Bagatto API

The `bag` command accepts a single filename as an argument. This is


@@ 105,7 141,7 @@ When Bagatto creates the *site data* for this specification, it will
consist of a single key-value pair:

```clj
repl:13:> (bagatto/eval-data data)
repl:13:> (eval-data data)
@{:config {:title "A Demo Bagatto Config"}}
```



@@ 132,7 168,7 @@ current directory, load its contents, and then call
the content of the site data associated with `:config-json`.

```clj
repl:17:> (bagatto/eval-data data)
repl:17:> (eval-data data)
@{:config-json @{"subtitle" "A Very Good Blog." 
                 :path "config.json" 
                 :contents @"{\"subtitle\":\"A Very Good Blog.\"}\n"}}


@@ 170,7 206,7 @@ Thus, we can use it as a data specification:
                    :attrs bagatto/parse-base}})
```
```clj
repl:27:> (bagatto/eval-data data)
repl:27:> (eval-data data)
@{:static @[@{:path "demo/static/hello.png"}]}
```



@@ 208,7 244,7 @@ additional metadata.
```

```clj
repl:33:> (bagatto/eval-data data)
repl:33:> (eval-data data)
@{:posts @[@{:path "demo/posts/post.md" :contents @"..."} 
           @{"status" "post" 
             :path "demo/posts/post2.md" 


@@ 268,7 304,7 @@ their code.
The relationship between `data` and `site` is simple but important to
understand. The site specification is evaluated in the *context* of
the site data, which is the output of the data specification (it's
what we see when we run `bagatto/eval-data` above). 
what we see when we run `eval-data` above). 

A site specification isn't actually a mapping data entries to pages;
in most websites of any size, any given page will require data from


@@ 293,7 329,7 @@ repl:2:> (def site {:_ {:dest "out.txt" :out "Welcome to my website"}})
{:_ {:dest "out.txt" :out "Welcome to my website"}}
```

We can use `bagatto/eval-site` to get an output of the path and
We can use `eval-site` to get an output of the path and
contents of each file to be created. This is useful for debugging; in
reality, site contents are generated using fibers, so this lets us
peek under the hood to understand what our site specifications produce.


@@ 303,7 339,7 @@ this case our only specification is completely static. therefore we
can pass in an empty struct as the site data.

```cli
repl:4:> (bagatto/eval-site site {})
repl:4:> (eval-site site {})
@[(:write "out.txt" "Welcome to my website")]
```



@@ 337,7 373,7 @@ functions, we don't need to use the output of the `eval-data`
command. We can construct a struct directly.

```clj
repl:8:> (bagatto/eval-site site {:secret "p@ssw0rd"})
repl:8:> (eval-site site {:secret "p@ssw0rd"})
@[(:write "out.txt" "\"p@ssw0rd\"")]
```



@@ 356,7 392,7 @@ repl:12:> (defn renderer [data] string/format "%s:%j:%f"
<function renderer>
repl:14:> (def site {:_ {:dest "out.txt" :out renderer}})
{:_ {:dest "out.txt" :out <function renderer>}}
repl:15:> (bagatto/eval-site site {:personal {:password "p@ssw0rd"} 
repl:15:> (eval-site site {:personal {:password "p@ssw0rd"} 
                                   :config {:prefix "md5"}})
@[(:write "out.txt" "md5:\"p@ssw0rd\":0.487181")]
``` 


@@ 443,7 479,7 @@ we specify.
We can evaluate the data spec, and use that to evaluate the site spec:

```clj
repl:56:> (bagatto/eval-site site (bagatto/eval-data data))
repl:56:> (eval-site site (eval-data data))
@[(:write "passwords/alice.json" "pw::1234") 
  (:write "passwords/bob.json" "pw::snoopy")]
```


@@ 483,7 519,7 @@ repl:58:> (def site {:_ {:each :users :dest (bagatto/path-copier "passwords/")}}
Evaluating the site produces two copy instructions to the new paths:

```clj
repl:63:> (bagatto/eval-site site (bagatto/eval-data data))
repl:63:> (eval-site site (eval-data data))
@[(:copy "users/alice.json" "passwords/alice.json") 
  (:copy "users/bob.json" "passwords/bob.json")]
```


@@ 605,7 641,7 @@ Thus I avoid having to write a new renderer function for each
template. Evaluating the site we get the same thing:

```clj
repl:7:> (bagatto/eval-site site {"topic" "Web Design"})
repl:7:> (eval-site site {"topic" "Web Design"})
@[(:write "out.txt" @"I am known for my Web Design skills.\n")]
```


M api.md => api.md +90 -109
@@ 6,9 6,6 @@
, [bagatto/datestr-&gt;date](#bagattodatestr-&gt;date)
, [bagatto/datestr-&gt;secs](#bagattodatestr-&gt;secs)
, [bagatto/epp](#bagattoepp)
, [bagatto/eval-data](#bagattoeval-data)
, [bagatto/eval-loader](#bagattoeval-loader)
, [bagatto/eval-site](#bagattoeval-site)
, [bagatto/format](#bagattoformat)
, [bagatto/get-default](#bagattoget-default)
, [bagatto/glob](#bagattoglob)


@@ 32,7 29,9 @@
, [bagatto/slug-from-attr](#bagattoslug-from-attr)
, [bagatto/slugify](#bagattoslugify)
, [bagatto/slurp-*](#bagattoslurp-*)
, [bagatto/write-site](#bagattowrite-site)
, [repl/eval-data](#repleval-data)
, [repl/eval-site](#repleval-site)
, [repl/write-site](#replwrite-site)

## bagatto/%p



@@ 63,7 62,7 @@ repl:11:> (f {"author" "Z. D. Smith"} {:title "My second post"})
"site/z-d-smith/my-second-post.html"
```

[1]: bagatto.janet#L267
[1]: bagatto.janet#L264

## bagatto/*



@@ 76,7 75,7 @@ repl:11:> (f {"author" "Z. D. Smith"} {:title "My second post"})
Generate a function that will return all the filenames that match a given
file blob.

[2]: bagatto.janet#L122
[2]: bagatto.janet#L119

## bagatto/attr-sorter



@@ 89,7 88,7 @@ file blob.
Return a sorter function that, given a list of items, sorts
according to the items' values at the specified key.

[3]: bagatto.janet#L350
[3]: bagatto.janet#L347

## bagatto/datestr-&gt;date



@@ 104,7 103,7 @@ of the kind returned by `os/date`. Pass a truthy value in the second
argument to adjust for human display (setting values like day and
month to be 1-indexed).

[4]: bagatto.janet#L95
[4]: bagatto.janet#L92

## bagatto/datestr-&gt;secs



@@ 117,7 116,7 @@ month to be 1-indexed).
Given a string representation of a date or datetime, return the
epoch seconds value for that date.

[5]: bagatto.janet#L87
[5]: bagatto.janet#L84

## bagatto/epp



@@ 131,60 130,11 @@ Pretty-print to stderr. Since Temple templates operate over stdout,
we should use stderr instead if we need to print something to the
console for debugging purposes.

[6]: bagatto.janet#L466

## bagatto/eval-data

**function**  | [source][7]

```janet
(eval-data data)
```

Evaluate an object according to the Bagatto *site data specification*.

Not necessary to define a module, but can be useful to debug your
configuration from within the REPL.

[7]: bagatto.janet#L363

## bagatto/eval-loader

**function**  | [source][8]

```janet
(eval-loader fiber)
```

Evaluate a loader fiber to view the list of filenames, or filename
and contents, it produces.

Not necessary to define a module, but can be useful to debug your
configuration from within the REPL.

[8]: bagatto.janet#L373

## bagatto/eval-site

**function**  | [source][9]

```janet
(eval-site site data)
```

Evaluate an object according to the Bagatto *site generation specification*,
given a site data object as context.

Not necessary to define a module, but can be useful to debug your
configuration from within the REPL.

# TODO : To make this work again, expose the generator functions in a non-threaded context.

[9]: bagatto.janet#L384
[6]: bagatto.janet#L421

## bagatto/format

**function**  | [source][10]
**function**  | [source][7]

```janet
(format templ & xs)


@@ 194,11 144,11 @@ A simple wrapper around `string/format` to ease development. If one
of `xs` is nil, it will output an empty string rather than crashing
the template.

[10]: bagatto.janet#L456
[7]: bagatto.janet#L411

## bagatto/get-default

**function**  | [source][11]
**function**  | [source][8]

```janet
(get-default attribute)


@@ 213,11 163,11 @@ and then implement your more specific logic.

(see `bagatto/set-defaults!` for more information.)

[11]: bagatto.janet#L34
[8]: bagatto.janet#L31

## bagatto/glob

**function**  | [source][12]
**function**  | [source][9]

```janet
(glob pattern)


@@ 225,11 175,11 @@ and then implement your more specific logic.



[12]: bagatto.janet#L114
[9]: bagatto.janet#L111

## bagatto/include

**macro**  | [source][13]
**macro**  | [source][10]

```janet
(include template)


@@ 249,11 199,11 @@ the included template. This makes it much easier to trace rendering
errors in nested templates.


[13]: bagatto.janet#L414
[10]: bagatto.janet#L364

## bagatto/item-getter

**function**  | [source][14]
**function**  | [source][11]

```janet
(item-getter path)


@@ 264,11 214,11 @@ the given path in the item.

The path should be a tuple of keys, eg.: `[:user :full-name]`. 

[14]: bagatto.janet#L257
[11]: bagatto.janet#L254

## bagatto/jdn-data

**function**  | [source][15]
**function**  | [source][12]

```janet
(jdn-data src)


@@ 276,11 226,11 @@ The path should be a tuple of keys, eg.: `[:user :full-name]`.

Get metadata from a JDN-formatted string.

[15]: bagatto.janet#L67
[12]: bagatto.janet#L64

## bagatto/json-data

**function**  | [source][16]
**function**  | [source][13]

```janet
(json-data src)


@@ 288,23 238,23 @@ Get metadata from a JDN-formatted string.

Get metadata from a JSON-formatted string.

[16]: bagatto.janet#L72
[13]: bagatto.janet#L69

## bagatto/markdown-&gt;html

**function**  | [source][17]
**function**  | [source][14]

```janet
(markdown->html md)
(markdown->html md &keys {:exts exts :opts opts})
```

Render a markdown string into HTML.

[17]: bagatto.janet#L438
[14]: bagatto.janet#L391

## bagatto/mmarkdown-&gt;html

**function**  | [source][18]
**function**  | [source][15]

```janet
(mmarkdown->html md &keys {:smart smart})


@@ 318,11 268,11 @@ Accepts &keys flags :

(requires the presence of the multimarkdown executable.)

[18]: bagatto.janet#L443
[15]: bagatto.janet#L398

## bagatto/mmarkdown-data

**function**  | [source][19]
**function**  | [source][16]

```janet
(mmarkdown-data md)


@@ 330,11 280,11 @@ Accepts &keys flags :

Get metadata from a markdown string using multimarkdown.

[19]: bagatto.janet#L62
[16]: bagatto.janet#L59

## bagatto/parse-base

**function**  | [source][20]
**function**  | [source][17]

```janet
(parse-base _src attrs)


@@ 345,11 295,11 @@ default attributes that are provided for every file. These are:
- `:path`: the file path
- `:contents`: (if the file was read) the contents of the file 

[20]: bagatto.janet#L142
[17]: bagatto.janet#L139

## bagatto/parse-jdn

**function**  | [source][21]
**function**  | [source][18]

```janet
(parse-jdn src attrs)


@@ 357,11 307,11 @@ default attributes that are provided for every file. These are:

Attribute parser for JDN.

[21]: bagatto.janet#L161
[18]: bagatto.janet#L158

## bagatto/parse-json

**function**  | [source][22]
**function**  | [source][19]

```janet
(parse-json src attrs)


@@ 369,11 319,11 @@ Attribute parser for JDN.

Attribute parser for JSON.

[22]: bagatto.janet#L166
[19]: bagatto.janet#L163

## bagatto/parse-mmarkdown

**function**  | [source][23]
**function**  | [source][20]

```janet
(parse-mmarkdown src attrs)


@@ 383,11 333,11 @@ Attribute parser for multimarkdown.

(requires the presence of the multimarkdown executable.)

[23]: bagatto.janet#L152
[20]: bagatto.janet#L149

## bagatto/path-copier

**function**  | [source][24]
**function**  | [source][21]

```janet
(path-copier base &opt key)


@@ 407,11 357,11 @@ repl:4:> (f {} {:path "original/source/directory/newfile.png"})
"destination/newfile.png"
```

[24]: bagatto.janet#L329
[21]: bagatto.janet#L326

## bagatto/render

**function**  | [source][25]
**function**  | [source][22]

```janet
(render template site &opt item)


@@ 432,11 382,11 @@ template.

See the [Temple](https://git.sr.ht/~bakpakin/temple) site for more details.

[25]: bagatto.janet#L175
[22]: bagatto.janet#L172

## bagatto/renderer

**function**  | [source][26]
**function**  | [source][23]

```janet
(renderer template-path &opt extra-attrs)


@@ 447,11 397,11 @@ that will call `render` with that template on any input.

(see `bagatto/render` for more details.)

[26]: bagatto.janet#L233
[23]: bagatto.janet#L230

## bagatto/set-defaults!

**function**  | [source][27]
**function**  | [source][24]

```janet
(set-defaults! defaults)


@@ 463,11 413,11 @@ specifications. For instance, setting the default of `:attrs` to
by parsing it as JSON. `:attrs` could still be set on any entry in
the data spec in order to override the default.

[27]: bagatto.janet#L23
[24]: bagatto.janet#L20

## bagatto/set-output-dir!

**function**  | [source][28]
**function**  | [source][25]

```janet
(set-output-dir! dir)


@@ 478,11 428,11 @@ Name a directory for all produced files to be placed. For instance,
`(bagatto/set-output-dir! "site")` will place your generated file
hierarchy in a directory called `site`.

[28]: bagatto.janet#L48
[25]: bagatto.janet#L45

## bagatto/site-getter

**function**  | [source][29]
**function**  | [source][26]

```janet
(site-getter path)


@@ 493,11 443,11 @@ the value at the given path in the site.

The path should be a tuple of keys, eg.: `[:blog :description]`. 

[29]: bagatto.janet#L247
[26]: bagatto.janet#L244

## bagatto/slug-from-attr

**function**  | [source][30]
**function**  | [source][27]

```janet
(slug-from-attr item key)


@@ 508,11 458,11 @@ it make the value into a slug.

(see `bagatto/slugify` for more details.)

[30]: bagatto.janet#L219
[27]: bagatto.janet#L216

## bagatto/slugify

**function**  | [source][31]
**function**  | [source][28]

```janet
(slugify s)


@@ 520,11 470,11 @@ it make the value into a slug.

Normalize a string for use as a slug, eg., in a file path.

[31]: bagatto.janet#L205
[28]: bagatto.janet#L202

## bagatto/slurp-*

**function**  | [source][32]
**function**  | [source][29]

```janet
(slurp-* pattern)


@@ 533,11 483,42 @@ Normalize a string for use as a slug, eg., in a file path.
Generate a function that will slurp all the files that match a given
file blob.

[32]: bagatto.janet#L130
[29]: bagatto.janet#L127

## repl/eval-data

## bagatto/write-site
**function**  | [source][30]

```janet
(eval-data data)
```

Evaluate an object according to the Bagatto *site data specification*.

Not necessary to define a module, but can be useful to debug your
configuration from within the REPL.

[30]: repl.janet#L5

## repl/eval-site

**function**  | [source][31]

**function**  | [source][33]
```janet
(eval-site site data)
```

Evaluate an object according to the Bagatto *site generation specification*,
given a site data object as context.

Not necessary to define a module, but can be useful to debug your
configuration from within the REPL.

[31]: repl.janet#L15

## repl/write-site

**function**  | [source][32]

```janet
(write-site writer-specs output-dir)


@@ 549,5 530,5 @@ actual file generation.
Not necessary to define a module, but can be useful to debug your
configuration from within the REPL.

[33]: bagatto.janet#L397
[32]: repl.janet#L26


M bagatto.janet => bagatto.janet +1 -1
@@ 160,7 160,7 @@
  [src attrs]
  (merge-into attrs (jdn-data src)))

(defn markdownparse-json
(defn parse-json
  "Attribute parser for JSON."
  [src attrs]
  (merge-into attrs (json-data src)))

M main.janet => main.janet +10 -1
@@ 4,6 4,7 @@
(import src/core)
(import src/error)
(import src/env)
(import repl)

(defn- index-value
  [env sym index]


@@ 22,6 23,12 @@
                                :help "The index module to evaluate."
                                :required true}])

(def repl-env
  ```
  An environment including the `repl` module, for interactive development.
  ```
  (require "repl"))

(defn main [& args]
  (merge-into root-env core/bagatto)
  (env/prepare-root-env!)


@@ 35,7 42,9 @@
      (if (args "repl")
        # REPL mode: Enter a REPL to experiment with the contents of the
        # index module.
        (repl nil nil env)
        (do
          (merge-into env repl-env)
          (repl nil nil env))
        # Normal mode: evaluate index module and write site.
        (do (setdyn :bagatto-defaults (env :bagatto-defaults))


M project.janet => project.janet +1 -1
@@ 16,4 16,4 @@
  :install true)

(declare-source
  :source ["bagatto.janet"])
  :source ["bagatto.janet" "repl.janet"])