Skip to content
This repository has been archived by the owner on Jan 12, 2023. It is now read-only.

Commit

Permalink
rec_fun, field_fun and const added
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Jonas committed Jan 31, 2014
1 parent d36ec5b commit b3a34f1
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 49 deletions.
52 changes: 34 additions & 18 deletions src/ejson.erl
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,13 @@ conv(Tuple, Options) when is_tuple(Tuple) ->
%% Convert each values
lists:reverse(
lists:foldl(
fun({{list, Name}, Value}, Acc) ->
[{list_to_binary(Name), conv_list(Value, Options)} | Acc];
({{proplist, Name}, Value}, Acc) ->
[{list_to_binary(Name), conv_proplist(Value, Options)} | Acc];
({skip, _Value}, Acc) ->
Acc;
({{pre, Name, {Mod, Fun}}, _Value}, Acc) ->
Value = erlang:apply(Mod, Fun, [Tuple]),
[{list_to_binary(Name), conv(Value, Options)} | Acc];
({{const, Name, Value}, _ReplacedValue}, Acc) ->
[{list_to_binary(Name), conv(Value, Options)} | Acc];
({Name, Value}, Acc) ->
[{list_to_binary(Name), conv(Value, Options)} | Acc]
fun({Rule, Value}, Acc) ->
case apply_rule(Rule, Tuple, Value, Options) of
{AttrName, AttrValue} ->
[{list_to_binary(AttrName), AttrValue} | Acc];
undefined ->
Acc
end
end,
[],
zip(FieldNames, Vals)));
Expand All @@ -110,9 +104,29 @@ conv(Pid, _) when is_pid(Pid) ->
list_to_binary(pid_to_list(Pid)).


conv_list(List, Options) ->
[conv(L, Options) || L <- List].

conv_list(List, Options) when is_list(List) ->
[conv(L, Options) || L <- List];
conv_list(List, _Options) ->
throw({error, {not_a_list, List}}).

apply_rule({list, Name}, _Record, Value, Options) ->
List = conv_list(Value, Options),
{Name, List};
apply_rule({proplist, Name}, _Record, Value, Options) ->
PropList = conv_proplist(Value, Options),
{Name, PropList};
apply_rule(skip, _Record, _Value, _Options) ->
undefined;
apply_rule({field_fun, Name, {M, F}}, _Record, Value, Options) ->
Value2 = erlang:apply(M, F, [Value]),
{Name, conv(Value2, Options)};
apply_rule({rec_fun, Name, {M, F}}, Record, _Value, Options) ->
Value2 = erlang:apply(M, F, [Record]),
{Name, conv(Value2, Options)};
apply_rule({const, Name, Const}, _Record, _Value, Options) ->
{Name, conv(Const, Options)};
apply_rule(Name, _Record, Value, Options) ->
{Name, conv(Value, Options)}.

%%-----------------------------------------------------------------------------
%% @doc
Expand All @@ -122,7 +136,7 @@ conv_list(List, Options) ->
%% each key, convert the atom key into camel-cased name.
%% @end
%%-----------------------------------------------------------------------------
conv_proplist(List, Options) ->
conv_proplist(List, Options) when is_list(List) ->
Keys = proplists:get_keys(List),
lists:map(
fun(Key) ->
Expand All @@ -133,7 +147,9 @@ conv_proplist(List, Options) ->
{camel_case(Key), conv_list(Vals, Options)}
end
end,
Keys).
Keys);
conv_proplist(List, _Options) ->
throw({error, {not_a_proplist, List}}).

camel_case(Atom) ->
list_to_binary(lists:reverse(camel_case(atom_to_list(Atom), []))).
Expand Down
52 changes: 30 additions & 22 deletions test/ejson_basic_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,71 @@

-ifdef(TEST).

-import(ejson, [camel_case/1, conv/2, json_prop/2, zip/2]).

-include_lib("eunit/include/eunit.hrl").

zip_test() ->
?assertEqual([{undefined, 1}], ejson:zip([], [1])),
?assertEqual([{2, 1}, {3, undefined}], ejson:zip([2, 3], [1])),
?assertEqual([], ejson:zip([], [])),
?assertEqual([{1, 2}, {3, 4}], ejson:zip([1, 3], [2, 4])).
?assertEqual([{undefined, 1}], zip([], [1])),
?assertEqual([{2, 1}, {3, undefined}], zip([2, 3], [1])),
?assertEqual([], zip([], [])),
?assertEqual([{1, 2}, {3, 4}], zip([1, 3], [2, 4])).

camel_case_test() ->
?assertEqual(<<"simple">>, ejson:camel_case(simple)),
?assertEqual(<<"xAxis">>, ejson:camel_case(x_axis)).
?assertEqual(<<"simple">>, camel_case(simple)),
?assertEqual(<<"xAxis">>, camel_case(x_axis)).

conv_atom_test() ->
Options = [{weather, ["month", "value"]}],

J = ejson:conv({weather, january, snowing}, Options),
J = conv({weather, january, snowing}, Options),

?assertEqual(<<"january">>, ejson:json_prop(J, "month")),
?assertEqual(<<"snowing">>, ejson:json_prop(J, "value")).
?assertEqual(<<"january">>, json_prop(J, "month")),
?assertEqual(<<"snowing">>, json_prop(J, "value")).

conv_pid_test() ->
Options = [{procs, ["sup"]}],
Bin = list_to_binary(pid_to_list(self())),

J = ejson:conv({procs, self()}, Options),
J = conv({procs, self()}, Options),

?assertEqual(Bin, json_prop(J, "sup")).

undef_test() ->
Options = [{nullable, ["object"]}],

?assertEqual(Bin, ejson:json_prop(J, "sup")).
J = conv({nullable, undefined}, Options),
?assertEqual(null, json_prop(J, "object")).

bool_test() ->
Options = [{bool, ["value"]}],

J1 = ejson:conv({bool, true}, Options),
J2 = ejson:conv({bool, false}, Options),
J1 = conv({bool, true}, Options),
J2 = conv({bool, false}, Options),

?assertEqual(true, ejson:json_prop(J1, "value")),
?assertEqual(false, ejson:json_prop(J2, "value")).
?assertEqual(true, json_prop(J1, "value")),
?assertEqual(false, json_prop(J2, "value")).

number_test() ->
Options = [{complex, ["r", "i"]}],

J = ejson:conv({complex, -35, 809}, Options),
J = conv({complex, -35, 809}, Options),

?assertEqual(-35, ejson:json_prop(J, "r")),
?assertEqual(809, ejson:json_prop(J, "i")).
?assertEqual(-35, json_prop(J, "r")),
?assertEqual(809, json_prop(J, "i")).

binary_test() ->
Options = [{text, ["value"]}],

J = ejson:conv({text, <<"A binary as is">>}, Options),
J = conv({text, <<"A binary as is">>}, Options),

?assertEqual(<<"A binary as is">>, ejson:json_prop(J, "value")).
?assertEqual(<<"A binary as is">>, json_prop(J, "value")).

string_test() ->
Options = [{message, ["text"]}],

J = ejson:conv({message, "Texting something"}, Options),
J = conv({message, "Texting something"}, Options),

?assertEqual(<<"Texting something">>, ejson:json_prop(J, "text")).
?assertEqual(<<"Texting something">>, json_prop(J, "text")).

-endif.
58 changes: 49 additions & 9 deletions test/ejson_list_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

-ifdef(TEST).

-import(ejson, [conv/2, json_prop/2]).

-include_lib("eunit/include/eunit.hrl").

list_test() ->
Expand All @@ -12,26 +14,64 @@ list_test() ->
Book2 = {book, "TDD - the easy way", 760},
Person = {person, "Sam", [Book1, Book2]},

J = ejson:conv(Person, Options),
J = conv(Person, Options),

?assertEqual(<<"Sam">>, ejson:json_prop(J, "name")),
?assertEqual(<<"Sam">>, json_prop(J, "name")),

Bs = ejson:json_prop(J, "books"),
Bs = json_prop(J, "books"),
[B1, B2 ] = Bs,

?assertEqual(2, length(Bs)),
?assertEqual(<<"Introduction to clean coding">>,
ejson:json_prop(B1, "title")),
?assertEqual(251, ejson:json_prop(B1, "numberOfPages")),
?assertEqual(<<"TDD - the easy way">>, ejson:json_prop(B2, "title")),
?assertEqual(760, ejson:json_prop(B2, "numberOfPages")).
?assertEqual(<<"Introduction to clean coding">>, json_prop(B1, "title")),
?assertEqual(251, json_prop(B1, "numberOfPages")),
?assertEqual(<<"TDD - the easy way">>, json_prop(B2, "title")),
?assertEqual(760, json_prop(B2, "numberOfPages")).

proplist_test() ->
Square = {shape, square, [{a, 10}]},
Circle = {shape, circle, [{radius, 5}]},
Rect = {shape, rect, [{x_left, 10}, {y_left, 15},
{x_right, 50}, {y_right, 30}]},

Options = [{shape, ["type", {proplist, "data"}]}].
Options = [{shape, ["type", {proplist, "data"}]},
{shapes, [{list, "shapes"}]}],

Shapes = conv({shapes, [Square, Circle, Rect]}, Options),

Ss = json_prop(Shapes, "shapes"),
?assertEqual(3, length(Ss)),

[S1, S2, S3] = Ss,

?assertEqual(<<"square">>, json_prop(S1, "type")),
S1d = json_prop(S1, "data"),
?assertEqual(10, json_prop(S1d, "a")),

?assertEqual(<<"circle">>, json_prop(S2, "type")),
S2d = json_prop(S2, "data"),
?assertEqual(5, json_prop(S2d, "radius")),

?assertEqual(<<"rect">>, json_prop(S3, "type")),
S3d = json_prop(S3, "data"),
?assertEqual(10, json_prop(S3d, "xLeft")),
?assertEqual(15, json_prop(S3d, "yLeft")),
?assertEqual(50, json_prop(S3d, "xRight")),
?assertEqual(30, json_prop(S3d, "yRight")).

list_error_test() ->
Opts = [{book, ["title", {list, "authors"}]}],

?assertThrow({error, {not_a_list, _}}, conv({book, "Title", 12}, Opts)).

proplist_error_test() ->
Opts = [{canvas, [{proplist, "props"}]}],

?assertThrow({error, {not_a_proplist, _}}, conv({canvas, 12}, Opts)).

many_prop_test() ->
Opts = [{canvas, [{proplist, "props"}]}],

J = conv({canvas, [{a, 2}, {a, 3}]}, Opts),
?assertEqual([2, 3], json_prop(json_prop(J, "props"), "a")).

-endif.
44 changes: 44 additions & 0 deletions test/ejson_preprocess_test.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
-module(ejson_preprocess_test).

-ifdef(TEST).

-import(ejson, [conv/2, json_prop/2]).

-include_lib("eunit/include/eunit.hrl").

field_fun_enc_test() ->
Opts = [{rect, [{field_fun, "a", {?MODULE, rect_field_conv}},
{field_fun, "b", {?MODULE, rect_field_conv}}]
}],

J = conv({rect, 3, 5}, Opts),

?assertEqual(30, json_prop(J, "a")),
?assertEqual(50, json_prop(J, "b")).

rec_fun_enc_test() ->
Opts = [{rect, ["a", "b", {rec_fun, "area", {?MODULE, rect_area}}]}],

J= conv({rect, 8, 12}, Opts),

?assertEqual(8, json_prop(J, "a")),
?assertEqual(12, json_prop(J, "b")),
?assertEqual(96, json_prop(J, "area")).

const_test() ->
Opts = [{dummy, [{const, "file", {file, "erl", "sh"}}]},
{file, ["name", "ext"]}],

J = conv({dummy, "whatever"}, Opts),
File = json_prop(J, "file"),

?assertEqual(<<"erl">>, json_prop(File, "name")),
?assertEqual(<<"sh">>, json_prop(File, "ext")).

rect_field_conv(A) ->
A * 10.

rect_area({rect, A, B}) ->
A * B.

-endif.
18 changes: 18 additions & 0 deletions test/ejson_skip_test.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-module(ejson_skip_test).

-ifdef(TEST).

-import(ejson, [conv/2, json_prop/2]).

-include_lib("eunit/include/eunit.hrl").

skip_test() ->
Opts = [{request, [skip, "path", skip, "method"]}],

J = conv({request, "Socket info", "/index.html", self(), "GET"}, Opts),

?assertEqual(<<"/index.html">>, json_prop(J, "path")),
?assertEqual(<<"GET">>, json_prop(J, "method")),
?assertEqual(2, length(J)).

-endif.

0 comments on commit b3a34f1

Please sign in to comment.