Skip to content

Commit

Permalink
Added support for .hrl files and tidied up naming conventions etc
Browse files Browse the repository at this point in the history
  • Loading branch information
hypernumbers committed Sep 18, 2013
1 parent df94bf6 commit 6bbf392
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 74 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ deps
*.plt
*~
ebin/
md/.erl/*
md/.erl
src/
include/
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The Literate Erlang, like Literate CoffeeScript is blocks of Markdown interpolat

The Literate Erlang compiler is implemented as a ``rebar`` plugin. For more details of ``rebar`` and its role in Erlang development see https://github.com/rebar/rebar.

Literate Erlang files end with ``.erl.md`` and are stored in the ``/md`` directory alonside the ``/src`` directory as part of a normal Erlang/OTP file structure. See the section on directory structure in the Erlang Design principles document http://www.erlang.org/doc/design_principles/applications.html#id73971
Literate Erlang files end with ``.erl.md`` or ``.hrl.md`` and are stored in the ``/src_md`` and ``/include_md`` directories alonside the ``/src`` and ``/include`` directories as part of a normal Erlang/OTP file structure. See the section on directory structure in the Erlang Design principles document http://www.erlang.org/doc/design_principles/applications.html#id73971

The compiler is implemented as a rebar pluging - the source code for it is in the directory ``/priv/rebar_plugins``.

Expand All @@ -28,7 +28,7 @@ The compiler works by transforming the Literate Erlang to plain erlang and then
Usage
-----

Write your literate-erlang files in the directory ``/md`` naming them like ``mymodule.erl.md``
Write your literate-erlang files in the directory ``/src_md`` naming them like ``mymodule.erl.md``. Header files are written in ``/include_md`` and named ``myheder.hrl.md``.

Compile them to normal erlang using:
``rebar literate-compile``
Expand All @@ -49,20 +49,19 @@ Implementation

The reverse compiler implmented as a ``rebar`` plugin called ``markup``.

This turns all files ending ``.erl`` in the ``src/`` into markdown files which are placed in an `md/` directory.
This turns all files ending ``.erl`` in the ``/src_md/.erl`` directory into markdown files which are placed in an `/src_md` directory and all ``.hrl`` files in ``include_md/.hrl`` directory into ``.hrl.md`` filed in ``/include_md``.

Usage
-----

The canonical version under version control is the markdown files in the ``md/`` directory. So the first step is to compile them to erlang:
The canonical version under version control is the markdown files in the ``src_md/`` directory. So the first step is to compile them to erlang:
``rebar compile_literate``

Then copy the ``.erl`` files to the directory ``md/.erl`` and edit them there.
Then copy the ``.erl`` files to the directory ``src_md/.erl`` and the `..hrl`` files to ``/include_md/.hrl`` and edit them there.

The production of working beam files is then:
``rebar markup``
``rebar literate_compile``
``rebar compile``

Baby Steps
==========
Expand Down
5 changes: 5 additions & 0 deletions include_md/.hrl/test2.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
%%% Another testing record
-record(banjo, {
rupert = dict:new() :: dict(),
bennie
}).
9 changes: 9 additions & 0 deletions include_md/test.hrl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
This is the .hrl file for testing

```erlang
-record(test, {
bish = [] :: list(),
bosh = [] :: list()
}).
```
Which is nice
42 changes: 30 additions & 12 deletions priv/rebar_plugins/compile_literate.erl
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@
compile_literate(Config, _AppFile) ->
ErlOpts = rebar_config:get(Config, erl_opts, []),
SrcDirs = get_src_dirs(ErlOpts),
ok = clear_down(SrcDirs),
CompilerOptions = get_compiler_options(ErlOpts),
Files = [filelib:wildcard(X ++ "/../md/*.erl.md") || X <- SrcDirs],
[ok = compile_file(X, CompilerOptions) || X <- lists:merge(Files)],
ErlFiles = [filelib:wildcard(X ++ "/../src_md/*.erl.md") || X <- SrcDirs],
[ok = compile_file(X, CompilerOptions, erl) || X <- lists:merge(ErlFiles)],
HrlFiles = [filelib:wildcard(X ++ "/../include_md/*.hrl.md") || X <- SrcDirs],
[ok = compile_file(X, CompilerOptions, hrl) || X <- lists:merge(HrlFiles)],
ok.

compile_file(File, CompilerOptions) ->
compile_file(File, CompilerOptions, Type) ->
CWD = rebar_utils:get_cwd(),
{ok, Lines} = read_lines(CWD ++ "/" ++ File),
Source = make_erlang_source(Lines),
ok = write_source_and_compile(Source, File, CompilerOptions).
ok = write_source_and_compile(Source, File, CompilerOptions, Type).

make_erlang_source(Lines) ->
make_erl2(Lines, comment, []).
Expand All @@ -41,7 +44,7 @@ make_erl3(["\n" | T], erlang, Acc) ->
make_erl3([" " ++ Rest | T], erlang, Acc) ->
make_erl3(T, erlang, [Rest | Acc]);
make_erl3(["```" ++ _Rest | T], erlang, Acc) ->
make_erl2(T, comment, ["\n" | Acc]);
make_erl2(T, comment, ["%%%```\n" | Acc]);
%% Oops, not indented? lets comment out then
make_erl3(List, erlang, Acc) ->
make_erl2(List, comment, Acc).
Expand All @@ -68,18 +71,25 @@ get_src_dirs(ErlOpts) ->
get_compiler_options(ErlOpts) ->
proplists:delete(src_dirs, ErlOpts).

write_source_and_compile(Source, File, CompilerOptions) ->
write_source_and_compile(Source, File, CompilerOptions, Type) ->
File2 = filename:basename(filename:rootname(File)),
Dir = filename:dirname(File),
NewCompOpts = adjust_output_dirs(CompilerOptions, Dir),
Dir2 = Dir ++ "/../src/",
Dir2 = case Type of
erl -> Dir ++ "/../src/";
hrl -> Dir ++ "/../include/"
end,
ok = filelib:ensure_dir(Dir2),
ok = file:write_file(Dir2 ++ File2, Source),
case compile:file(Dir2 ++ File2, NewCompOpts) of
{ok, _} -> ok;
error -> io:format("Compile of ~p failed~n", [File])
end,
ok.
%% now compile the .erl files
case Type of
erl -> case compile:file(Dir2 ++ File2, NewCompOpts) of
{ok, _} -> ok;
error -> io:format("Compile of ~p failed~n", [File])
end,
ok;
hrl -> ok
end.

adjust_output_dirs(CompilerOptions, Dir) ->

Expand All @@ -92,3 +102,11 @@ adjust_output_dirs(CompilerOptions, Dir) ->
CompilerOptions
end.

clear_down(SrcDirs) ->
WildCards = lists:merge([[
X ++ "/../include/*",
X ++ "/../src/*"
] || X <- SrcDirs]),
Files = lists:merge([filelib:wildcard(X) || X <- WildCards]),
[ok = file:delete(X) || X <- Files],
ok.
29 changes: 20 additions & 9 deletions priv/rebar_plugins/markup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,28 @@
markup(Config, _AppFile) ->
ErlOpts = rebar_config:get(Config, erl_opts, []),
SrcDirs = get_src_dirs(ErlOpts),
Files = lists:merge([filelib:wildcard(X ++ "/../md/.erl/*.erl") || X <- SrcDirs]),
io:format("Files is ~p~n", [Files]),
ErlFiles = get_files(SrcDirs, erl),
HrlFiles = get_files(SrcDirs, hrl),
[ok = markup_to_literate(X, erl) || X <- ErlFiles],
[ok = markup_to_literate(X, hrl) || X <- HrlFiles],
ok.

get_files(SrcDirs, Type) ->
WildCards = case Type of
erl -> "/../src_md/.erl/*.erl";
hrl -> "/../include_md/.hrl/*.hrl"
end,
Files = lists:merge([filelib:wildcard(X ++ WildCards) || X <- SrcDirs]),
FilterFun = fun(X) ->
not filelib:is_dir(X)
end,
Files2 = lists:filter(FilterFun, Files),
[ok = markup_to_literate(X) || X <- Files2],
ok.
lists:filter(FilterFun, Files).

markup_to_literate(File) ->
markup_to_literate(File, Type) ->
CWD = rebar_utils:get_cwd(),
{ok, Lines} = read_lines(CWD ++ "/" ++ File),
Source = make_markdown_source(Lines),
ok = write_source(Source, File).
ok = write_source(Source, File, Type).

make_markdown_source(Lines) ->
make_markdown(Lines, []).
Expand Down Expand Up @@ -87,9 +95,12 @@ get_src_dirs(ErlOpts) ->
SrcDirs -> SrcDirs
end.

write_source(Source, File) ->
write_source(Source, File, Type) ->
File2 = filename:basename(File) ++ ".md",
Dir = filename:dirname(File) ++ "/../../md/",
Dir = case Type of
erl -> filename:dirname(File) ++ "/../../src_md/";
hrl -> filename:dirname(File) ++ "/../../include_md/"
end,
ok = filelib:ensure_dir(Dir),
ok = file:write_file(Dir ++ File2, Source).

Expand Down
45 changes: 0 additions & 45 deletions src/util2.erl

This file was deleted.

49 changes: 49 additions & 0 deletions src_md/.erl/util2.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
%%% -----------------------------------------------------------------------------
%%% File util2.erl
%%% @author Gordon Guthrie <gordonguthrie@vixo.com>
%%% @doc
%%% @copyright Hypernumbers Ltd
%%% @private
%%%
%%% Created 22 Nov 2006 by Gordon Guthrie <gordonguthrie@vixo.com>
%%% -----------------------------------------------------------------------------
%%%```erlang
-module(util2).

-export([
timestamp_to_date/1,
get_timestamp/0
]).

-define(MEGA, 1000000000000).
-define(SEC, 1000000).


%%% -----------------------------------------------------------------------------
%%%
%%% Worker functions for the util2
%%% There are two util files cos you can't load one with try/catch into the
%%% debugger (ie that one)
%%%
%%% -----------------------------------------------------------------------------
%%%
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% %%%
%%% These functions are all utility functions %%%
%%% %%%
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%%```erlang
-spec get_timestamp() -> pos_integer().
get_timestamp()->
{Mega, Sec, Micro} = now(),
?MEGA * Mega + ?SEC * Sec + Micro.

timestamp_to_date(Stamp) when is_list(Stamp) ->
timestamp_to_date(list_to_integer(Stamp));
timestamp_to_date(Stamp) when is_integer(Stamp) ->
Mega = trunc(Stamp/?MEGA),
Sec = trunc((Stamp - Mega * ?MEGA)/?SEC),
Micro = Stamp - Mega * ?MEGA - Sec * ?SEC,
{Mega, Sec, Micro}.

File renamed without changes.

0 comments on commit 6bbf392

Please sign in to comment.