From ef59cbb43708aef1a8125970603ffce4f13c5b54 Mon Sep 17 00:00:00 2001 From: Alexander Neganov Date: Mon, 9 Jul 2012 03:33:30 +0400 Subject: [PATCH 01/10] Fix Makefile, make deps .PHONY, remove tags dep --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 25f99b8..ee93d64 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,12 @@ REBAR = rebar PROJECT = nakaz +app: deps + @$(REBAR) compile + deps: @$(REBAR) get-deps -app: deps tags - @$(REBAR) compile - clean: @$(REBAR) clean rm -f test/*.beam @@ -40,4 +40,4 @@ dialyze: app-nodeps @$(DIALYZER) --plt .$(PROJECT).plt -r ebin/ \ -Werror_handling -Wrace_conditions -Wunmatched_returns -Wunderspecs -.PHONY: build-plt plt-add-deps plt-remove-deps plt-readd-deps dialyze +.PHONY: deps build-plt plt-add-deps plt-remove-deps plt-readd-deps dialyze From e0497c8d3589a0e6fc43533674c1648c00da538b Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Mon, 9 Jul 2012 03:34:59 +0400 Subject: [PATCH 02/10] Minor 'README.md' update -- way to many features, way to many --- README.md | 87 +++++++++++++++++++++++++++++++++++-- example/src/example_app.erl | 2 + 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 99d2409..ca9f296 100644 --- a/README.md +++ b/README.md @@ -42,19 +42,98 @@ configured application can have one or more sections, for example: ```yaml example: + srv_conf: + conn_type: http + log_conf: log: "priv/log.txt" severity: debug + ``` -Here, [example] [3] application defines a single section, named -`log_conf`. As you might have noticed, applications are defined -on the **top level** of the configuration file, with sections, -residing on the **second level**. +Here, [example] [3] application defines a two sections, named +`log_conf` and `srv_conf`. So, as you might have noticed, the +expected structure is simple: + +* applications are defined on the **top level** of the configuration file, +* with sections, residing on the **second level**. + +> "Enough YAML, show me some Erlang code, dude?!" + +### Configuration path + +For flexibility reasons `nakaz` doesn't allow you to actually **read** +configuration file from the code, instead, it handles reading and +parsing internally, and all **you** have to do is pass path to the +configuration file via command line: + +```bash +$ erl -nakaz path/to/config.yaml +``` + +**Note**: the current implementation doesn't allow using multiple +configuration files, but this might change in the future versions. + +### Applications + +As we've already mentioned, `nakaz` represents your application +configuration as sections; what we haven't mentioned is that **every** +section will be parsed into a **typed** Erlang record! Here's an +[example] [4]: + +```erlang +-module(my_awesome_app). +-behaviour(application). +-compile({parse_transform, nakaz_pt}). + +-include_lib("nakaz/include/nakaz.hrl"). + +-type filename() :: string(). + +-record(srv_conf, {conn_type :: http | ssl}). +-record(log_conf, {log :: filename(), + severity :: debug | info | error}). + +%% Application callbacks + +-export([start/2, stop/1]). + +%% Application callbacks + +start(_StartType, _StartArgs) -> + case ?NAKAZ_ENSURE([#srv_conf{}, #log_conf{}]) of + ok -> example_sup:start_link(); + {error, Msg} -> io:format(Msg) + end. + +stop(_State) -> + ok. +``` + +What happens here? First thing to notice is `{parse_transform, nakaz_pt}`, +this is **required** for all the record-related magic to happen. Second, +`?NAKAZ_ENSURE()` macro -- as the name suggests, this macro *ensures* +that the configration file actually contains all of the sections, required +by your application. Moreover, `?NAKAZ_ENSURE()` also checks that the +values in those sections **exactly** match the types you've declared in +the record specs! + +If anything goes wrong, the `Msg` term will contain an understable +description of the error. + +#### Why records? + +Probably, the use of records in `?NAKAZ_ENSURE()` call looks a little +supprising, and you might be thinking +`"wtf is wrong with those crazy russians?!"`. Here's the deal, forcing +arguments to be records we actually make sure that each of them is +a valid record and is available in the module scope (which is just what +`nakaz_pt` needs!). [1]: http://www.yaml.org [2]: http://en.wikipedia.org/wiki/YAML#Associative_arrays [3]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/example/priv/conf.yaml +[4]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/example/src/example_app.erl Why the name? ------------- diff --git a/example/src/example_app.erl b/example/src/example_app.erl index 9b48ac2..99d7376 100644 --- a/example/src/example_app.erl +++ b/example/src/example_app.erl @@ -1,6 +1,7 @@ -module(example_app). -behaviour(application). -compile({parse_transform, nakaz_pt}). + -include_lib("nakaz/include/nakaz.hrl"). -include("example.hrl"). @@ -8,6 +9,7 @@ -export([start/0, stop/0]). %% Application callbacks + -export([start/2, stop/1]). %% API From 93db81ae1406324247a86d5e1f4227b838ce229c Mon Sep 17 00:00:00 2001 From: Alexander Neganov Date: Mon, 9 Jul 2012 03:39:33 +0400 Subject: [PATCH 03/10] Proper Makefile for example app --- example/Makefile | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/example/Makefile b/example/Makefile index bc71334..dcd3d16 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,2 +1,23 @@ -run: +DIALYZER = dialyzer +REBAR = rebar + +PROJECT = nakaz + +app: deps + @$(REBAR) compile + +deps: + @$(REBAR) get-deps + +clean: + @$(REBAR) clean + rm -f test/*.beam + rm -f erl_crash.dump + +app-nodeps: + @$(REBAR) compile skip_deps=true + +run: app-nodeps erl -pa deps/*/ebin ebin -s example_app -nakaz priv/conf.yaml + +.PHONY: deps app-nodeps run clean app From 9ec92dbdc7ec449f4c05faa8e5d657b980659cad Mon Sep 17 00:00:00 2001 From: Alexander Neganov Date: Mon, 9 Jul 2012 03:46:01 +0400 Subject: [PATCH 04/10] fix exmple app Makefile --- example/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/example/Makefile b/example/Makefile index dcd3d16..6fba912 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,8 +1,5 @@ -DIALYZER = dialyzer REBAR = rebar -PROJECT = nakaz - app: deps @$(REBAR) compile From f3b055a7ed39f74c7f715f3cb0d5583913803882 Mon Sep 17 00:00:00 2001 From: Alexander Neganov Date: Mon, 9 Jul 2012 03:51:23 +0400 Subject: [PATCH 05/10] add readme for example app --- example/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 example/README.md diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..67335df --- /dev/null +++ b/example/README.md @@ -0,0 +1,8 @@ +Nakaz example application +------------------------- + +Can be built and started with: +''' +make app +make run +''' \ No newline at end of file From fa06e84a659c10110685a4f2e5cbe44346e0d423 Mon Sep 17 00:00:00 2001 From: Alexander Neganov Date: Mon, 9 Jul 2012 03:52:26 +0400 Subject: [PATCH 06/10] fix readme for example app --- example/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/example/README.md b/example/README.md index 67335df..8d89013 100644 --- a/example/README.md +++ b/example/README.md @@ -2,6 +2,7 @@ Nakaz example application ------------------------- Can be built and started with: + ''' make app make run From 41e86cca6038444f95a3d988386488b6b4dcc0ba Mon Sep 17 00:00:00 2001 From: Alexander Neganov Date: Mon, 9 Jul 2012 03:55:30 +0400 Subject: [PATCH 07/10] fix example app readme. again. --- example/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/README.md b/example/README.md index 8d89013..7adfee4 100644 --- a/example/README.md +++ b/example/README.md @@ -3,7 +3,7 @@ Nakaz example application Can be built and started with: -''' -make app -make run -''' \ No newline at end of file +```bash +$ make app +$ make run +``` \ No newline at end of file From dc2212415dc1eb8986831c60345435b9dc231306 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Mon, 9 Jul 2012 03:45:53 +0400 Subject: [PATCH 08/10] Added a section on '?NAKAZ_USE' to 'README.md' --- README.md | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ca9f296..94c4502 100644 --- a/README.md +++ b/README.md @@ -112,9 +112,9 @@ stop(_State) -> What happens here? First thing to notice is `{parse_transform, nakaz_pt}`, this is **required** for all the record-related magic to happen. Second, -`?NAKAZ_ENSURE()` macro -- as the name suggests, this macro *ensures* +`?NAKAZ_ENSURE` macro -- as the name suggests, this macro *ensures* that the configration file actually contains all of the sections, required -by your application. Moreover, `?NAKAZ_ENSURE()` also checks that the +by your application. Moreover, `?NAKAZ_ENSURE` also checks that the values in those sections **exactly** match the types you've declared in the record specs! @@ -123,7 +123,7 @@ description of the error. #### Why records? -Probably, the use of records in `?NAKAZ_ENSURE()` call looks a little +Probably, the use of records in `?NAKAZ_ENSURE` call looks a little supprising, and you might be thinking `"wtf is wrong with those crazy russians?!"`. Here's the deal, forcing arguments to be records we actually make sure that each of them is @@ -135,6 +135,37 @@ a valid record and is available in the module scope (which is just what [3]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/example/priv/conf.yaml [4]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/example/src/example_app.erl +### Accessing config sections + +Whenever you need to access a specific section from the configuration +file, simply [call] [5] `?NAKAZ_USE` passing **section name** as an +argument: + +```erlang +%% IMPORTANT: without this line your module won't be notified of any +%% configuration changes! +-behaviour(nakaz_user). + +init([]) -> + SrvConf = ?NAKAZ_USE(#srv_conf{}), + LogConf = ?NAKAZ_USE(#log_conf{}), + {ok, #state{srv_conf=SrvConf, + log_conf=LogConf}}. +``` + +Three awesome facts about `?NAKAZ_USE`: + +* it only allows using *ensured* sections, any other sections simply + don't exist; +* the returned section is guaranteed to be 100% valid, because + `?NAKAZ_ENSURE` already did all the hard work of type checking and + validating configuration values; +* the caller will be notified of section changes, see [nakaz_user] [6] + documentation for details. + +[5]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/example/src/example_srv.erl#L38 +[6]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/src/nakaz_user.erl + Why the name? ------------- From 5854e6ab33faa3695dfa22eba77fefa2e8f2dcf7 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Mon, 9 Jul 2012 03:53:44 +0400 Subject: [PATCH 09/10] Final sketches! --- README.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 94c4502..4077954 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ | \| || \ | \ | \ .-`.-` |__/\____||__|\__\|__|\__\|__|\__\|______| - configuration management done right! making sysops happier one at a time! Is it any good? @@ -18,13 +17,20 @@ For easy and sexy config files processing and easy config reloading support. Why do I need it? ----------------- -Usually config files for Erlang software is just a bunch of Erlang terms. -It is hard to read, write, parse and validate. And sometimes you need -to handle config reloading. All this makes pain in ass and puts your code -in mess. -Nakaz uses YAML for config files (which is human-readable and clean), --record specs as config schema definition, has schema validation and has -support for config reloading interface and callbacks. + +Configuration files is usually not the strongest part of Erlang +applications. The usual way of configuring things is by simply writing +Erlang terms in some `*.config` file and then either calling +[file:consult/1](http://www.erlang.org/doc/man/file.html#consult-1) +directly or loading them in application environment by the OTP machinery. +While okay for most of Erlang developers, this way of doing configuration +can hardly be called user friendly. + +In contrast, `nakaz` uses YAML for config files, which easy to both +read **and** write, it also takes care of validation, config reloading +and more! + +[Screencast](http://tiny.cc/nakaz) Ho can I use it? ---------------- From ea7f04c6f265af40914d204013ca8eabc6a9ef17 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Mon, 9 Jul 2012 03:54:23 +0400 Subject: [PATCH 10/10] Reordered sections in 'README.md' --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4077954..ea6f568 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,14 @@ making sysops happier one at a time! +Why the name? +------------- + +This is the dumbest name we could come up with, which roughly +[translates] [1] to `mandate` from old-Russian. + +[1]: http://translate.google.com/#ru|en|%D0%BD%D0%B0%D0%BA%D0%B0%D0%B7 + Is it any good? --------------- @@ -171,11 +179,3 @@ Three awesome facts about `?NAKAZ_USE`: [5]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/example/src/example_srv.erl#L38 [6]: https://github.com/Spawnfest2012/holybrolly-nakaz/blob/master/src/nakaz_user.erl - -Why the name? -------------- - -This is the dumbest name we could come up with, which roughly -[translates] [1] to `mandate` from old-Russian. - -[1]: http://translate.google.com/#ru|en|%D0%BD%D0%B0%D0%BA%D0%B0%D0%B7