Using rib with my own parser - Rib

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Joel McCracken

so, for this project I am trying to build

Joel McCracken

it does seem like asciidoc is unsuitable, it doesnt have a good way to "embed" xml tags

Joel McCracken

which is fine, i can just use my own xml thing anyway

Joel McCracken

I could do like +++<my-tag>+++, have some other content, and end it with +++</my-tag>+++

Joel McCracken

but that just seems horrible

Sridhar Ratnakumar

I find asciidoc's built-in syntax to be good enough. Is there anything you plan to define in XML that is not possible to do in asciidoc?

Sridhar Ratnakumar

The other shortcoming of asciidoc is you won't get a Haskell parsed data-type, if we shell-out to its ruby html generator

Sridhar Ratnakumar

Alternatively: perhaps asciidoc can be included in your xml markup?

Sridhar Ratnakumar

So parts of your xml doc gets parsed with asciidoc, while you retain control over the rest of it

Joel McCracken

yeah, this is kindof what I was thinking of

Joel McCracken

plain text can be treated as asciidoc or markdown

Joel McCracken

its the way I have things working in pollen

Joel McCracken

actually, now that I think about it, I think i don't have markdown w/ pollen, just some subset of things I want are built in to the markup (e.g. double newlines -> paragraphs

Joel McCracken

So, as far as I can tell, I will have to modify rib itself, i can't just implement my own IsMarkup thing

Sridhar Ratnakumar

Yes, but the only modification you need to do is to add a constructor to the Markup type. This is something we can obviate by improving the API.

Joel McCracken

Would it be worth it for me to try to figure it out?

Sridhar Ratnakumar

Assuming you are using the master branch (and not one on Hackage)

Sridhar Ratnakumar

This type basically https://github.com/srid/rib/blob/master/src/Rib/Markup.hs#L26-L28

Haskell library for writing your own static site generator - srid/rib
Sridhar Ratnakumar

You'd add a constructor like Markup_MyXmlThingy :: Markup MyXmlDoc

Sridhar Ratnakumar

(in addition to writing an instance for IsMarkup MyXmlDoc)

Sridhar Ratnakumar

See https://github.com/srid/rib/blob/master/src/Rib/Markup/MMark.hs for an example. That adds mmark support.

Haskell library for writing your own static site generator - srid/rib
Sridhar Ratnakumar

Tomorrow I'll figure out if there is a way to obviate it. But meanwhile you may just modify rib ...

Sridhar Ratnakumar

The only reason the Markup doc type exists is to build the patterns dict for passing to buildHtmlMulti.

Joel McCracken

well what I meant was figuring out how to get rid of it

Sridhar Ratnakumar
        Rib.buildHtmlMulti patterns $
          renderPage . Page_Doc
    -- File patterns to build, using the associated markup parser
    patterns =
      Map.fromList
        [ ([relfile|*.md|], Some Rib.Markup_MMark)
        ]

That tells the function, "yea, build *.md files using this markup parser"

Joel McCracken

(the need to modify RIB itself)

Joel McCracken

id def prefer to adoid having my own fork for long

Joel McCracken

question @Sridhar Ratnakumar does the desire I am describing ring true for you too? (that is, writing in an extensible markup language)

Sridhar Ratnakumar

Perhaps buildHtmlMulti can take the IsMarkup constraint, and then you call it multiple times, one for each markup type:

mdPages <- buildHtmlMulti @MMark [relfile|*.md] ...
xmlPages <- buildHtmlMulti @MyXmlType [relfile|*.xml] ...
let allPages = mdPages <> xmlPages
Joel McCracken

its weird to me that it seems like most people do not care about it

Joel McCracken

im not sure if i'm just a weirdo, or if its like people never think about it, or what

Joel McCracken

yea thats kinda what I was thinking

Sridhar Ratnakumar

I've thought about something like xml. Or yaml. Or even dhall ... as representation of structured data (if not text).

Sridhar Ratnakumar

For example, links.dhall - which gets processed and rendered into a page of links.

Joel McCracken

really the reason I like xml over those options is that i think its a bit more flexible

Joel McCracken

like, xml already supports e.g. CDATA

Joel McCracken

If i want to embed something funky, its there

Sridhar Ratnakumar

I just wouldn't want to use xml for formatting text content.

Sridhar Ratnakumar

But for structured data, it is fine.

Sridhar Ratnakumar

One of these days I want to add dhall support.

Joel McCracken

i mean, something like adding *bold* to the xml processing would go a really long away

Sridhar Ratnakumar

during development of rib you may find nix-shell --run ghcid to be handy.

Joel McCracken

text separated by a blank line to mean new paragraph, etc

Sridhar Ratnakumar

And to test your library changes, you can clone https://github.com/srid/rib-sample and run nix-shell --arg rib /path/to/your/rib --run 'ghcid -T ":main serve -p 9876"' (spins up http://localhost:9876). though you'd have to re-run the command after changing rib library.

Sample site for the Rib static site generator. Contribute to srid/rib-sample development by creating an account on GitHub.
Joel McCracken

would it be appropriate to add as ection to the readme

Joel McCracken

i almost always do that

Joel McCracken

because i freaking forget which version of a command works

Joel McCracken

for some reason i have a very hard time figuring out the right way to make ghcid do what I want it to do

Sridhar Ratnakumar

i almost never have to configure ghcid.

Sridhar Ratnakumar

defaults work fine for me

Sridhar Ratnakumar

except for the -T argument, which is kind of needed if you also want to run the program in addition to compiling it

Sridhar Ratnakumar

ghcid -T "blah" will basically evaluate "blah" in the ghci repl it launches

Sridhar Ratnakumar

(right after every successful compile)

Joel McCracken

liek i had to do this to make the tests run

Joel McCracken

ghcid -c 'stack ghci joelmccracken-hs:joelmccracken-hs-test' --test 'Main.main'

Joel McCracken

(this is where I was spiking out the xml processing for my xml version to validate i have a path forward)

Sridhar Ratnakumar

you could just put those CLI in scripts/myscript

Sridhar Ratnakumar

btw, development stuff may instead be added to https://github.com/srid/rib/blob/master/CONTRIBUTING.md

Haskell library for writing your own static site generator - srid/rib
Sridhar Ratnakumar

feel free to open a PR, otherwise i'll add it tomorrow

Joel McCracken

i probably wont start tonight, about to go to bed

Joel McCracken

and i am going to be afk for a few days

Joel McCracken

but i might be hacking on it

Sridhar Ratnakumar

oh yea, merry christmas! :D

Joel McCracken

ha ty, i dont celebrate it but we are going to get together as family

Sridhar Ratnakumar

Looks like Data.Some and Data.Proxy is coming in handy to achieve this (eliminating need to modify rib)

Sridhar Ratnakumar

I'm wondering if the 'meta' from Document meta should be discarded, for simplicity.

Sridhar Ratnakumar

@Joel McCracken If you are curious, in particular this commit: https://github.com/srid/rib/pull/65/commits/4f42517abb6d244e51013644cb09a571341c77e7

Fixes #62 todo Simplify API, lest user has to use Some too much? Test with rib-sample in a branch
Sridhar Ratnakumar

Actually there are some problems with this. I'll address them.

Sridhar Ratnakumar

Looks to be like in the end IsMarkup type class will have only one method left, to parse the file into some type. That's greatly simplifying.

Sridhar Ratnakumar

w00t! got dhall version working. both markdown and dhall at same time, without having to change rib

Joel McCracken

so its interesting, I really don't know if a "metas" section is necessary

Sridhar Ratnakumar

meta is gone in the latest PR

Joel McCracken

it is necessary if 1) you need some kind of meta support and 2) your markup doesnt support some kind of metas

Sridhar Ratnakumar

instead I exposed metadata functions from MMark.hs and Pandoc.hs that the user can explicitly call if they need to extract meta

Joel McCracken

yeah, that sounds good

Joel McCracken

but how do you handle like

Sridhar Ratnakumar

I'm wondering if I can do away with the type class itself, and instead expect just a function Text -> IO a :-)

Joel McCracken

possibly? hard to say per se

Sridhar Ratnakumar

I'm not sure yet; still exploring in code ...

Joel McCracken

if it were me, given your stated goal, i think what I would do is make handy, discrete functions

Joel McCracken

that can be combined arbitrarily

Joel McCracken

not saying you aren't doing that

Sridhar Ratnakumar

The document type now looks like this:

data Document repr
  = Document
      { -- | Path to the document; relative to the source directory.
        _document_path :: Path Rel File,
        -- | Parsed representation of the document.
        _document_val :: repr
      }
  deriving (Generic, Functor)

Basically a tuple of filepath and parsed structure. That's the minimum rib will need to pass over to the user.

Joel McCracken

just like i feel like I am not sure what probelm that typeclass solves

Sridhar Ratnakumar

And type class's responsibility has been reduced to ... basically creating this Document value. That's all it essentially does.

Sridhar Ratnakumar

Well , it's a learning process for me - rib being my first haskell library :-D so I'm not surprised to begin from a place of overengineering.

Joel McCracken

no worires man! its better than my first attempt would be, for sure

Sridhar Ratnakumar

anywya, in your case, it would be Document MyXmlType

Sridhar Ratnakumar

replacing type class with something like:

type MarkupParser a = forall m b. MonadIO m => Path b File -> m (Either Text a)
Sridhar Ratnakumar

wow it actually worked haha

Sridhar Ratnakumar

okay, so the shake function will looke like this:

buildHtmlMulti patterns myMarkupParser myPageBuilder

patterns, input function, output function. that's it

Joel McCracken

do you think its stableenough to develop against? i fetched your branch

Sridhar Ratnakumar

I think it is nearly done. What do you think of the API? Looking for some final tweaks before I merge.

Sridhar Ratnakumar

(One last thing to do before I merge the PR is to update rib-sample)

Sridhar Ratnakumar

I don't like "Rib.Markup". Dhall is not a markup. So I'm gonna rename it to something more general. Since there is now Rib.Source (renamed from 'Document', as 'source' reflects its nature more precisely), I'll try Rib.Parser

Sridhar Ratnakumar

Okay, branch is stable. Going to test for bugs. Then merge. Here's the user-facing upgrade path you can expect: https://github.com/srid/rib-sample/pull/4/files

Sridhar Ratnakumar

In that PR, notice the use of M.parseIO. That's where you would inject your Xml parser function.

Sridhar Ratnakumar

@Joel McCracken Everything merged to master!

Sridhar Ratnakumar

@Joel McCracken When you get to play with it, I'd be interested in hearing your feedback regarding the SourceReader type. Whether it does what you want re: your xml parsing. Personally I just found that I needed to switch from IO to shake's Action monad, when working with dhall parsing, so I am proposing this change: https://github.com/srid/rib/pull/69

This will allow us to do Shake-y things in our readers. For example, parsing our Dhall files may require need'ing its dependent .dhall files, doing which ensures that when those files change ri...
Joel McCracken

I'm going to work with this today, at least I am planning on it. I'll let you know when I do

Sridhar Ratnakumar

I merged this PR. Shouldn't be huge change in the user code. Just replace IO a with Action a in your reader function. And prepend all IO functions with liftIO. Prefer readFile' (from import Development.Shake) when reading some file, as it will track the dependency automatically.

Sridhar Ratnakumar

Here's what adding Dhall parser support to a rib-based static website currently looks like :-) https://github.com/srid/website/pull/6/files

Sridhar Ratnakumar

I think I'm gonna add that parse function into Rib.Parser.Dhall