Skip to content

Instantly share code, notes, and snippets.

@mietek
Created September 14, 2010 21:34
Show Gist options
  • Save mietek/579818 to your computer and use it in GitHub Desktop.
Save mietek/579818 to your computer and use it in GitHub Desktop.
-module(util_record).
-compile(export_all).
-define(NAME_ELEMENT, 1).
-define(VERSION_ELEMENT, 2).
-spec update_record(atom(), fun(), tuple()) -> tuple().
update_record(Name, UpdateFun, Record) ->
case {element(?NAME_ELEMENT, Record), element(?VERSION_ELEMENT, Record)} of
{Name, {version, Version}} ->
UpdateFun(Version, Record);
{Name, _NotVersioned} ->
UpdateFun(not_versioned, Record)
end.
-spec insert_version(integer(), tuple()) -> tuple().
insert_version(Version, Record) ->
insert_element(?VERSION_ELEMENT, {version, Version}, Record).
-spec update_version(integer(), tuple()) -> tuple().
update_version(Version, Record) ->
update_element(?VERSION_ELEMENT, fun (_) -> {version, Version} end, Record).
-spec insert_field(integer(), term(), tuple()) -> tuple().
insert_field(Position, Value, Record) ->
insert_element(Position + 1, Value, Record).
-spec update_field(integer(), fun(), tuple()) -> tuple().
update_field(Position, UpdateFun, Record) ->
update_element(Position + 1, UpdateFun, Record).
-spec remove_field(integer(), tuple()) -> tuple().
remove_field(Position, Record) ->
remove_element(Position + 1, Record).
-spec insert_element(integer(), term(), tuple()) -> tuple().
insert_element(Position, Value, Tuple) ->
{Elements1, Elements2} = lists:split(Position - 1, tuple_to_list(Tuple)),
list_to_tuple(Elements1 ++ [Value | Elements2]).
-spec update_element(integer(), fun(), tuple()) -> tuple().
update_element(Position, UpdateFun, Tuple) ->
{Elements1, [OldValue | Elements2]} = lists:split(Position - 1, tuple_to_list(Tuple)),
Value = UpdateFun(OldValue),
list_to_tuple(Elements1 ++ [Value | Elements2]).
-spec remove_element(integer(), tuple()) -> tuple().
remove_element(Position, Tuple) ->
{Elements1, [_OldValue | Elements2]} = lists:split(Position - 1, tuple_to_list(Tuple)),
list_to_tuple(Elements1 ++ Elements2).
-module(x_version_1).
-import(util_record, [insert_version/2,
update_version/2,
insert_field/3,
update_record/3]).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
% -record(x, {field_a :: string()}).
-record(x, {version = {version, 1} :: {version, integer()},
field_a :: string()}).
-spec update_x(not_versioned | integer(), tuple()) -> #x{}.
update_x(not_versioned, X) ->
update_x(1, insert_version(1, X));
update_x(1, X) ->
X.
-spec update_x(tuple()) -> #x{}.
update_x(X) ->
update_record(x, fun update_x/2, X).
update_x_not_versioned_test() ->
?assertEqual(#x{version = {version, 1},
field_a = "field_a"},
update_x({x, "field_a"})).
update_x_version_1_test() ->
?assertEqual(#x{version = {version, 1},
field_a = "field_a"},
update_x({x, {version, 1}, "field_a"})).
-module(x_version_2).
-import(util_record, [insert_version/2,
update_version/2,
insert_field/3,
update_record/3]).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
% -record(x, {field_a :: string()}).
% -record(x, {version = {version, 1} :: {version, integer()},
% field_a :: string()}).
-record(x, {version = {version, 2} :: {version, integer()},
field_a :: string(),
field_b :: string()}).
-spec update_x(not_versioned | integer(), tuple()) -> #x{}.
update_x(not_versioned, X) ->
update_x(1, insert_version(1, X));
update_x(1, X) ->
update_x(2, update_version(2, insert_field(3, "default_field_b", X)));
update_x(2, X) ->
X.
-spec update_x(tuple()) -> #x{}.
update_x(X) ->
update_record(x, fun update_x/2, X).
update_x_not_versioned_test() ->
?assertEqual(#x{version = {version, 2},
field_a = "field_a",
field_b = "default_field_b"},
update_x({x, "field_a"})).
update_x_version_1_test() ->
?assertEqual(#x{version = {version, 2},
field_a = "field_a",
field_b = "default_field_b"},
update_x({x, {version, 1}, "field_a"})).
update_x_version_2_test() ->
?assertEqual(#x{version = {version, 2},
field_a = "field_a",
field_b = "field_b"},
update_x({x, {version, 2}, "field_a", "field_b"})).
-module(x_version_3).
-import(util_record, [insert_version/2,
update_version/2,
insert_field/3,
remove_field/2,
update_record/3]).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
% -record(x, {field_a :: string()}).
% -record(x, {version = {version, 1} :: {version, integer()},
% field_a :: string()}).
% -record(x, {version = {version, 2} :: {version, integer()},
% field_a :: string(),
% field_b :: string()}).
-record(x, {version = {version, 3} :: {version, integer()},
field_b :: string()}).
-spec update_x(not_versioned | integer(), tuple()) -> #x{}.
update_x(not_versioned, X) ->
update_x(1, insert_version(1, X));
update_x(1, X) ->
update_x(2, update_version(2, insert_field(3, "default_field_b", X)));
update_x(2, X) ->
update_x(3, update_version(3, remove_field(2, X)));
update_x(3, X) ->
X.
-spec update_x(tuple()) -> #x{}.
update_x(X) ->
update_record(x, fun update_x/2, X).
update_x_not_versioned_test() ->
?assertEqual(#x{version = {version, 3},
field_b = "default_field_b"},
update_x({x, "field_a"})).
update_x_version_1_test() ->
?assertEqual(#x{version = {version, 3},
field_b = "default_field_b"},
update_x({x, {version, 1}, "field_a"})).
update_x_version_2_test() ->
?assertEqual(#x{version = {version, 3},
field_b = "field_b"},
update_x({x, {version, 2}, "field_a", "field_b"})).
update_x_version_3_test() ->
?assertEqual(#x{version = {version, 3},
field_b = "field_b"},
update_x({x, {version, 3}, "field_b"})).
-module(x_version_4).
-import(util_record, [insert_version/2,
update_version/2,
insert_field/3,
update_field/3,
remove_field/2,
update_record/3]).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
% -record(x, {field_a :: string()}).
% -record(x, {version = {version, 1} :: {version, integer()},
% field_a :: string()}).
% -record(x, {version = {version, 2} :: {version, integer()},
% field_a :: string(),
% field_b :: string()}).
% -record(x, {version = {version, 3} :: {version, integer()},
% field_b :: string()}).
-record(x, {version = {version, 4} :: {version, integer()},
field_b :: atom()}).
-spec update_x(not_versioned | integer(), tuple()) -> #x{}.
update_x(not_versioned, X) ->
update_x(1, insert_version(1, X));
update_x(1, X) ->
update_x(2, update_version(2, insert_field(3, "default_field_b", X)));
update_x(2, X) ->
update_x(3, update_version(3, remove_field(2, X)));
update_x(3, X) ->
update_x(4, update_version(4, update_field(2, fun list_to_atom/1, X)));
update_x(4, X) ->
X.
-spec update_x(tuple()) -> #x{}.
update_x(X) ->
update_record(x, fun update_x/2, X).
update_x_not_versioned_test() ->
?assertEqual(#x{version = {version, 4},
field_b = default_field_b},
update_x({x, "field_a"})).
update_x_version_1_test() ->
?assertEqual(#x{version = {version, 4},
field_b = default_field_b},
update_x({x, {version, 1}, "field_a"})).
update_x_version_2_test() ->
?assertEqual(#x{version = {version, 4},
field_b = field_b},
update_x({x, {version, 2}, "field_a", "field_b"})).
update_x_version_3_test() ->
?assertEqual(#x{version = {version, 4},
field_b = field_b},
update_x({x, {version, 3}, "field_b"})).
update_x_version_4_test() ->
?assertEqual(#x{version = {version, 4},
field_b = field_b},
update_x({x, {version, 4}, field_b})).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment