Skip to content

A GO program to loop structured data through the template engine

License

Notifications You must be signed in to change notification settings

pilgreen/loopit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

loopit

A GO program to loop structured data through the template engine. This is a command-line program that pipes a CSV or JSON file through the "text/template" package and prints the results to Stdout. If you need to make a full blown website or blog, and have stumbled onto this page, I highly recommend using Hugo instead. I often have to make small snippets of data-based code, portions of a page, or single pages in multiple environments. With these type of projects, the file structure required by Hugo sometimes prevents me from using it.

Example usage:

loopit [options] template.html [...template.html]

Command-Line options

-data file|url

The data flag will accept a file path on the system or a url to a CSV, JSON or RSS file. Loopit will make a map of the file data and pass it to the template.

In the case of a CSV file, loopit will create an object for each row using the first row as the keys for each object. Therefore, the file needs to have a header row with column names that can be used in the dot notation of the "text/template" pacakge. As a general rule stick to single words without punctuation and you should be fine.

In the case of a JSON file, loopit will pass the object or array straight through.

In the case of an RSS file, loopit will convert most standard elements.

If you do not specify a template file, loopit will print the parsed data to sdout. It will also accept data piped in through stdin if -data is ommitted.

-markdown

The markdown flag passes the output through the russross/blackfriday package.

-minify

The minify flag will pass the output through the tdewolff/minify package. Currently this only works for HTML output.

-out filename

Write the markup to a file instead of stdout. This uses ioutil.WriteFile() and replaces the file each time.

-watch

After the initial render, loopit will enter watch mode and re-run the render function any time a template is written. It also recursively walks the current directory and adds any .js and .css files it finds to the list.

-shim

The shim flag is a boolean option. When added, loopit will use goquery to move DOM around after the template has been parsed. This is useful when HTML is provided in a JSON object, but needs to be enhanced with ads or any other content.

Here is an example that will inject an ad before the 3rd paragraph:

<div shim="body p:nth-child(3)">[Ad code goes here]</div>

-version

Prints the version.

Template functions

The Go template package is very basic, but also extendable. Below are custom functions that are available in the template based solely on need so far. Several of these are borrowed from Hugo.

Strings

add

Adds an int to an int.

{{ add 1 $index }}

dateFormat

This function parses a date using the time package and returns a formatted version of your choosing. The Golang time package is kind of odd, but also very flexible. Make sure to read the documentation fully before working with this.

The first parameter is the date string to parse, the second is a representation of that date mapped to 'Mon Jan 2 15:04:05 MST 2006' and the third is the desired output format mapped to 'Mon Jan 2 15:04:05 MST 2006'.

The fourth parameter is optional, and allows you to alter the Timezone using the time.LoadLocation() function.

{{ dateFormat "2017/11/2" "2006/01/02" "Jan 2" "America/Chicago" }}

findRe

This function returns the first string match using the regexp package.

{{ findRe "^foo" "foobar" }}

findSubRe

This is similar to findRe, but it returns a slice of strings that match sub-patterns.

{{ findSubRe "^foo(.*)$" "foobar" }}

This would return: ["foobar", "bar"]

floatToInt

Straightforward but sometimes necessary when comparing data types from JSON feeds that are casted with json.UnMarshal()

{{ floatToInt .floatPropertyInFeed }}

inchesToFeet

Simple function that will convert 68 inches to the string 5'8".

{{ inchesToFeet .player.height }}

lower

Returns a string converted to lower case.

{{ lower "John Smith" }}

marshal

Returns a JSON string representation of an object. Like the JavaScript JSON.stringify() function.

{{ marshal .tags }}

minify

The minify functions sends a string through the tdewolff/minify package. The following mimetypes are supported:

  • "text/css"
  • "text/html"
  • "text/javascript"
<style>{{ file "./css/styles.css" | minify "text/css" }}</style>

markdown

This function sends the string through the blackfriday.MarkdownCommon() function and returns parsed HTML as a string.

{{ file "./contents.md" | markdown }}

matchRe

Just like findRe but returns a boolean instead of the matching string

{{ findRe "^foo" "foobar" }}

replace

Passes a string through the strings.Replace function swapping the first match.

{{ replace "http" "https" .url }}

replaceRe

More advanced replacing using the regexp package. This replaces all matching strings in the pattern.

{{ replaceRe "^<div xmlns.*?>" "" .body }}

subtract

Subtracts an int from an int.

{{ subtract 1 $index }}

trim

Trims characters and space from both sides of the string.

{{ trim "/" .link }}

unescape

Runs a string through the url.QueryUnescape() function, which converts each 3-byte encoded substring of the form "%AB" into the hex-decoded byte 0xAB. Useful for urls in feeds.

Note: escape is already available in the Go Template package.

{{ unescape .link }}

upper

Converts a string to uppercase.

{{ upper "huge" }}

Collections

find

This function is based on the Array.find function in javascript. It returns the first value of a sequence that matches (or doesn't match) the comparator.

{{ $josh := find .employees "name" "Josh" }}

or

{{ $awayTeam := find .teams "venue.location" "!=" "home" }}

join

Joins a slice using a separator and returns the string.

{{ join "," .authors }}

pluck

A port of Underscore's pluck function. Uses dot notation to grab nested objects and returns a slice.

{{ pluck "album.title" .relatedWork }}

slice

Pulls a subset of data by index. For example, to range over the first five rows of a csv file use the following code.

{{ range slice . 0 5 }} ... {{ end }}

sort

Sorts a sequence by a path. Ascending and desending order are supported.

{{ range sort .people "name.last" }} ... {{ end }}

or

{{ range sort .people "age" "desc" }} ... {{ end }}

where

A port of Hugo's where function, this returns a filtered slice and is desinged to work with a range. Dot notation is possible.

The default comparator is ==, but you can use any of the following: =, ==, eq, !=, <>, ne, <, lt, >, gt, <=, lte, >=, gte, matches.

matches runs a pattern through the regexp.MatchString() function.

{{ range (where .friends ".name.first" "ne" "John") }}

Scratch

This is a copy of a concept from Hugo. The Go template package is intentionally dumb by design, but that doesn't always work when a JSON feed is created by a third party and time to publication is critical. Variable scope is very tight, so to loosen it up a bit you can use scratch. This lets you maintain global variables and alter them from within loops and conditionals.

It works very much like local storage in the browser, with key/string pairings. There are three functions to get, set and delete a pairing. Unlike Hugo, only strings are supported.

{{ $scratch := scratch }}
{{ $scratch.Set("name", "Jane") }}

{{ if [condition] }}
  {{ $scratch.Set("name", "Gloria") }}
{{ end }}

<h2>Hello, {{ $scratch.Get("name") }}</h2>

Partials

Loopit is designed to make small snippets quickly, but often those snippets can turn into full blown pages that need some DRY tools. Partials allows you to run data through an external template and get a string, which can be further manipulated by the functions in this template.

file

Simply returns file contents as a string. Relative paths are compared to the working directory when the loopit command is run, not relative to the template. This is a tad confusing but allows for maximum flexibility, like common atomic structures for multiple projects. For consistency, I personally use a Makefile.

{{ file "./css/atoms.css" | minify "text/css" }}

partial

Returns contents of a file as a string, but runs data through loopit and includes all functions (except nested partials I haven't figured that one out yet). Just like file, relative paths are compared to the working directory.

{{ partial "./amp-components/amp-img.tmpl" .photo }}

About

A GO program to loop structured data through the template engine

Resources

License

Stars

Watchers

Forks

Packages

No packages published