@ -0,0 +1,29 @@ | |||||
Copyright (c) {{copyright_year}}, {{copyright_holder}} <{{author_email}}>. | |||||
All rights reserved. | |||||
Redistribution and use in source and binary forms, with or without | |||||
modification, are permitted provided that the following conditions are | |||||
met: | |||||
* Redistributions of source code must retain the above copyright | |||||
notice, this list of conditions and the following disclaimer. | |||||
* Redistributions in binary form must reproduce the above copyright | |||||
notice, this list of conditions and the following disclaimer in the | |||||
documentation and/or other materials provided with the distribution. | |||||
* The names of its contributors may not be used to endorse or promote | |||||
products derived from this software without specific prior written | |||||
permission. | |||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,14 @@ | |||||
{{appid}} | |||||
===== | |||||
An Erlang {{appid}} library. | |||||
Build | |||||
----- | |||||
$ rebar get-deps compile | |||||
Run | |||||
--- | |||||
$ erl -pa ebin -env ERL_LIBS deps -s {{appid}} |
@ -0,0 +1,7 @@ | |||||
{variables, [{appid, "myapp"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "LICENSE", "LICENSE"}. |
@ -0,0 +1,17 @@ | |||||
{application, {{appid}}, | |||||
[ | |||||
{description, "{{appid}}"} | |||||
,{vsn, "0.1.0"} | |||||
,{registered, [{{appid}}_sup]} | |||||
,{applications, | |||||
[kernel | |||||
,stdlib | |||||
]} | |||||
,{mod, { {{appid}}, []} } | |||||
,{env, | |||||
[ | |||||
]} | |||||
,{start_phases, | |||||
[{listen, []} | |||||
]} | |||||
]}. |
@ -0,0 +1,77 @@ | |||||
%%%------------------------------------------------------------------- | |||||
%% @copyright {{copyright_holder}} ({{copyright_year}}) | |||||
%% @author {{author_name}} <{{author_email}}> | |||||
%% @doc {{appid}} OTP application callback module. | |||||
%% @end | |||||
%%%------------------------------------------------------------------- | |||||
-module({{appid}}_app). | |||||
-behaviour(application). | |||||
-define(APP, {{appid}}). | |||||
%% Application callbacks | |||||
-export([start_phase/3, start/2, stop/1]). | |||||
-export([config/0, config/1, config/2, | |||||
start/0, a_start/2]). | |||||
%%%=================================================================== | |||||
%%% Convenience Functions | |||||
%%%=================================================================== | |||||
start() -> | |||||
a_start(?APP, permanent). | |||||
config(Key, Default) -> | |||||
case application:get_env(?APP, Key) of | |||||
undefined -> Default; | |||||
{ok, Val} -> Val | |||||
end. | |||||
config(Key) -> | |||||
case application:get_env(?APP, Key) of | |||||
undefined -> erlang:error({missing_config, Key}); | |||||
{ok, Val} -> Val | |||||
end. | |||||
config() -> | |||||
application:get_all_env(?APP). | |||||
%% =================================================================== | |||||
%% Application callbacks | |||||
%% =================================================================== | |||||
start(_StartType, _StartArgs) -> | |||||
{{appid}}_sup:start_link(). | |||||
stop(_State) -> | |||||
ok. | |||||
start_phase(listen, _Type, _Args) -> | |||||
Dispatch = [{'_', | |||||
[{'_', {{app}}_http_handler, []}]} | |||||
], | |||||
cowboy:start_listener(http, 100, | |||||
cowboy_tcp_transport, | |||||
[{port, config(http_listen_port)}], | |||||
cowboy_http_protocol, | |||||
[{dispatch, Dispatch}]), | |||||
ok. | |||||
%%%=================================================================== | |||||
%%% Internal functions | |||||
%%%=================================================================== | |||||
a_start(App, Type) -> | |||||
start_ok(App, Type, application:start(App, Type)). | |||||
start_ok(_App, _Type, ok) -> ok; | |||||
start_ok(_App, _Type, {error, {already_started, _App}}) -> ok; | |||||
start_ok(App, Type, {error, {not_started, Dep}}) -> | |||||
ok = a_start(Dep, Type), | |||||
a_start(App, Type); | |||||
start_ok(App, _Type, {error, Reason}) -> | |||||
erlang:error({app_start_failed, App, Reason}). |
@ -0,0 +1,79 @@ | |||||
%%%------------------------------------------------------------------- | |||||
%% @copyright {{copyright_holder}} ({{copyright_year}}) | |||||
%% @author {{author_name}} <{{author_email}}> | |||||
%% @doc {{appid}} {{fsmid}} OTP FSM. | |||||
%% @end | |||||
%%%------------------------------------------------------------------- | |||||
-module({{appid}}_{{fsmid}}_fsm). | |||||
-behaviour(gen_fsm). | |||||
-include("{{appid}}_log.hrl"). | |||||
%% API | |||||
-export([start_link/0 | |||||
]). | |||||
%% gen_fsm callbacks | |||||
-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3, | |||||
terminate/3, code_change/4]). | |||||
-export([disconnected/2 | |||||
,disconnected/3 | |||||
]). | |||||
-record(state, {replaceme}). | |||||
%%==================================================================== | |||||
%% API | |||||
%%==================================================================== | |||||
start_link() -> | |||||
gen_fsm:start_link(?MODULE, [], []). | |||||
%%==================================================================== | |||||
%% gen_fsm callbacks | |||||
%%==================================================================== | |||||
%% gen_fsm init/1 callback | |||||
%% @private | |||||
init([]) -> | |||||
{ok, disconnected, #state{}}. | |||||
%% state event handler functions. | |||||
%% @private | |||||
disconnected(Event, State) -> | |||||
?WARN("[state: disconnected] Unhandled event: ~p", [Event]), | |||||
{next_state, disconnected, State}. | |||||
disconnected(Event, _From, State) -> | |||||
?WARN("[state: disconnected] Unhandled event: ~p", [Event]), | |||||
{next_state, disconnected, State}. | |||||
%% gen_fsm callbacks | |||||
%% @private | |||||
handle_event(Event, StateName, State) -> | |||||
?WARN("[state: ~p] Unhandled event: ~p", [StateName, Event]), | |||||
{next_state, StateName, State}. | |||||
%% @private | |||||
handle_sync_event(Event, _From, StateName, State) -> | |||||
?WARN("[state: ~p] Unhandled event: ~p", [StateName, Event]), | |||||
{next_state, StateName, State}. | |||||
%% @private | |||||
handle_info(Info, StateName, State) -> | |||||
?INFO("[state: ~p] Unexpected msg: ~p", [StateName, Info]), | |||||
{next_state, StateName, State}. | |||||
%% @private | |||||
terminate(_Reason, _StateName, _State) -> | |||||
ok. | |||||
%% @private | |||||
code_change(_OldVsn, StateName, State, _Extra) -> | |||||
{ok, StateName, State}. | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== |
@ -0,0 +1,63 @@ | |||||
%%%------------------------------------------------------------------- | |||||
%% @copyright {{copyright_holder}} ({{copyright_year}}) | |||||
%% @author {{author_name}} <{{author_email}}> | |||||
%% @doc {{appid}} {{srvid}} OTP gen_server. | |||||
%% @end | |||||
%%%------------------------------------------------------------------- | |||||
-module({{appid}}_{{srvid}}). | |||||
-behaviour(gen_server). | |||||
-include("{{appid}}_log.hrl"). | |||||
%% API | |||||
-export([start_link/0 | |||||
]). | |||||
%% gen_server callbacks | |||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, | |||||
terminate/2, code_change/3]). | |||||
-record(state, {replaceme}). | |||||
%%==================================================================== | |||||
%% API | |||||
%%==================================================================== | |||||
start_link() -> | |||||
gen_server:start_link(?MODULE, [], []). | |||||
%%==================================================================== | |||||
%% gen_server callbacks | |||||
%%==================================================================== | |||||
%% @private | |||||
init([]) -> | |||||
{ok, #state{}}. | |||||
%% @private | |||||
handle_call(Call, _From, State) -> | |||||
?WARN("Unexpected call ~p.", [Call]), | |||||
{noreply, State}. | |||||
%% @private | |||||
handle_cast(Msg, State) -> | |||||
?WARN("Unexpected cast ~p", [Msg]), | |||||
{noreply, State}. | |||||
%% @private | |||||
handle_info(Info, State) -> | |||||
?WARN("Unexpected info ~p", [Info]), | |||||
{noreply, State}. | |||||
%% @private | |||||
terminate(_Reason, _State) -> | |||||
ok. | |||||
%% @private | |||||
code_change(_OldVsn, State, _Extra) -> | |||||
{ok, State}. | |||||
%%==================================================================== | |||||
%% internal functions | |||||
%%==================================================================== |
@ -0,0 +1,15 @@ | |||||
{variables, [{appid, "myapp"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "simpleapp.erl", "src/{{appid}}.erl"}. | |||||
{template, "simpleapp.app.src", "src/{{appid}}.app.src"}. | |||||
{template, "simpleapp_app.erl", "src/{{appid}}_app.erl"}. | |||||
{template, "simpleapp_sup.erl", "src/{{appid}}_sup.erl"}. | |||||
{template, "simplelogging.hrl", "src/{{appid}}_log.hrl"}. | |||||
{template, "simple_rebar.config", "rebar.config"}. | |||||
{template, "simpleapp_gitignore", ".gitignore"}. | |||||
{template, "LICENSE", "LICENSE"}. | |||||
{template, "README.md", "README.md"}. |
@ -0,0 +1,8 @@ | |||||
{variables, [{appid, "myapp"} | |||||
,{fsmid, "fsmid"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "otp_fsm.erl", "src/{{appid}}_{{fsmid}}_fsm.erl"}. |
@ -0,0 +1,13 @@ | |||||
{application, {{appid}}, | |||||
[ | |||||
{description, "{{appid}}"} | |||||
,{vsn, "0.1.0"} | |||||
,{registered, []} | |||||
,{applications, | |||||
[kernel | |||||
,stdlib | |||||
]} | |||||
,{env, | |||||
[ | |||||
]} | |||||
]}. |
@ -0,0 +1,13 @@ | |||||
{variables, [{appid, "myapp"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "simpleapp.erl", "src/{{appid}}.erl"}. | |||||
{template, "otplib.app.src", "src/{{appid}}.app.src"}. | |||||
{template, "simplelogging.hrl", "src/{{appid}}_log.hrl"}. | |||||
{template, "simple_rebar.config", "rebar.config"}. | |||||
{template, "simpleapp_gitignore", ".gitignore"}. | |||||
{template, "LICENSE", "LICENSE"}. | |||||
{template, "README.md", "README.md"}. |
@ -0,0 +1,8 @@ | |||||
{variables, [{appid, "myapp"} | |||||
,{srvid, "mysrv"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "otp_srv.erl", "src/{{appid}}_{{srvid}}.erl"}. |
@ -0,0 +1,7 @@ | |||||
{variables, [{appid, "myapp"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "Readme.md", "Readme.md"}. |
@ -0,0 +1,48 @@ | |||||
%%%------------------------------------------------------------------- | |||||
%% @copyright {{copyright_holder}} ({{copyright_year}}) | |||||
%% @author {{author_name}} <{{author_email}}> | |||||
%% @doc CommonTest test suite for {{test}} | |||||
%% @end | |||||
%%%------------------------------------------------------------------- | |||||
-module({{test}}_SUITE). | |||||
-include_lib("common_test/include/ct.hrl"). | |||||
-compile(export_all). | |||||
%%%%%%%%%%%%%%%%%%%% | |||||
%%% Tests to run %%% | |||||
%%%%%%%%%%%%%%%%%%%% | |||||
%% Specific test cases or groups to run. The test case is named as | |||||
%% a single atom. | |||||
all() -> | |||||
[default_case]. | |||||
%%%%%%%%%%%%%%%%%%%%%% | |||||
%%% Setup/Teardown %%% | |||||
%%%%%%%%%%%%%%%%%%%%%% | |||||
%% Runs once at the beginning of the suite. The process is different | |||||
%% from the one the case will run in. | |||||
init_per_suite(Config) -> | |||||
Config. | |||||
%% Runs once at the end of the suite. The process is different | |||||
%% from the one the case will run in. | |||||
end_per_suite(Config) -> | |||||
Config. | |||||
%% Runs before the test case. Runs in the same process. | |||||
init_per_testcase(_CaseName, Config) -> | |||||
Config. | |||||
%% Runs after the test case. Runs in the same process. | |||||
end_per_testcase(_CaseName, Config) -> | |||||
Config. | |||||
%%%%%%%%%%%%% | |||||
%%% TESTS %%% | |||||
%%%%%%%%%%%%% | |||||
default_case(Config) -> | |||||
_Priv = ?config(priv_dir, Config), | |||||
_Data = ?config(data_dir, Config), | |||||
ok. |
@ -0,0 +1,7 @@ | |||||
{variables, [{test, "mytest"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "simple_SUITE.erl", "test/{{test}}_SUITE.erl"}. |
@ -0,0 +1,2 @@ | |||||
{variables, [{appid, "myapp"}]}. | |||||
{template, "simpleapp_gitignore", ".gitignore"}. |
@ -0,0 +1,2 @@ | |||||
{erl_opts, [debug_info]}. | |||||
{deps, []}. |
@ -1,12 +1,17 @@ | |||||
{application, {{appid}}, | {application, {{appid}}, | ||||
[ | [ | ||||
{description, ""}, | |||||
{vsn, "1"}, | |||||
{registered, []}, | |||||
{applications, [ | |||||
kernel, | |||||
stdlib | |||||
]}, | |||||
{mod, { {{appid}}_app, []}}, | |||||
{env, []} | |||||
{description, "{{appid}}"} | |||||
,{vsn, "0.1.0"} | |||||
,{registered, [{{appid}}_sup]} | |||||
,{applications, | |||||
[kernel | |||||
,stdlib | |||||
]} | |||||
,{mod, { {{appid}}, []}} | |||||
,{env, | |||||
[ | |||||
]} | |||||
,{start_phases, | |||||
[{listen, []} | |||||
]} | |||||
]}. | ]}. |
@ -0,0 +1,22 @@ | |||||
%%%------------------------------------------------------------------- | |||||
%% @copyright {{copyright_holder}} ({{copyright_year}}) | |||||
%% @author {{author_name}} <{{author_email}}> | |||||
%% @doc {{appid}} public API | |||||
%% @end | |||||
%%%------------------------------------------------------------------- | |||||
-module({{appid}}). | |||||
%% API | |||||
-export([ | |||||
]). | |||||
%%==================================================================== | |||||
%% API | |||||
%%==================================================================== | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== |
@ -0,0 +1,12 @@ | |||||
*~ | |||||
*.beam | |||||
.gitignore | |||||
ebin/*.app | |||||
c_src/*.o | |||||
.eunit/* | |||||
.#* | |||||
deps/* | |||||
.rebar/ | |||||
.rebarinfo | |||||
.edts* | |||||
logs/* |
@ -0,0 +1,19 @@ | |||||
%%% Author : Geoff Cant <nem@erlang.geek.nz> | |||||
%%% Description : Logging macros | |||||
%%% Created : 13 Jan 2006 by Geoff Cant <nem@erlang.geek.nz> | |||||
-ifndef(logging_macros). | |||||
-define(logging_macros, true). | |||||
-define(INFO(Format, Args), | |||||
error_logger:info_msg("pid=~p mod=~p line=~p " ++ Format, | |||||
[self(), ?MODULE, ?LINE | Args])). | |||||
-define(WARN(Format, Args), | |||||
error_logger:warning_msg("pid=~p mod=~p line=~p " ++ Format, | |||||
[self(), ?MODULE, ?LINE | Args])). | |||||
-define(ERR(Format, Args), | |||||
error_logger:error_msg("pid=~p mod=~p line=~p " ++ Format, | |||||
[self(), ?MODULE, ?LINE | Args])). | |||||
-endif. %logging |
@ -0,0 +1,2 @@ | |||||
{variables, [{appid, "myapp"}]}. | |||||
{template, "simplelogging.hrl", "src/{{appid}}_log.hrl"}. |
@ -0,0 +1,37 @@ | |||||
%%%------------------------------------------------------------------- | |||||
%% @copyright {{copyright_holder}} ({{copyright_year}}) | |||||
%% @author {{author_name}} <{{author_email}}> | |||||
%% @doc {{supid}} supervisor | |||||
%% @end | |||||
%%%------------------------------------------------------------------- | |||||
-module({{appid}}_{{supid}}_sup). | |||||
-behaviour(supervisor). | |||||
%% API | |||||
-export([start_link/0]). | |||||
%% Supervisor callbacks | |||||
-export([init/1]). | |||||
-define(SERVER, ?MODULE). | |||||
%%==================================================================== | |||||
%% API functions | |||||
%%==================================================================== | |||||
start_link() -> | |||||
supervisor:start_link({local, ?SERVER}, ?MODULE, []). | |||||
%%==================================================================== | |||||
%% Supervisor callbacks | |||||
%%==================================================================== | |||||
%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules} | |||||
init([]) -> | |||||
{ok, { {one_for_all, 0, 1}, []} }. | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== |
@ -0,0 +1,8 @@ | |||||
{variables, [{appid, "myapp"} | |||||
,{supid, "my"} | |||||
,{copyright_year, "2014"} | |||||
,{copyright_holder, "Geoff Cant"} | |||||
,{author_name, "Geoff Cant"} | |||||
,{author_email, "nem@erlang.geek.nz"} | |||||
]}. | |||||
{template, "simplesup.erl", "src/{{appid}}_{{supid}}_sup.erl"}. |