221V 1 год назад
Родитель
Сommit
d7f0e3fbea
5 измененных файлов с 127 добавлено и 87 удалено
  1. 14 2
      example/src/rest_users.erl
  2. 75 65
      src/rest.erl
  3. 4 1
      src/rest_app.erl
  4. 26 17
      src/rest_cowboy.erl
  5. 8 2
      src/rest_sup.erl

+ 14 - 2
example/src/rest_users.erl

@@ -1,16 +1,28 @@
 -module(rest_users).
 -compile({parse_transform, rest}).
+
 -export([init/0, populate/1, new/0, exists/1, get/0, get/1, post/1, delete/1]).
 
 -record(user, {id, cn, name, type}).
 -rest_record(user).
 
+
 new()                -> #user{}.
 init()               -> ets:new(users, [public, named_table, {keypos, #user.id}]).
 populate(Users)      -> ets:insert(users, Users).
-exists(Id)           -> X = ets:member(users, erlang:binary_to_list(Id)), io:format("Member: ~p~n", [X]), X.
+
+exists(Id)           ->
+  X = ets:member(users, erlang:binary_to_list(Id)),
+  io:format("Member: ~p~n", [X]),
+  X.
+
 get()                -> ets:tab2list(users).
-get(Id)              -> [U] = ets:lookup(users, erlang:binary_to_list(Id)), io:format("User: ~p~n", [U]), U.
+
+get(Id)              ->
+  [U] = ets:lookup(users, erlang:binary_to_list(Id)),
+  io:format("User: ~p~n", [U]),
+  U.
+
 delete(Id)           -> ets:delete(users, erlang:binary_to_list(Id)).
 post(#user{} = User) -> ets:insert(users, User);
 post(Data)           -> post(from_json(Data, #user{})).

+ 75 - 65
src/rest.erl

@@ -48,7 +48,7 @@ findType([_H|T]) ->
 
 record_fields(_RecordName, []) -> [];
 record_fields(RecordName, [{attribute, _, record, {RecordName, Fields}} | _Forms]) ->
-    [record_field(Field, RecordName) || Field <- Fields];
+  [record_field(Field, RecordName) || Field <- Fields];
 record_fields(RecordName, [_ | Forms]) -> record_fields(RecordName, Forms).
 
 last_export_line(Exports) ->
@@ -58,88 +58,97 @@ last_export_line(Exports) ->
   end.
 
 generate({FunName, _Arity} = Fun, Record, Fields, Forms) ->
-    Exports = lists:filter(fun({attribute, _, export, _}) -> true; (_) -> false end, Forms),
-    case exported(Fun, Exports) of
-        true  -> Forms;
-        false ->
-            Line = last_export_line(Exports),
-            Gen = list_to_atom("generate_" ++ atom_to_list(FunName)),
-            lists:flatten([?MODULE:Gen(export(Form, Fun, Line), Record, Fields) || Form <- Forms])
-    end.
+  Exports = lists:filter(
+    fun({attribute, _, export, _}) -> true;
+       (_) -> false
+    end, Forms),
+  case exported(Fun, Exports) of
+    true  -> Forms;
+    false ->
+      Line = last_export_line(Exports),
+      Gen = list_to_atom("generate_" ++ atom_to_list(FunName)),
+      lists:flatten([?MODULE:Gen(export(Form, Fun, Line), Record, Fields) || Form <- Forms])
+  end.
 
-exported(Fun, Exports) -> lists:member(Fun, lists:flatten([E || {attribute, _, export, E} <- Exports])).
+exported(Fun, Exports) ->
+  lists:member(Fun, lists:flatten([E || {attribute, _, export, E} <- Exports])).
 
-field_var(Field) -> list_to_atom("V_" ++ atom_to_list(Field)).
+field_var(Field) -> erlang:list_to_atom("V_" ++ erlang:atom_to_list(Field)).
 
 from_json_prelude(Line) ->
-    {clause, Line,
-     [{nil, Line}, {var, Line, 'Acc'}],
-     [],
-     [{var, Line, 'Acc'}]}.
+  {clause, Line,
+   [{nil, Line}, {var, Line, 'Acc'}],
+   [],
+   [{var, Line, 'Acc'}]}.
 
 from_json_coda(Line) ->
-    {clause, Line,
-     [{cons, Line, {var, Line, '_'}, {var, Line, 'Json'}}, {var, Line, 'Acc'}],
-     [],
-     [{call, Line, {atom, Line, from_json}, [
+  {clause, Line,
+   [{cons, Line, {var, Line, '_'}, {var, Line, 'Json'}}, {var, Line, 'Acc'}],
+   [],
+   [{call, Line, {atom, Line, from_json}, [
      %{var, Line, 'Json'}, % here is fix for recursive binarized preprocessing to raw X:from_json
      {call, Line, {remote, Line, {atom, Line, ?MODULE}, {atom, Line, binarize}}, [{var, Line, 'Json'}]},
-     {var, Line, 'Acc'}]}]}.
+     {var, Line, 'Acc'}
+   ]}]}.
 
 from_json_clauses(_, _, []) -> [];
 from_json_clauses(Line, Record, [Field | Fields]) ->
-    [{clause, Line,
-      [{cons, Line,
-        {tuple, Line,
-         [{bin, Line,
-           [{bin_element, Line, {string, Line, atom_to_list(Field)}, default, default}]},
-          {var, Line, field_var(Field)}]},
-        {var, Line, 'Json'}},
-       {var, Line, 'Acc'}],
-      [],
-      [{call, Line,
-        {atom, Line, from_json},
-        [{var, Line, 'Json'},
-         {record, Line,
-          {var, Line, 'Acc'},
-          Record,
-          [{record_field, Line,
-            {atom, Line, Field},
-            {call, Line,
-             {remote, Line, {atom, Line, ?MODULE }, {atom, Line, from_json}},
-             [{var, Line, field_var(Field)},
-              {atom, Line, case erlang:get({Record, Field}) of undefined -> Record; FieldType -> FieldType end}]}
-            }]}]}]}
-     | from_json_clauses(Line, Record, Fields)].
+  [{clause, Line,
+    [{cons, Line,
+      {tuple, Line,
+       [{bin, Line,
+         [{bin_element, Line, {string, Line, erlang:atom_to_list(Field)}, default, default}]},
+        {var, Line, field_var(Field)}]},
+      {var, Line, 'Json'}},
+     {var, Line, 'Acc'}],
+    [],
+    [{call, Line,
+      {atom, Line, from_json},
+      [{var, Line, 'Json'},
+       {record, Line,
+        {var, Line, 'Acc'},
+        Record,
+        [{record_field, Line,
+          {atom, Line, Field},
+          {call, Line,
+           {remote, Line, {atom, Line, ?MODULE }, {atom, Line, from_json}},
+           [{var, Line, field_var(Field)},
+            {atom, Line,
+             case erlang:get({Record, Field}) of
+               undefined -> Record;
+               FieldType -> FieldType
+             end}]}
+          }]}]}]}
+   | from_json_clauses(Line, Record, Fields)].
 
 generate_from_json({eof, Line}, Record, Fields) ->
-    [{function, Line, from_json, 2,
-      [from_json_prelude(Line)] ++ from_json_clauses(Line, Record, Fields) ++ [from_json_coda(Line)]},
-     {eof, Line + 1}];
+  [{function, Line, from_json, 2,
+    [from_json_prelude(Line)] ++ from_json_clauses(Line, Record, Fields) ++ [from_json_coda(Line)]},
+   {eof, Line + 1}];
 generate_from_json(Form, _, _) -> Form.
 
 export({attribute, LastExportLine, export, Exports}, Fun, LastExportLine) ->
-    {attribute, LastExportLine, export, [Fun | Exports]};
+  {attribute, LastExportLine, export, [Fun | Exports]};
 export(Form, _, _) -> Form.
 
 to_json_cons(Line, []) -> {nil, Line};
 to_json_cons(Line, [Field | Fields]) ->
-    {cons, Line,
-     {tuple, Line,
-      [{atom, Line, Field},
-       {call, Line,
-        {remote, Line, {atom, Line, ?MODULE}, {atom, Line, to_json}},
-        [{var, Line, field_var(Field)}]}]},
-     to_json_cons(Line, Fields)}.
+  {cons, Line,
+   {tuple, Line,
+    [{atom, Line, Field},
+     {call, Line,
+      {remote, Line, {atom, Line, ?MODULE}, {atom, Line, to_json}},
+      [{var, Line, field_var(Field)}]}]},
+   to_json_cons(Line, Fields)}.
 
 generate_to_json({eof, Line}, Record, Fields) ->
-    [{function, Line, to_json, 1,
-      [{clause, Line,
-        [{record, Line, Record,
-          [{record_field, Line, {atom, Line, F}, {var, Line, field_var(F)}} || F <- Fields]}],
-        [],
-        [to_json_cons(Line, Fields)]}]},
-     {eof, Line + 1}];
+  [{function, Line, to_json, 1,
+    [{clause, Line,
+      [{record, Line, Record,
+        [{record_field, Line, {atom, Line, F}, {var, Line, field_var(F)}} || F <- Fields]}],
+      [],
+      [to_json_cons(Line, Fields)]}]},
+   {eof, Line + 1}];
 
 generate_to_json(Form, _, _) -> Form.
 
@@ -169,13 +178,14 @@ to_json(X) when erlang:is_tuple(X) ->
   Module:to_json(X);
 to_json(Data) ->
   case is_string(Data) of
-    true  -> rest:to_binary(Data);
+    true  -> to_binary(Data);
     false -> json_match(Data)
   end.
 
 json_match([{_, _} | _] = Props) ->
-  [{rest:to_binary(Key), to_json(Value)} || {Key, Value} <- Props];
-json_match([_ | _] = NonEmptyList) -> [to_json(X) || X <- NonEmptyList];
+  [{to_binary(Key), to_json(Value)} || {Key, Value} <- Props];
+json_match([_ | _] = NonEmptyList) ->
+  [to_json(X) || X <- NonEmptyList];
 json_match(Any) -> Any.
 
 is_char(C) -> erlang:is_integer(C) andalso C >= 0 andalso C =< 255.
@@ -186,7 +196,7 @@ is_string(_)                                                 -> false.
 to_binary(A) when erlang:is_atom(A) -> erlang:atom_to_binary(A, latin1);
 to_binary(B) when erlang:is_binary(B) -> B;
 to_binary(I) when erlang:is_integer(I) -> to_binary(erlang:integer_to_list(I));
-to_binary(F) when erlang:is_float(F) -> float_to_binary(F, [{decimals, 9}, compact]);
+to_binary(F) when erlang:is_float(F) -> erlang:float_to_binary(F, [{decimals, 9}, compact]);
 to_binary(L) when erlang:is_list(L) ->  erlang:iolist_to_binary(L).
 
 parse(String) ->

+ 4 - 1
src/rest_app.erl

@@ -1,6 +1,9 @@
 -module(rest_app).
 -behaviour(application).
+
 -export([start/2, stop/1]).
 
-start(_StartType, _StartArgs) -> rest_sup:start_link().
+start(_StartType, _StartArgs) ->
+  rest_sup:start_link().
+
 stop(_State) -> ok.

+ 26 - 17
src/rest_cowboy.erl

@@ -1,12 +1,13 @@
 -module(rest_cowboy).
 -author('Dmitry Bushmelev').
 
--export([init/2, rest_init/2, resource_exists/2, allowed_methods/2, content_types_provided/2,
-         to_html/2, to_json/2, content_types_accepted/2, delete_resource/2,
-         handle_urlencoded_data/2, handle_json_data/2]).
+-export([init/2, rest_init/2, resource_exists/2, allowed_methods/2,
+         content_types_provided/2, content_types_accepted/2, delete_resource/2,
+         handle_urlencoded_data/2, handle_json_data/2, to_html/2, to_json/2]).
 
 -record(st, {resource_module = undefined :: atom(), resource_id = undefined :: binary()}).
 
+
 init(Req, Opts) -> {cowboy_rest, Req, Opts}.
 
 -ifndef(REST_JSON).
@@ -15,9 +16,13 @@ init(Req, Opts) -> {cowboy_rest, Req, Opts}.
 
 c(X) -> erlang:list_to_atom(erlang:binary_to_list(X)).
 
+
 rest_init(Req, _Opts) ->
   {Resource, Req1} = cowboy_req:binding(resource, Req),
-  Module = case rest_module(Resource) of {ok, M} -> M; _ -> undefined end,
+  Module = case rest_module(Resource) of
+    {ok, M} -> M;
+    _ -> undefined
+  end,
   {Id, Req2} = cowboy_req:binding(id, Req1),
   {Origin, Req3} = cowboy_req:header(<<"origin">>, Req2, <<"*">>),
   Req4 = cowboy_req:set_resp_header(<<"Access-Control-Allow-Origin">>, Origin, Req3),
@@ -35,8 +40,10 @@ resource_exists(#{bindings := #{id := _}} = Req, State) ->
   io:format("EXISTS id: true~n"),
   {true, Req, State}.
 
-allowed_methods(#{bindings := #{resource := _}} = Req, State) -> {[<<"GET">>, <<"POST">>], Req, State};
-allowed_methods(#{bindings := #{resource := _, id := _}} = Req, State) -> {[<<"GET">>, <<"PUT">>, <<"DELETE">>], Req, State}.
+allowed_methods(#{bindings := #{resource := _}} = Req, State) ->
+  {[<<"GET">>, <<"POST">>], Req, State};
+allowed_methods(#{bindings := #{resource := _, id := _}} = Req, State) ->
+  {[<<"GET">>, <<"PUT">>, <<"DELETE">>], Req, State}.
 
 content_types_provided(#{bindings := #{resource := Module}} = Req, State) ->
   {case erlang:function_exported(c(Module), to_html, 1) of
@@ -58,21 +65,23 @@ to_html(#{bindings := #{resource := Module, id := Id}} = Req, State) ->
   {Html, Req, State}.
 
 
-default_html_layout(Body) -> [<<"<html><body>">>, Body, <<"</body></html>">>].
+default_html_layout(Body) ->
+  [<<"<html><body>">>, Body, <<"</body></html>">>].
 
 to_json(#{bindings := #{resource := Module, id := Id}} = Req, State) ->
-    io:format("~p ~p ~p~n", [?FUNCTION_NAME, Module, Id]),
-    M = c(Module),
-    Struct = case Id of
-                 undefined -> [{M, [ M:to_json(Resource) || Resource <- M:get() ]}];
-                 _         -> M:to_json(M:get(Id)) end,
-    {erlang:iolist_to_binary(?REST_JSON:encode(Struct)), Req, State};
+  io:format("~p ~p ~p~n", [?FUNCTION_NAME, Module, Id]),
+  M = c(Module),
+  Struct = case Id of
+    undefined -> [{M, [ M:to_json(Resource) || Resource <- M:get() ]}];
+    _         -> M:to_json(M:get(Id))
+  end,
+  {erlang:iolist_to_binary(?REST_JSON:encode(Struct)), Req, State};
 
 to_json(#{bindings := #{resource := Module}} = Req, State) ->
-    io:format("~p ~p~n", [?FUNCTION_NAME, Module]),
-    M = c(Module),
-    Struct = [{M, [ M:to_json(Resource) || Resource <- M:get() ]}],
-    {erlang:iolist_to_binary(?REST_JSON:encode(Struct)), Req, State}.
+  io:format("~p ~p~n", [?FUNCTION_NAME, Module]),
+  M = c(Module),
+  Struct = [{M, [ M:to_json(Resource) || Resource <- M:get() ]}],
+  {erlang:iolist_to_binary(?REST_JSON:encode(Struct)), Req, State}.
 
 
 content_types_accepted(Req, State) ->

+ 8 - 2
src/rest_sup.erl

@@ -1,7 +1,13 @@
 -module(rest_sup).
+
 -behaviour(supervisor).
+
 -export([start_link/0, init/1]).
 
-start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-init([]) -> {ok, {{one_for_one, 5, 10}, []}}.
+
+start_link() ->
+  supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
+  {ok, {{one_for_one, 5, 10}, []}}.