Browse Source

initial import

Yuriy Zhloba 10 years ago
commit
61134e6dd6
10 changed files with 377 additions and 0 deletions
  1. 8 0
      .dialyzer.ignore
  2. 6 0
      .gitignore
  3. 30 0
      Makefile
  4. 6 0
      rebar.config
  5. 9 0
      src/herd.app.src
  6. 47 0
      src/herd_rand.erl
  7. 66 0
      src/herd_simple_formats.erl
  8. 70 0
      src/herd_string.erl
  9. 78 0
      test/herd_simple_formats_test.erl
  10. 57 0
      test/herd_string_test.erl

+ 8 - 0
.dialyzer.ignore

@@ -0,0 +1,8 @@
+  erlang:get_module_info/1
+  erlang:get_module_info/2
+  erlang:integer_to_list/1
+  erlang:make_ref/0
+  erlang:md5/1
+  erlang:now/0
+  erlang:phash2/1
+  eunit:test/1

+ 6 - 0
.gitignore

@@ -0,0 +1,6 @@
+.rebar
+TODO.org
+ebin
+TAGS
+.eunit
+erl_crash.dump

+ 30 - 0
Makefile

@@ -0,0 +1,30 @@
+compile:
+	rebar compile skip_deps=true
+
+get-deps:
+	rebar get-deps
+
+compile_all:
+	rebar compile
+
+eunit:
+	rebar eunit skip_deps=true
+
+clean:
+	rebar clean skip_deps=true
+	rm -f erl_crash.dump
+
+clean_all:
+	rebar clean
+	rm -f erl_crash.dump
+
+run:
+	erl -pa ebin +pc unicode
+
+d:
+	dialyzer --src \
+	-I include -r src test \
+	| fgrep --invert-match --file .dialyzer.ignore
+
+etags:
+	etags src/* include/*

+ 6 - 0
rebar.config

@@ -0,0 +1,6 @@
+%%-*- mode: erlang -*-
+{erl_opts, [warn_missing_spec]}.
+
+{clean_files, ["*.eunit", "ebin/*.beam"]}.
+
+{deps, []}.

+ 9 - 0
src/herd.app.src

@@ -0,0 +1,9 @@
+{application, herd,
+ [
+  {description, "Base library for erlang projects"},
+  {vsn, "1"},
+  {modules, []},
+  {registered, []},
+  {applications, [kernel, stdlib]},
+  {env, []}
+ ]}.

+ 47 - 0
src/herd_rand.erl

@@ -0,0 +1,47 @@
+-module(herd_rand).
+
+-export([init_crypto/0, str/1, uuid/0, md5hex/1, hex/0]).
+
+
+%%% module API
+
+%% sets random seed for current process
+-spec init_crypto() -> ok.
+init_crypto() ->
+    <<A:32, B:32, C:32>> = crypto:rand_bytes(12),
+    random:seed({A,B,C}),
+    ok.
+
+
+%% generates random string which consists of 0-9A-Za-z chars
+-spec str(integer()) -> string().
+str(Length) ->
+    lists:map(fun(Char) when Char > 83 -> Char + 13;
+                 (Char) when Char > 57 -> Char + 7;
+                 (Char) -> Char
+              end,
+              [crypto:rand_uniform(48, 110) || _ <- lists:seq(1, Length)]).
+
+
+%% generates UUIDs like "85b3a1cf-d003-4548-a16d-c7739c18f519"
+-spec uuid() -> string().
+uuid() ->
+    R1 = crypto:rand_uniform(1, round(math:pow(2, 48))) - 1,
+    R2 = crypto:rand_uniform(1, round(math:pow(2, 12))) - 1,
+    R3 = crypto:rand_uniform(1, round(math:pow(2, 32))) - 1,
+    R4 = crypto:rand_uniform(1, round(math:pow(2, 30))) - 1,
+    <<TL:32, TM:16, THV:16, CSR:8, CSL:8, N:48>> = <<R1:48, 4:4, R2:12, 2:2, R3:32, R4:30>>,
+    lists:flatten(io_lib:format("~8.16.0b-~4.16.0b-~4.16.0b-~2.16.0b~2.16.0b-~12.16.0b",
+                                [TL, TM, THV, CSR, CSL, N])).
+
+
+%% gets md5 hash from string
+-spec(md5hex(string()) -> string()).
+md5hex(Str) ->
+    <<Hash:128/integer>> = erlang:md5(Str),
+    string:to_lower(integer_to_list(Hash, 16)).
+
+
+%% generates random md5 hash
+-spec hex() -> string().
+hex() -> md5hex(integer_to_list(erlang:phash2({now(), make_ref()}))).

+ 66 - 0
src/herd_simple_formats.erl

@@ -0,0 +1,66 @@
+-module(herd_simple_formats).
+
+-export([get_date/1, get_time/1, get_datetime/1, get_ip/1]).
+
+
+%%% module API
+
+-spec get_date(string()) -> calendar:date() | error.
+get_date(Str) ->
+    case to_int_list(Str, "-") of
+        [Y, M, D] when Y >= 0
+                       andalso M >= 1 andalso M =< 12
+                       andalso D >= 1 andalso D =< 31 ->
+            {Y, M, D};
+        _ -> error
+    end.
+
+
+-spec get_time(string()) -> calendar:time() | error.
+get_time(Str) ->
+    case to_int_list(Str, ":") of
+        [H, M, S] when H >= 0 andalso H =< 24
+                       andalso M >= 0 andalso M < 60
+                       andalso S >= 0 andalso S < 60 ->
+            {H, M, S};
+        _ -> error
+    end.
+
+
+-spec get_datetime(string()) -> calendar:datetime().
+get_datetime(Str) ->
+    case string:tokens(Str, " ") of
+        [DStr, TStr | _] ->
+            case {get_date(DStr), get_time(TStr)} of
+                {error, _} -> error;
+                {_, error} -> error;
+                DT -> DT
+            end;
+        _ -> error
+    end.
+
+
+-spec get_ip(string()) -> {byte(), byte(), byte(), byte()} | error.
+get_ip(Str) ->
+    Ints = lists:filter(
+             fun(N) when is_integer(N) andalso N >= 0 andalso N =< 255 -> true;
+                (_) -> false
+             end, to_int_list(Str, ".")),
+    case Ints of
+        [N1, N2, N3, N4] -> {N1, N2, N3, N4};
+        _ -> error
+    end.
+
+
+%% inner functions
+
+-spec to_int_list(string(), string()) -> [integer()].
+to_int_list(Str, Delimeter) ->
+    lists:filtermap(
+      fun(S) ->
+              case string:to_integer(S) of
+                  {error, _} -> false;
+                  {N, _} -> {true, N}
+              end
+      end,
+      string:tokens(Str, Delimeter)).

+ 70 - 0
src/herd_string.erl

@@ -0,0 +1,70 @@
+-module(herd_string).
+
+-export([fill_before/3, split/2, replace/3,
+         escape_xml/1, escape_json/1]).
+
+
+%%% module API
+
+-spec fill_before(string(), char(), integer()) -> string().
+fill_before(Str, Char, ToLength) ->
+    case length(Str) of
+        Length when Length >= ToLength -> Str;
+        _ -> fill_before([Char | Str], Char, ToLength)
+    end.
+
+
+-spec split(string(), string()) -> [string()].
+split("", _) -> "";
+split(Str, "") -> [Str];
+split(Str, WithStr) -> split(Str, WithStr, [], []).
+
+
+-spec split(string(), string(), [char()], [string()]) -> [string()].
+split([], _, [], Acc2) -> lists:reverse(Acc2);
+split([], _, Acc1, Acc2) -> lists:reverse([lists:reverse(Acc1) | Acc2]);
+split(Str, WithStr, Acc1, Acc2) ->
+    io:format("~p ~p ~p ~p", [Str, WithStr, Acc1, Acc2]),
+    case lists:prefix(WithStr, Str) of
+        true -> Str2 = lists:sublist(Str, length(WithStr) + 1, length(Str)),
+                case Acc1 of
+                    [] -> split(Str2, WithStr, [], Acc2);
+                    _ -> split(Str2, WithStr, [], [lists:reverse(Acc1) | Acc2])
+                end;
+        false -> [Char | Str2] = Str,
+                 split(Str2, WithStr, [Char | Acc1], Acc2)
+    end.
+
+
+-spec replace(string(), string(), string()) -> string().
+replace([], _, _) -> "";
+replace(Str, Old, New) ->
+    case lists:prefix(Old, Str) of
+        true -> Str2 = lists:sublist(Str, length(Old) + 1, length(Str)),
+                New ++ replace(Str2, Old, New);
+        false -> [Char | Str2] = Str,
+                 [Char | replace(Str2, Old, New)]
+    end.
+
+
+-spec escape_xml(string()) -> string().
+escape_xml(Str) ->
+    lists:flatten(
+      lists:map(fun($&) -> "&amp;";
+                   ($>) -> "&gt;";
+                   ($<) -> "&lt;";
+                   ($") -> "&quot;";
+                   (Char) -> Char
+                end, Str)).
+
+
+-spec escape_json(string()) -> string().
+escape_json(Str) ->
+    lists:flatten(
+      lists:map(fun(92) -> "\\\\";
+                   (34) -> "\\\"";
+                   (10) -> "\\n";
+                   (13) -> "\\r";
+                   (9) -> "\\t";
+                   (Char) -> Char
+                end, Str)).

+ 78 - 0
test/herd_simple_formats_test.erl

@@ -0,0 +1,78 @@
+-module(herd_simple_formats_test).
+
+-include_lib("eunit/include/eunit.hrl").
+
+%% eunit tests
+
+get_date_test() ->
+    ?assertEqual({2014, 5, 20}, herd_simple_formats:get_date("2014-05-20")),
+    ?assertEqual({2014, 5, 20}, herd_simple_formats:get_date("2014-5-20")),
+    ?assertEqual({1970, 1, 1}, herd_simple_formats:get_date("1970-1-1")),
+    ?assertEqual({1970, 1, 1}, herd_simple_formats:get_date("1970-01-01")),
+    ?assertEqual({1970, 12, 31}, herd_simple_formats:get_date("1970-12-31")),
+    ?assertEqual({1970, 1, 1}, herd_simple_formats:get_date("1970-1-1-bla")),
+    ?assertEqual(error, herd_simple_formats:get_date("2000-13-31")),
+    ?assertEqual(error, herd_simple_formats:get_date("2000-10-32")),
+    ?assertEqual(error, herd_simple_formats:get_date("bla-bla-bla")),
+    ?assertEqual(error, herd_simple_formats:get_date("1970-10-bla")),
+    ok.
+
+
+get_time_test() ->
+    ?assertEqual({23, 15, 34}, herd_simple_formats:get_time("23:15:34")),
+    ?assertEqual({12, 0, 11}, herd_simple_formats:get_time("12:00:11")),
+    ?assertEqual({0, 0, 0}, herd_simple_formats:get_time("00:00:00")),
+    ?assertEqual({1, 0, 0}, herd_simple_formats:get_time("01:00:00")),
+    ?assertEqual({0, 1, 0}, herd_simple_formats:get_time("00:01:00")),
+    ?assertEqual({0, 0, 1}, herd_simple_formats:get_time("00:00:01")),
+    ?assertEqual({1, 1, 1}, herd_simple_formats:get_time("01:01:01")),
+    ?assertEqual({23, 59, 59}, herd_simple_formats:get_time("23:59:59")),
+    ?assertEqual(error, herd_simple_formats:get_time("01:01:01:01")),
+    ?assertEqual(error, herd_simple_formats:get_time("01:01:ab")),
+    ?assertEqual(error, herd_simple_formats:get_time("01:01")),
+    ?assertEqual(error, herd_simple_formats:get_time("25:10:10")),
+    ?assertEqual(error, herd_simple_formats:get_time("24:60:10")),
+    ?assertEqual(error, herd_simple_formats:get_time("24:30:60")),
+    ok.
+
+
+get_datetime_test() ->
+    ?assertEqual(error, herd_simple_formats:get_datetime("")),
+    ?assertEqual(error, herd_simple_formats:get_datetime("bla-bla-bla")),
+    ?assertEqual(error, herd_simple_formats:get_datetime("bla-bla-bla bla:bla:bla")),
+    ?assertEqual(error, herd_simple_formats:get_datetime("2014-05-20")),
+    ?assertEqual(error, herd_simple_formats:get_datetime("2014-05-20 bla-bla-bla")),
+    ?assertEqual(error, herd_simple_formats:get_datetime("2014-05-20 bla bla bla")),
+    ?assertEqual(error, herd_simple_formats:get_datetime("blablabla 23:15:34")),
+    ?assertEqual({{2014, 5, 20}, {23, 15, 34}},
+                 herd_simple_formats:get_datetime("2014-05-20 23:15:34")),
+    ?assertEqual({{2014, 5, 20}, {12, 0, 11}},
+                 herd_simple_formats:get_datetime("2014-5-20 12:00:11")),
+    ?assertEqual({{1970, 1, 1}, {0, 0, 0}},
+                 herd_simple_formats:get_datetime("1970-1-1 00:00:00")),
+    ?assertEqual({{1970, 1, 1}, {23, 5, 9}},
+                 herd_simple_formats:get_datetime("1970-01-01 23:05:09")),
+    ?assertEqual({{1970, 12, 31}, {23, 59, 59}},
+                 herd_simple_formats:get_datetime("1970-12-31 23:59:59")),
+    ?assertEqual({{2014, 9, 19}, {12, 59, 30}},
+                 herd_simple_formats:get_datetime("2014-09-19 12:59:30 UTC")),
+    ok.
+
+
+get_ip_test() ->
+    ?assertEqual({0, 0, 0, 0}, herd_simple_formats:get_ip("0.0.0.0")),
+    ?assertEqual({1, 2, 3, 4}, herd_simple_formats:get_ip("1.2.3.4")),
+    ?assertEqual({127, 0, 0, 1}, herd_simple_formats:get_ip("127.0.0.1")),
+    ?assertEqual({255, 255, 255, 255}, herd_simple_formats:get_ip("255.255.255.255")),
+    ?assertEqual({10, 1, 0, 20}, herd_simple_formats:get_ip("10.1.0.20")),
+    ?assertEqual({173, 194, 112, 238}, herd_simple_formats:get_ip("173.194.112.238")),
+    ?assertEqual({93, 158, 134, 3}, herd_simple_formats:get_ip("93.158.134.3")),
+    ?assertEqual(error, herd_simple_formats:get_ip("255.255.255.256")),
+    ?assertEqual(error, herd_simple_formats:get_ip("255.255.255.500")),
+    ?assertEqual(error, herd_simple_formats:get_ip("1.2.3")),
+    ?assertEqual(error, herd_simple_formats:get_ip("-1.2.3.4")),
+    ?assertEqual(error, herd_simple_formats:get_ip("1.2.3.4.5")),
+    ?assertEqual(error, herd_simple_formats:get_ip("a.b.c.d")),
+    ?assertEqual(error, herd_simple_formats:get_ip("hellothere")),
+    ?assertEqual(error, herd_simple_formats:get_ip("127.hello.there.again")),
+    ok.

+ 57 - 0
test/herd_string_test.erl

@@ -0,0 +1,57 @@
+-module(herd_string_test).
+
+-include_lib("eunit/include/eunit.hrl").
+
+%% eunit tests
+
+fill_before_test() ->
+    ?assertEqual("    abcdef", herd_string:fill_before("abcdef", 32, 10)),
+    ?assertEqual("__abc", herd_string:fill_before("abc", $_, 5)),
+    ?assertEqual("01", herd_string:fill_before("1", $0, 2)),
+    ?assertEqual("000000000012345", herd_string:fill_before("12345", $0, 15)),
+    ?assertEqual("abcdef", herd_string:fill_before("abcdef", 32, 5)),
+    ?assertEqual("abcdef", herd_string:fill_before("abcdef", 32, 6)),
+    ?assertEqual(" abcdef", herd_string:fill_before("abcdef", 32, 7)),
+    ok.
+
+
+split_test() ->
+    ?assertEqual(["hello", "there"], herd_string:split("hello there", " ")),
+    ?assertEqual(["he", "o there"], herd_string:split("hello there", "ll")),
+    ?assertEqual(["h", "llo th", "r"], herd_string:split("hello there", "e")),
+    ?assertEqual(["aa", "bbb", "ccc"], herd_string:split("aa___bbb___ccc", "___")),
+    ?assertEqual(["aa", "bbb", "ccc"], herd_string:split("___aa___bbb___ccc", "___")),
+    ?assertEqual(["aa", "bbb", "ccc"], herd_string:split("___aa___bbb___ccc___", "___")),
+    ?assertEqual(["aa", "bbb", "ccc"], herd_string:split("aa___bbb___ccc___", "___")),
+    ?assertEqual([], herd_string:split("", "")),
+    ?assertEqual([], herd_string:split("", "aa")),
+    ?assertEqual(["aa"], herd_string:split("aa", "")),
+    ok.
+
+
+replace_test() ->
+    ?assertEqual("", herd_string:replace("", "old", "new")),
+    ?assertEqual("aa|bb|cc", herd_string:replace("aa--bb--cc", "--", "|")),
+    ?assertEqual("nice Cool", herd_string:replace("nice cool", "cool", "Cool")),
+    ?assertEqual("AAbbcc", herd_string:replace("aabbcc", "aa", "AA")),
+    ?assertEqual("aaBBcc", herd_string:replace("aabbcc", "bb", "BB")),
+    ?assertEqual("aabbCC", herd_string:replace("aabbcc", "cc", "CC")),
+    ?assertEqual("AAbbcc AAbbcc", herd_string:replace("aabbcc aabbcc", "aa", "AA")),
+    ?assertEqual("aaBBcc aaBBcc", herd_string:replace("aabbcc aabbcc", "bb", "BB")),
+    ?assertEqual("aabbCC aabbCC", herd_string:replace("aabbcc aabbcc", "cc", "CC")),
+    ok.
+
+
+escape_xml_test() ->
+    ?assertEqual("hello &lt;b&gt;from &quot;Holliwood&quot;&lt;/b&gt;!",
+                 herd_string:escape_xml("hello <b>from \"Holliwood\"</b>!")),
+    ?assertEqual("one &amp; two", herd_string:escape_xml("one & two")),
+    ok.
+
+
+escape_json_test() ->
+    ?assertEqual("hello \\\"there\\\" and\\n here\\n\\ragain\\t ok.",
+                 herd_string:escape_json("hello \"there\" and\n here\n\ragain\t ok.")),
+    ?assertEqual("\\\\ ok \\\\ ok",
+                 herd_string:escape_json("\\ ok \\ ok")),
+    ok.