Projects: Category Archive (Page 4)

Posts about software development projects from or maintained by Bit Badger Solutions

Saturday, September 9, 2017
  Writing a Hexo Tag Plugin

In the process of migrating Daniel's Weekly Devotions to Hexo, we ran into a problem that we felt sure a tag plugin could solve.

The Problem

Jekyll's Markdown parser follows the original one, where text within an HTML tag is not processed. This can be the desired behavior in many cases, as you could put what would otherwise be translated as Markdown between HTML tags, and the parser/renderer will leave it alone. One of the common features, used multiple times in most posts, are links to Scripture references and blocks of quoted text. We had an include to automate the links, but we needed a special class on the <blockquote> tag, which meant that all Scripture blockquotes could not use Markdown (or end up with “smartified” quotes and such; we had to use the HTML entities within these quotes.) We also included the verse numbers as superscripts within the quoted text; more tags.

It looked something like this… (the “ref” CSS class turns the text red)

<blockquote class="bible">
  <p>
    <sup>11</sup> …And Jesus said, <span class="ref">“Neither do I condemn you;
    go, and from now on sin no more.”</span>
  </p>
  <cite><a href="https://www.biblegateway.com/passage/?search=John+8:11&version=ESV"
    title="Read John 8:11 (ESV) at Bible Gateway">John 8:11</a>b <em>(ESV)</em></cite>
</blockquote>

If you've ever edited Markdown, you'll recognize how jarring all that HTML code is within the flow of the otherwise-regular text; and look at all those entities!

The Solution

We looked through at the Hexo Plugin List to find some examples, and began working towards writing a plugin to handle both the links (the part within the <cite> in the example above) as well as the entire blocks of quoted text. Some tags, like the {% codeblock %} tag, have a start tag and an end tag ({% endcodeblock %}); others, like the {% youtube %} tag, just pass arguments with the tag. (You can see all the default tags here.) Hexo passes two arguments to the tag plugin - the arguments within the (start) tag, plus the content (which is blank for tags that don't have an end tag). The returned value from the plugin call is substituted in the document.

For generating a link, that is pretty easy; it could be an inline tag, and it's just a matter of parsing the arguments and forming a link. For the quotes, we need to make sure that we include the content, and Hexo provides a way to run that content through the Markdown renderer. We are converging on a solution!

Hexo will pick up and execute any .js files in the scripts directory of the site as its generating it, so the first efforts were just local to that repo. The reference link looked something like this…

hexo.extend.tag.register('esv', (args, content) => {
  // option parsing with RegEx, similar to the way their tags do

  let reference = arg.trim()
  let urlReference = reference.split(' ').join('+')

  return `<a href="https://www.biblegateway.com/passage/?search=${urlReference}&version=${version}" `
    + `title="Read ${reference} (${version}) at Bible Gateway">${reference}</a>${extraText}${versionText}`
})

...which let the Markdown document go from…

<a href="https://www.biblegateway.com/passage/?search=John+8:11&version=ESV"
  title="Read John 8:11 (ESV) at Bible Gateway">John 8:11</a>b <em>(ESV)</em>

...to…

{% esv John 8:11 extra:b show-version %}

We refactored the link code to be version-agnostic and extracted it from the tag.register function so that we could reuse that for the blockquote citation. This made the local version of the blockquote look something like this:

hexo.extend.tag.register('bible', (args, content) => {
  let text = hexo.render.renderSync({ text: content, engine: 'markdown' })
  return `<blockquote class="bible">${text}<cite>— ${generateRef(args)}</cite></blockquote>`
})

This means that the blockquote can support all of the arguments the inline reference did. We also switched out the marked Markdown processor for the markdown-it one, which lets us do superscripts by using the ^ character. Revisiting our example under “The Problem,” our Markdown source to generate the same blockquote is now:

{% bible John 8:11 extra:b show-version %}
^11^...And Jesus said, <span class="ref">"Neither do I condemn you; go, and from
now on sin no more."</span>
{% endbible %}

The Plugin

The plugin is available on npm, is fully tested, and its source is open. If you use Hexo, and wish to cite Scripture references in your posts with links where readers can see the text for themselves - enjoy!

Categorized under ,
Tagged , , , ,

Saturday, October 22, 2011
  Database Abstraction v0.8

When we began developing C# web applications, we found ourselves in the position of determining what the best way of accessing the database is. We evaluated several technologies…

  • NHibernate - May be very good, but it was overkill for what we were trying to do.
  • LINQ to SQL - This brings C#'s LINQ (Language-Integrated Query) to SQL databases. You create database-aware classes and use LINQ to select from collections, which LINQ to SQL converts to database access. This is a good abstraction, but it relies on SQL Server; as we typically deploy to PostgreSQL, this didn't work. (We also couldn't get DBLinq, a database-agnostic implementation, to work.)
  • ADO.NET - This is the tried-and-true database access methodology, released as part of the initial release of the .NET framework. The downside to this is that it encourages SQL in the code at the point of data retrieval; it does not provide a clean separation of data access from data processing.
  • EF Code First - This didn't exist; it's also very SQL Server-centric. Not faulting Microsoft for that, especially since they release a free version now; but, as we deploy on Linux, until they release a Linux version, SQL Server is not an option.

With our PHP applications, we had written a database service that read queries from XML files. Then, queries were accessed by name, with parameters passed via arrays. The one thing that ADO.NET has that was useful was the fact that it is based on interfaces. This means that if we wrote something that exposed, manipulated, and depended on IDataConnection (instead of SqlConnection, the SQL Server implementation of that interface), we could support any implementation of database. The SqlDataReader implements IDataReader as well. Our solution was becoming apparent.

Over time, we developed what is now the Database Abstraction project hosted on CodePlex (UPDATE: migrated project to GitHub). On Thursday, we released the first public release (although the DLLs are in the repository, and are usually current at every commit). If you are looking for a way to separate your data access from the rest of your code, or want a solution that's database-agnostic, check it out. It supports SQL Server, MySQL, PostgreSQL, SQLite, and ODBC connections *, using the data provider name to derive the proper connection to implement. There is also a Mock implementation to support unit tests; this mock can provide data, providing a useful way to test methods. Finally, there is a membership and role provider based on Database Abstraction; simply configure the connection string, create the database tables, and away you go! **

A pre-release version is already in production use in our PrayerTracker application, and others are being built around it. If this sounds like something that could help your project, certainly feel free to check it out!

* Oracle is omitted from this list, as their DLL had redistribution restrictions; this meant that the source code repository, upon check-out, would have build errors. There may be an Oracle implementation in the future (it would be trivial), but there is not one now.

** The membership and role providers are untested; they will be tested and tweaked by version 0.9.

Categorized under , , , , ,
Tagged , , , , ,