├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── erlang.mk ├── rebar.config ├── rebar.lock ├── src ├── Makefile ├── positive.app.src └── positive.erl └── test ├── positive.coverspec └── positive_SUITE.erl /.gitignore: -------------------------------------------------------------------------------- 1 | ebin 2 | logs 3 | positive.d 4 | *.beam 5 | test/*.beam -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | 3 | script: "make all tests" 4 | otp_release: 5 | - 18.2 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jesper Louis Andersen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = positive 2 | 3 | CT_OPTS = -cover test/positive.coverspec 4 | 5 | include erlang.mk 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Positive 2 | 3 | [![Build Status](https://travis-ci.org/jlouis/positive.svg?branch=master)](https://travis-ci.org/jlouis/positive) 4 | 5 | Test if a term is an integer and is positive. 6 | 7 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {deps, []}. 2 | {erl_opts, [debug_info,warn_export_vars,warn_shadow_vars,warn_obsolete_guard]}. 3 | -------------------------------------------------------------------------------- /rebar.lock: -------------------------------------------------------------------------------- 1 | []. 2 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | $(MAKE) -C .. app 3 | -------------------------------------------------------------------------------- /src/positive.app.src: -------------------------------------------------------------------------------- 1 | {application, positive, [ 2 | {description, "Library: check if an integer is positive"}, 3 | {vsn, "13.3.7"}, 4 | {modules, []}, 5 | {registered, []}, 6 | {applications, [ 7 | kernel, 8 | stdlib 9 | ]}, 10 | {env, []}, 11 | 12 | {maintainers, ["Jesper Louis Andersen"]}, 13 | {licenses, ["MIT"]}, 14 | {links, [{"Github", "https://github.com/jlouis/positive"}]} 15 | ]}. 16 | -------------------------------------------------------------------------------- /src/positive.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(positive). 3 | -export([is_positive/1, 'really?'/1, 'perhaps?'/1]). 4 | 5 | %% @doc Checks whether an integer is positive or not. 6 | -spec is_positive(any()) -> boolean(). 7 | is_positive(N) when is_integer(N) -> 8 | N > 0; 9 | is_positive(_) -> false. 10 | 11 | %% @doc Syntax sugar for is_positive/1. 12 | -spec 'really?'(any()) -> boolean(). 13 | 'really?'(N) -> 14 | is_positive(N). 15 | 16 | %% @doc Optimized version of 'really?'/1 that uses heuristics 17 | %% only use this when you are not 'really?' conceared about whether 18 | %% a value is positive but just want to know if it 'perhaps?' is. 19 | -spec 'perhaps?'(any()) -> true. 20 | 'perhaps?'(_N) when is_integer(_N) -> 21 | true; 22 | 'perhaps?'(_) -> 23 | false. 24 | -------------------------------------------------------------------------------- /test/positive.coverspec: -------------------------------------------------------------------------------- 1 | %% Specific modules to include in cover. 2 | { 3 | incl_mods, 4 | [ positive ] 5 | }. -------------------------------------------------------------------------------- /test/positive_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(positive_SUITE). 2 | 3 | -export([all/0]). 4 | -export([is_positive_test/1 5 | , is_positive_but_not_integer_test/1 6 | , is_negative_test/1 7 | , is_not_integer_test/1 8 | , 'is_really?_positive_test'/1 9 | , 'is_really?_negative_test'/1 10 | , 'is_not_really?_integer_test'/1]). 11 | 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | %%% Common Test 14 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15 | 16 | -spec ignored_funs() -> [atom()]. 17 | ignored_funs() -> 18 | [ module_info 19 | , init_per_suite 20 | , end_per_suite 21 | ]. 22 | 23 | -spec all() -> [atom()]. 24 | all() -> 25 | [Fun || {Fun, 1} <- module_info(exports), 26 | not lists:member(Fun, ignored_funs())]. 27 | 28 | -type config() :: proplists:proplist(). 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | %%% Test cases 31 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 32 | 33 | -spec is_positive_test(config()) -> _. 34 | is_positive_test(_Config) -> 35 | PositiveNumbers = lists:seq(1,1000000), 36 | Results = lists:map(fun positive:is_positive/1, PositiveNumbers), 37 | true = lists:all(fun(Bool) -> Bool == true end, Results), 38 | {comment, ""}. 39 | 40 | -spec is_positive_but_not_integer_test(config()) -> _. 41 | is_positive_but_not_integer_test(_Config) -> 42 | PositiveButNotIntegers = [X + 0.1 || X <- lists:seq(1,1000000)], 43 | Results = lists:map(fun positive:is_positive/1, PositiveButNotIntegers), 44 | true = lists:all(fun(Bool) -> Bool == false end, Results), 45 | {comment, ""}. 46 | 47 | -spec is_negative_test(config()) -> _. 48 | is_negative_test(_Config) -> 49 | NegativeNumbers = lists:seq(-1000000, -1), 50 | Results = lists:map(fun positive:is_positive/1, NegativeNumbers), 51 | true = lists:all(fun(Bool) -> Bool == false end, Results), 52 | {comment, ""}. 53 | 54 | -spec is_not_integer_test(config()) -> _. 55 | is_not_integer_test(_Config) -> 56 | Letters = lists:seq($A, $z), 57 | Tuples = module_info(exports), 58 | Atoms = [Fun || {Fun, 1} <- module_info(exports)], 59 | PositiveButNotIntegers = [X + 0.1 || X <- lists:seq(1, 1000000)], 60 | NegativeButNotIntegers = [X - 0.1 || X <- lists:seq(-100000, 0)], 61 | InputList = Letters ++ Tuples ++ Atoms ++ PositiveButNotIntegers ++ 62 | NegativeButNotIntegers, 63 | Results = lists:map(fun positive:is_positive/1, InputList), 64 | false = lists:all(fun(Bool) -> Bool == true end, Results), 65 | {comment, ""}. 66 | 67 | -spec 'is_really?_positive_test'(config()) -> _. 68 | 'is_really?_positive_test'(_Config) -> 69 | PositiveNumbers = lists:seq(1,1000000), 70 | Results = lists:map(fun positive:'really?'/1, PositiveNumbers), 71 | true = lists:all(fun(Bool) -> Bool == true end, Results), 72 | {comment, ""}. 73 | 74 | -spec 'is_really?_negative_test'(config()) -> _. 75 | 'is_really?_negative_test'(_Config) -> 76 | NegativeNumbers = lists:seq(-1000000, -1), 77 | Results = lists:map(fun positive:'really?'/1, NegativeNumbers), 78 | true = lists:all(fun(Bool) -> Bool == false end, Results), 79 | {comment, ""}. 80 | 81 | -spec 'is_not_really?_integer_test'(config()) -> _. 82 | 'is_not_really?_integer_test'(_Config) -> 83 | Letters = lists:seq($A, $z), 84 | Tuples = module_info(exports), 85 | Atoms = [Fun || {Fun, 1} <- module_info(exports)], 86 | InputList = Letters ++ Tuples ++ Atoms, 87 | Results = lists:map(fun positive:is_positive/1, InputList), 88 | false = lists:all(fun(Bool) -> Bool == true end, Results), 89 | {comment, ""}. 90 | --------------------------------------------------------------------------------