{"id":13561985,"url":"https://github.com/efcasado/behaviours2","last_synced_at":"2025-06-27T01:07:18.705Z","repository":{"id":26950265,"uuid":"30413205","full_name":"efcasado/behaviours2","owner":"efcasado","description":"Erlang behaviours on steroids.","archived":false,"fork":false,"pushed_at":"2022-12-03T08:54:00.000Z","size":25,"stargazers_count":8,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-03T17:39:22.289Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/efcasado.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-02-06T13:24:05.000Z","updated_at":"2024-01-01T00:53:36.000Z","dependencies_parsed_at":"2023-01-14T05:40:34.494Z","dependency_job_id":null,"html_url":"https://github.com/efcasado/behaviours2","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/efcasado/behaviours2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efcasado%2Fbehaviours2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efcasado%2Fbehaviours2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efcasado%2Fbehaviours2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efcasado%2Fbehaviours2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/efcasado","download_url":"https://codeload.github.com/efcasado/behaviours2/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efcasado%2Fbehaviours2/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262170242,"owners_count":23269607,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T13:01:03.310Z","updated_at":"2025-06-27T01:07:18.654Z","avatar_url":"https://github.com/efcasado.png","language":"Erlang","funding_links":[],"categories":["Erlang"],"sub_categories":[],"readme":"behaviours2\n===========\n\nErlang behaviours on steroids.\n\n\n`behaviours2` allows developers to provide sound defaults for a behaviour's\ncallbacks. `behaviours2`'s parse transform will automatically inject a\ncallback's default implementation unless the user overwrites it by providing\na custom implementation.\n\n### Examples\n\n##### Simple behaviour\n\n```erlang\n-module(my_awesome_behaviour).\n\n%% To avoid problems when using `warnings_as_errors`\n-export([export_all]).\n\n-type t1() :: any().\n-type t2() :: any().\n\n-callback f1() -\u003e t1().\n-callback f2() -\u003e t2().\n-callback f3() -\u003e t2().\n\nf1() -\u003e\n    'default_f1'.\n\nf2() -\u003e\n    'default_f2'.\n    \nf3() -\u003e\n    f2().\n```\n\n```erlang\n-module(my_awesome_module).\n\n-compile({parse_transform, bhvs2_pt}).\n\n-behaviour(my_awesome_behaviour).\n\nf2() -\u003e\n  'custom_f2'.\n\n```\n\n```erlang\nmy_awesome_module:f1().\n% =\u003e default_f1\n\nmy_awesome_module:f2().\n% =\u003e custom_f2\n\nmy_awesome_module:f3().\n% =\u003e custom_f2.\n```\n\nNote that `f1` and `f3` were automatically injected into `my_awesome_module`. Note as well that no\nexplicit exports for the injected callback functions nor the provided one were required.\n\n##### gen_server (echo server)\n\nThe code snippet below illustrates how much effort it would take to\nwrite an echo server.\n\n```erlang\n-module(echo_server).\n\n-compile({parse_transform, bhv2_pt}).\n\n-behaviour(gen_server).\n\n-export([handle_call/3]).\n\nhandle_call(Msg, From, State) -\u003e\n  Reply = Msg,\n  {reply, Msg, State}.\n\n```\n\nBelow is its plain Erlang/OTP counterpart.\n\n```erlang\n-module(echo_server).\n\n-behaviour(gen_server).\n\n-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,\n         code_change/3]).\n\n-record(state, {}).\n\n-type state() :: #state{}.\n\n-spec init(Args :: []) -\u003e\n          {ok, state()} |\n          {ok, state(), timeout()} |\n          ignore |\n          {stop, Reason :: term()}.\ninit([]) -\u003e\n    {ok, #state{}}.\n\n-spec handle_call(Request :: term(),\n                  From :: {pid(), Tag :: term()},\n                  State :: state()) -\u003e\n          {reply, Reply :: term(), state()} |\n          {reply, Reply :: term(), state(), timeout()} |\n          {noreply, state()} |\n          {noreply, state(), timeout()} |\n          {stop, Reason :: term(), Reply :: term(), state()} |\n          {stop, Reason :: term(), state()}.\nhandle_call(Msg, _From, State) -\u003e\n    Reply = Msg,\n    {reply, Reply, State}.\n\n-spec handle_cast(Msg :: term(),\n                  State :: state()) -\u003e\n          {noreply, state()} |\n          {noreply, state(), timeout()} |\n          {stop, Reason :: term(), state()}.\nhandle_cast(Msg, State) -\u003e\n        {noreply, State}.\n\n-spec handle_info(Info :: term(),\n                  State :: state()) -\u003e\n          {noreply, state()} |\n          {noreply, state(), timeout()} |\n          {stop, Reason :: term(), state()}.\nhandle_info(Info, State) -\u003e\n    {noreply, State}.\n\n-spec terminate(Reason :: term(),\n                State :: state()) -\u003e any().\nterminate(_Reason, _State) -\u003e\n    ok.\n\n-spec code_change(OldVsn :: term() | {down, Vsn :: term()},\n                  State :: state(),\n                  Extra :: term()) -\u003e\n          {ok, NewState :: state()}.\ncode_change(_OldVsn, State, _Extra) -\u003e\n    {ok, State}.\n```\n\nQuite a significant difference. Don't you think?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fefcasado%2Fbehaviours2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fefcasado%2Fbehaviours2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fefcasado%2Fbehaviours2/lists"}