Skip to content

Commit

Permalink
full project
Browse files Browse the repository at this point in the history
  • Loading branch information
unknown authored and unknown committed Jul 28, 2011
1 parent 7e45608 commit 1cee04d
Show file tree
Hide file tree
Showing 7 changed files with 325 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>jsontpl</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.erlide.core.erlbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.erlide.core.builder.DialyzerBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.erlide.core.erlnature</nature>
</natures>
</projectDescription>
8 changes: 8 additions & 0 deletions .settings/org.erlide.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#Mon Jun 06 01:42:03 MSD 2011
backend_version=R13B
eclipse.preferences.version=1
external_includes=
external_modules=
include_dirs=include;
output_dir=ebin
source_dirs=src;
6 changes: 6 additions & 0 deletions ebin/jsontpl.app
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{application,jsontpl,
[{description,"Erlang Json template Library"},
{vsn,"0.1"},
{modules,[jsontpl,jsontpl_builder,jsontpl_types]},
{registered,[]},
{applications,[kernel,stdlib,sasl]}]}.
6 changes: 6 additions & 0 deletions src/jsontpl.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{application,jsontpl,
[{description,"Erlang Json template Library"},
{vsn,"0.1"},
{modules,[]},
{registered,[]},
{applications,[kernel,stdlib,sasl]}]}.
38 changes: 38 additions & 0 deletions src/jsontpl.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
%%=====================================================================
%% Copyright (c) 2011 Igor Timurov, <t051200@yandex.ru>
%% All Rights Reserved.
%%=====================================================================

-module(jsontpl).

%%
%% Include files
%%

%%
%% Exported Functions
%%
-export([
build/2,
encode/1,
decode/1
]).

%%
%% API Functions
%%

build(Project, FileName) ->
jsontpl_builder:build(Project, FileName).

encode(JsonObject) ->
couchbeam_util:json_encode(JsonObject).

decode(Binary) ->
couchbeam_util:json_decode(Binary).


%%
%% Local Functions
%%

137 changes: 137 additions & 0 deletions src/jsontpl_builder.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
%%=====================================================================
%% Copyright (c) 2011 Igor Timurov, <t051200@yandex.ru>
%% All Rights Reserved.
%%=====================================================================

-module(jsontpl_builder).

%%
%% Include files
%%

%%
%% Exported Functions
%%
-export([build/2]).

%%
%% API Functions
%%
build(Project, FileName) ->
build(Project, FileName, template_list(Project)).

template_list(Project) ->
filelib:fold_files(templates_dir(Project), "\.tpl$", true, fun(F,Acc) -> [F|Acc]end, []).

build(Project, FileName, TplFiles) ->
Templates = lists:foldl(fun open_tpl/2, [], TplFiles),
HrlFileName = filename:join(include_dir(Project), FileName ++ ".hrl"),
{ok, Hrl} = file:open(HrlFileName, [write]),
ErlFileName = filename:join(src_dir(Project), FileName ++ ".erl"),
{ok, Erl} = file:open(ErlFileName, [write]),
io:format(Hrl, "~s", [title()]),
module_title(Erl, FileName),
io:format(Erl, "-export([~s]).~n~n", [export_string(Templates)]),
lists:foreach(
fun(Template) ->
build2(Template, Hrl, Erl)
end, Templates),
file:close(Hrl),
file:close(Erl).

build2(Template, Hrl, Erl) ->
NewTemplaet = convert_template(Template),
define_record(NewTemplaet, Hrl),
define_parser(NewTemplaet, Erl),
define_packer(NewTemplaet, Erl).

define_record({Record, Fields}, Hrl) ->
io:format(Hrl, "-record(~w, {~n", [Record]),
define_record_fields(Fields, Hrl),
io:format(Hrl, "}).~n~n", []).

define_record_fields([], _Hrl) ->
ok;
define_record_fields([{Tag, _, _, Default} | Fields], Hrl) ->
io:format(Hrl, " ~p = ~p~s~n", [Tag, Default, comma(Fields)]),
define_record_fields(Fields, Hrl).

define_parser({Record, Fields}, Erl) ->
io:format(Erl, "~w(JsonObj) ->~n", [Record]),
io:format(Erl, " #~w{~n", [Record]),
define_parser_fields(Fields, Erl),
io:format(Erl, " }.~n~n", []).

define_parser_fields([], _Erl) ->
ok;
define_parser_fields([{Tag, Name, Type, Default} | Fields], Erl) ->
io:format(Erl, " ~s = jsontpl_types:parse(JsonObj, ~p, ~w, ~p)~s~n", [Tag, Name, Type, Default, comma(Fields)]),
define_parser_fields(Fields, Erl).

define_packer({Record, Fields}, Erl) ->
io:format(Erl, "~w(JsonObj0, Object) ->~n", [Record]),
define_packer_fields(Fields, Record, 0, Erl),
io:format(Erl, "~n~n", []).

define_packer_fields([], _Record, Id, Erl) ->
io:format(Erl, " JsonObj~p.", [Id]);
define_packer_fields([{Tag, Name, Type, _Default} | Fields], Record, Id, Erl) ->
NextId = Id+1,
io:format(Erl, " JsonObj~p = jsontpl_types:pack(JsonObj~p, ~p, ~p, Object#~s.~s),~n", [NextId, Id, Name, Type, Record, Tag]),
define_packer_fields(Fields, Record, NextId, Erl).

%%
%% Local Functions
%%

convert_template({Record, Fields}) ->
{Record, lists:map(fun({_Tag, _Name, _Type, _Default} = A) -> A;
({Tag, Type, Default}) -> {Tag, atom_to_binary(Tag, latin1), Type, Default} end, Fields)}.

open_tpl(File, Acc) ->
try
{ok, FileTemplates} = file:consult(File),
Acc ++ FileTemplates
catch
error:Reason ->
io:format("error: ~p~nfile: ~p~n", [Reason, File]),
Acc
end.

title() ->
"%% Author: Jsontpl compiler\n"
"%% Description:\n"
"%% This file was generated.\n"
"%% DO NOT EDIT IT DIRECTLY!\n\n".

module_title(Erl, ModuleName) ->
io:format(Erl, "~s", [title()]),
io:format(Erl, "-module(~s).~n~n", [ModuleName]),
io:format(Erl, "-include(\"~s.hrl\").~n~n", [ModuleName]).

app_dir(Project) ->
code:lib_dir(Project).

templates_dir(Project) ->
filename:join(priv_dir(Project), "jsontpl").

include_dir(Project) ->
filename:join(app_dir(Project), "include").

priv_dir(Project) ->
code:priv_dir(Project).

src_dir(Project) ->
filename:join(app_dir(Project), "src").

comma([]) ->
"";
comma(_List) ->
",".

export_string(Templates) ->
RecordStrings = ["\n " ++ atom_to_list(Record) ++ "/1," ++
"\n " ++ atom_to_list(Record) ++ "/2"
|| {Record, _Fields} <- Templates],
string:join(RecordStrings, ",") ++ "\n".

108 changes: 108 additions & 0 deletions src/jsontpl_types.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
%%=====================================================================
%% Copyright (c) 2011 Igor Timurov, <t051200@yandex.ru>
%% All Rights Reserved.
%%=====================================================================

-module(jsontpl_types).

%%
%% Include files
%%

%%
%% Exported Functions
%%
-export([
parse/4,
pack/4
]).

%%
%% API Functions
%%

parse(JsonObj, Key, Type, Default) ->
Value = couchbeam_doc:get_value(Key, JsonObj),
to_type(Type, Value, Default).

pack(JsonObj, _Key, _Type, null) ->
JsonObj;
pack(JsonObj, _Key, _Type, undefined) ->
JsonObj;
pack(JsonObj, Key, Type, Data) ->
Value = from_type(Type, Data),
couchbeam_doc:set_value(Key, Value, JsonObj).

%%
%% Local Functions
%%

from_type(any, Value) ->
Value;
from_type(bool, Value) when is_boolean(Value) ->
Value;
from_type(float, Value) when is_float(Value) ->
Value;
from_type(integer, Value) when is_integer(Value) ->
Value;
from_type(atom, Value) when is_atom(Value) ->
atom_to_binary(Value, latin1);
from_type(string, Value) when is_binary(Value) ->
Value;
from_type(string, Value) when is_integer(Value) ->
list_to_binary(integer_to_list(Value));
from_type(string, Value) when is_float(Value) ->
list_to_binary(float_to_list(Value));
from_type(string, Value) when is_atom(Value) ->
atom_to_binary(Value, latin1);
from_type(jsonstring, Value) when is_binary(Value) ->
jsontpl:decode(Value);
from_type({hash, _Size}, Value) when is_integer(Value) ->
Value;
from_type({tpl, Module, Fun}, Value) ->
Module:Fun({[]}, Value);
from_type([Type], List) when is_list(List) ->
[from_type(Type, Item) || Item <- List];
from_type({_LeftType, RightType}, {LeftItem, RightItem}) ->
{from_type(string, LeftItem), from_type(RightType, RightItem)}.

%% trivial type
to_type(_Type, null, Default) ->
Default;
to_type(_Type, undefined, Default) ->
Default;
to_type(any, Value, _Default) ->
Value;
to_type(bool, Value, _Default) when is_boolean(Value) ->
Value;
to_type(bool, <<"true">>, _Default) ->
true;
to_type(bool, <<"false">>, _Default) ->
false;
to_type(float, Value, _Default) when is_number(Value) ->
float(Value);
to_type(float, Value, _Default) when is_binary(Value) ->
list_to_float(binary_to_list(Value));
to_type(integer, Value, _Default) when is_number(Value) ->
round(Value);
to_type(integer, Value, _Default) when is_binary(Value) ->
list_to_integer(binary_to_list(Value));
to_type(atom, Value, _Default) when is_binary(Value) ->
binary_to_atom(Value, latin1);
to_type(atom, Value, _Default) when is_atom(Value) ->
Value;
to_type(string, Value, _Default) when is_binary(Value) ->
Value;
to_type(jsonstring, Value, _Default) ->
iolist_to_binary(jsontpl:encode(Value));
%% complex type
to_type({tpl, Module, Fun}, Value, _Default) ->
Module:Fun(Value);
to_type({hash, Size}, Value, _Default) ->
erlang:phash2(Value, Size);
to_type([Type], List, Default) when is_list(List) ->
[to_type(Type, Item, Default) || Item <- List];
to_type([Type], {List}, Default) when is_list(List) ->
[to_type(Type, Item, Default) || Item <- List];
to_type({LeftType, RightType}, {LeftItem, RightItem}, Default) ->
{to_type(LeftType, LeftItem, Default), to_type(RightType, RightItem, Default)}.

0 comments on commit 1cee04d

Please sign in to comment.