I am working on a DSL for creating web pages. Something like this (Julia like pseudo-code):
module Html function table(f::Function; args...) # actual implementation here end function tr(f::Function; args...) # actual implementation here end function td(f::Function; args...) # actual implementation here end end
A user would produce code as:
using Html table(border=0) do tr(style="border: 1px solid red") do td() td() end end
Html module provides an API for all HTML5 elements, which is a well defined set (so function are created for each standard element). This allows other packages to extend the
Html API, for instance to provide more advanced
module HtmlX using Html function Html.table(rows::Vector, columns::Vector) # actual implementation here end function Html.table(df::DataFrames.DataFrame) # actual implementation here end end
So all goes well for APIs for working with the standard HTML5 elements. However, the goal is to use
web components, which extend the HTML5 standard with random elements. Like say a
paginated_table. The problem is that
Html can not define a
paginated_table function in advance.
So I tried something like this:
module Html function register_element(elem) Core.eval(@__MODULE__, Meta.parse("function $elem end")) end end
But when running:
module HtmlX Html.register_element("paginated_table") end
Julia complains that I’m evaling in a closed module.
The objective is to have a rich ecosystem of 3rd party packages where users install and use a variety of such external elements. I don’t like the idea of having the elements defined in say 10 modules within a project, as this would be very confusing for the users. An alternative would be for the packages to export their functions but this would lead to an inconsistent API as
Html does not export the functions.
Any ideas or best practices? Thanks!