@ -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}}, | |||
[ | |||
{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"}. |