From f801e6a46fe378c7316e0556a804785a57d9d2cc Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 11 Sep 2017 23:07:31 +0100 Subject: [PATCH 1/4] Update the library to allow and prefer binary group names --- lib/fun_with_flags/gate.ex | 6 +++--- lib/fun_with_flags/store/serializer/ecto.ex | 2 +- lib/fun_with_flags/store/serializer/redis.ex | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/fun_with_flags/gate.ex b/lib/fun_with_flags/gate.ex index b7c28fb0..ebf7c7e3 100644 --- a/lib/fun_with_flags/gate.ex +++ b/lib/fun_with_flags/gate.ex @@ -16,16 +16,16 @@ defmodule FunWithFlags.Gate do def new(:group, group_name, enabled) when is_boolean(enabled) do validate_group_name(group_name) - %__MODULE__{type: :group, for: group_name, enabled: enabled} + %__MODULE__{type: :group, for: to_string(group_name), enabled: enabled} end defmodule InvalidGroupNameError do defexception [:message] end - defp validate_group_name(name) when is_atom(name), do: nil + defp validate_group_name(name) when is_binary(name) or is_atom(name), do: nil defp validate_group_name(name) do - raise InvalidGroupNameError, "invalid group name '#{inspect(name)}', it should be an atom." + raise InvalidGroupNameError, "invalid group name '#{inspect(name)}', it should be a binary or an atom." end diff --git a/lib/fun_with_flags/store/serializer/ecto.ex b/lib/fun_with_flags/store/serializer/ecto.ex index 9a5bb43a..240dd30b 100644 --- a/lib/fun_with_flags/store/serializer/ecto.ex +++ b/lib/fun_with_flags/store/serializer/ecto.ex @@ -35,7 +35,7 @@ defmodule FunWithFlags.Store.Serializer.Ecto do end defp do_deserialize_gate(%Record{gate_type: "group", enabled: enabled, target: target}) do - %Gate{type: :group, for: String.to_atom(target), enabled: enabled} + %Gate{type: :group, for: target, enabled: enabled} end def to_atom(atm) when is_atom(atm), do: atm diff --git a/lib/fun_with_flags/store/serializer/redis.ex b/lib/fun_with_flags/store/serializer/redis.ex index b8ae93b4..b92cdf0e 100644 --- a/lib/fun_with_flags/store/serializer/redis.ex +++ b/lib/fun_with_flags/store/serializer/redis.ex @@ -29,7 +29,7 @@ defmodule FunWithFlags.Store.Serializer.Redis do end def deserialize_gate(["group/" <> group_name, enabled]) do - %Gate{type: :group, for: String.to_atom(group_name), enabled: parse_bool(enabled)} + %Gate{type: :group, for: group_name, enabled: parse_bool(enabled)} end def deserialize_flag(name, []), do: Flag.new(name, []) From 3b156d18554c287ee1b0e332a905561f1825f670 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 11 Sep 2017 23:30:16 +0100 Subject: [PATCH 2/4] Update tests to not check for atom group names, as now they are converted to binaries --- test/fun_with_flags/gate_test.exs | 15 ++++++++++----- test/fun_with_flags/simple_store_test.exs | 4 ++-- .../fun_with_flags/store/persistent/ecto_test.exs | 4 ++-- .../store/persistent/redis_test.exs | 4 ++-- .../fun_with_flags/store/serializer/ecto_test.exs | 10 +++++----- .../store/serializer/redis_test.exs | 12 +++++++++--- test/fun_with_flags/store_test.exs | 6 +++--- test/support/test_user.ex | 11 +++++++++-- 8 files changed, 42 insertions(+), 24 deletions(-) diff --git a/test/fun_with_flags/gate_test.exs b/test/fun_with_flags/gate_test.exs index 0f62d82d..1c17b36d 100644 --- a/test/fun_with_flags/gate_test.exs +++ b/test/fun_with_flags/gate_test.exs @@ -27,13 +27,18 @@ defmodule FunWithFlags.GateTest do end end - test "new(:group, group_name, true|false) returns a new Group Gate" do - assert %Gate{type: :group, for: :plants, enabled: true} = Gate.new(:group, :plants, true) - assert %Gate{type: :group, for: :animals, enabled: false} = Gate.new(:group, :animals, false) + test "new(:group, group_name, true|false) returns a new Group Gate, with atoms" do + assert %Gate{type: :group, for: "plants", enabled: true} = Gate.new(:group, :plants, true) + assert %Gate{type: :group, for: "animals", enabled: false} = Gate.new(:group, :animals, false) end - test "new(:group, ...) with a name that is not an atom raises an exception" do - assert_raise FunWithFlags.Gate.InvalidGroupNameError, fn() -> Gate.new(:group, "a_binary", true) end + test "new(:group, group_name, true|false) returns a new Group Gate, with binaries" do + assert %Gate{type: :group, for: "plants", enabled: true} = Gate.new(:group, "plants", true) + assert %Gate{type: :group, for: "animals", enabled: false} = Gate.new(:group, "animals", false) + end + + test "new(:group, ...) with a name that is not an atom or a binary raises an exception" do + assert_raise FunWithFlags.Gate.InvalidGroupNameError, fn() -> Gate.new(:group, 123, true) end assert_raise FunWithFlags.Gate.InvalidGroupNameError, fn() -> Gate.new(:group, %{a: "map"}, false) end end end diff --git a/test/fun_with_flags/simple_store_test.exs b/test/fun_with_flags/simple_store_test.exs index 3e95c6d9..7e1d1b64 100644 --- a/test/fun_with_flags/simple_store_test.exs +++ b/test/fun_with_flags/simple_store_test.exs @@ -40,7 +40,7 @@ defmodule FunWithFlags.SimpleStoreTest do describe "delete(flag_name, gate)" do setup do - group_gate = %Gate{type: :group, for: :muggles, enabled: false} + group_gate = %Gate{type: :group, for: "muggles", enabled: false} bool_gate = %Gate{type: :boolean, enabled: true} name = unique_atom() @@ -76,7 +76,7 @@ defmodule FunWithFlags.SimpleStoreTest do describe "delete(flag_name)" do setup do - group_gate = %Gate{type: :group, for: :muggles, enabled: false} + group_gate = %Gate{type: :group, for: "muggles", enabled: false} bool_gate = %Gate{type: :boolean, enabled: true} name = unique_atom() diff --git a/test/fun_with_flags/store/persistent/ecto_test.exs b/test/fun_with_flags/store/persistent/ecto_test.exs index a32fa56c..14449b58 100644 --- a/test/fun_with_flags/store/persistent/ecto_test.exs +++ b/test/fun_with_flags/store/persistent/ecto_test.exs @@ -130,7 +130,7 @@ defmodule FunWithFlags.Store.Persistent.EctoTest do setup do name = unique_atom() bool_gate = %Gate{type: :boolean, enabled: false} - group_gate = %Gate{type: :group, for: :admins, enabled: true} + group_gate = %Gate{type: :group, for: "admins", enabled: true} actor_gate = %Gate{type: :actor, for: "string_actor", enabled: true} flag = %Flag{name: name, gates: sort_gates([bool_gate, group_gate, actor_gate])} @@ -261,7 +261,7 @@ defmodule FunWithFlags.Store.Persistent.EctoTest do setup do name = unique_atom() bool_gate = %Gate{type: :boolean, enabled: false} - group_gate = %Gate{type: :group, for: :admins, enabled: true} + group_gate = %Gate{type: :group, for: "admins", enabled: true} actor_gate = %Gate{type: :actor, for: "string_actor", enabled: true} flag = %Flag{name: name, gates: sort_gates([bool_gate, group_gate, actor_gate])} diff --git a/test/fun_with_flags/store/persistent/redis_test.exs b/test/fun_with_flags/store/persistent/redis_test.exs index d78fb0db..f84f0e10 100644 --- a/test/fun_with_flags/store/persistent/redis_test.exs +++ b/test/fun_with_flags/store/persistent/redis_test.exs @@ -217,7 +217,7 @@ defmodule FunWithFlags.Store.Persistent.RedisTest do setup do name = unique_atom() bool_gate = %Gate{type: :boolean, enabled: false} - group_gate = %Gate{type: :group, for: :admins, enabled: true} + group_gate = %Gate{type: :group, for: "admins", enabled: true} actor_gate = %Gate{type: :actor, for: "string_actor", enabled: true} flag = %Flag{name: name, gates: [bool_gate, group_gate, actor_gate]} @@ -428,7 +428,7 @@ defmodule FunWithFlags.Store.Persistent.RedisTest do setup do name = unique_atom() bool_gate = %Gate{type: :boolean, enabled: false} - group_gate = %Gate{type: :group, for: :admins, enabled: true} + group_gate = %Gate{type: :group, for: "admins", enabled: true} actor_gate = %Gate{type: :actor, for: "string_actor", enabled: true} flag = %Flag{name: name, gates: [bool_gate, group_gate, actor_gate]} diff --git a/test/fun_with_flags/store/serializer/ecto_test.exs b/test/fun_with_flags/store/serializer/ecto_test.exs index 62045c35..9d74cfaa 100644 --- a/test/fun_with_flags/store/serializer/ecto_test.exs +++ b/test/fun_with_flags/store/serializer/ecto_test.exs @@ -39,7 +39,7 @@ defmodule FunWithFlags.Store.Serializer.EctoTest do flag = %Flag{name: flag_name, gates: [ %Gate{type: :actor, for: "user:123", enabled: true}, %Gate{type: :boolean, enabled: true}, - %Gate{type: :group, for: :admins, enabled: false}, + %Gate{type: :group, for: "admins", enabled: false}, ]} assert ^flag = Serializer.deserialize_flag(flag_name, [bool_record, actor_record, group_record]) @@ -47,8 +47,8 @@ defmodule FunWithFlags.Store.Serializer.EctoTest do %Gate{type: :actor, for: "user:123", enabled: true}, %Gate{type: :actor, for: "string:albicocca", enabled: false}, %Gate{type: :boolean, enabled: true}, - %Gate{type: :group, for: :admins, enabled: false}, - %Gate{type: :group, for: :penguins, enabled: true}, + %Gate{type: :group, for: "admins", enabled: false}, + %Gate{type: :group, for: "penguins", enabled: true}, ]} actor_record_2 = %{actor_record | id: 5, target: "string:albicocca", enabled: false} @@ -82,10 +82,10 @@ defmodule FunWithFlags.Store.Serializer.EctoTest do test "with group data", %{flag_name: flag_name, group_record: group_record} do group_record = %{group_record | enabled: true} - assert %Gate{type: :group, for: :admins, enabled: true} = Serializer.deserialize_gate(flag_name, group_record) + assert %Gate{type: :group, for: "admins", enabled: true} = Serializer.deserialize_gate(flag_name, group_record) group_record = %{group_record | enabled: false} - assert %Gate{type: :group, for: :admins, enabled: false} = Serializer.deserialize_gate(flag_name, group_record) + assert %Gate{type: :group, for: "admins", enabled: false} = Serializer.deserialize_gate(flag_name, group_record) end end end diff --git a/test/fun_with_flags/store/serializer/redis_test.exs b/test/fun_with_flags/store/serializer/redis_test.exs index 2a8f4963..eae12982 100644 --- a/test/fun_with_flags/store/serializer/redis_test.exs +++ b/test/fun_with_flags/store/serializer/redis_test.exs @@ -30,6 +30,12 @@ defmodule FunWithFlags.Store.Serializer.RedisTest do gate = %Gate{type: :group, for: :swimmers, enabled: false} assert ["group/swimmers", "false"] = Serializer.serialize(gate) + + gate = %Gate{type: :group, for: "runners", enabled: true} + assert ["group/runners", "true"] = Serializer.serialize(gate) + + gate = %Gate{type: :group, for: "swimmers", enabled: false} + assert ["group/swimmers", "false"] = Serializer.serialize(gate) end end @@ -61,7 +67,7 @@ defmodule FunWithFlags.Store.Serializer.RedisTest do %Gate{type: :actor, for: "string:albicocca", enabled: true}, %Gate{type: :boolean, enabled: false}, %Gate{type: :actor, for: "user:123", enabled: false}, - %Gate{type: :group, for: :penguins, enabled: true}, + %Gate{type: :group, for: "penguins", enabled: true}, ]} raw_redis_data = [ @@ -86,8 +92,8 @@ defmodule FunWithFlags.Store.Serializer.RedisTest do end test "with group data" do - assert %Gate{type: :group, for: :fishes, enabled: true} = Serializer.deserialize_gate(["group/fishes", "true"]) - assert %Gate{type: :group, for: :cetacea, enabled: false} = Serializer.deserialize_gate(["group/cetacea", "false"]) + assert %Gate{type: :group, for: "fishes", enabled: true} = Serializer.deserialize_gate(["group/fishes", "true"]) + assert %Gate{type: :group, for: "cetacea", enabled: false} = Serializer.deserialize_gate(["group/cetacea", "false"]) end end diff --git a/test/fun_with_flags/store_test.exs b/test/fun_with_flags/store_test.exs index 34ab3326..4ac06354 100644 --- a/test/fun_with_flags/store_test.exs +++ b/test/fun_with_flags/store_test.exs @@ -57,7 +57,7 @@ defmodule FunWithFlags.StoreTest do describe "delete(flag_name, gate)" do setup data do - group_gate = %Gate{type: :group, for: :muggles, enabled: false} + group_gate = %Gate{type: :group, for: "muggles", enabled: false} bool_gate = data[:gate] name = data[:name] @@ -93,7 +93,7 @@ defmodule FunWithFlags.StoreTest do describe "delete(flag_name)" do setup data do - group_gate = %Gate{type: :group, for: :muggles, enabled: false} + group_gate = %Gate{type: :group, for: "muggles", enabled: false} bool_gate = data[:gate] name = data[:name] @@ -258,7 +258,7 @@ defmodule FunWithFlags.StoreTest do describe "integration: Cache and Persistence" do setup data do - group_gate = %Gate{type: :group, for: :muggles, enabled: false} + group_gate = %Gate{type: :group, for: "muggles", enabled: false} bool_gate = data[:gate] {:ok, bool_gate: bool_gate, group_gate: group_gate} end diff --git a/test/support/test_user.ex b/test/support/test_user.ex index 29d64314..87ecf809 100644 --- a/test/support/test_user.ex +++ b/test/support/test_user.ex @@ -11,11 +11,18 @@ end defimpl FunWithFlags.Group, for: FunWithFlags.TestUser do - def in?(%{email: email}, :admin) do + def in?(%{email: email}, "admin") do Regex.match?(~r/@wayne.com$/, email) end + def in?(user, :admin) do + __MODULE__.in?(user, "admin") + end + + # Matches binaries or atoms. + # def in?(%{groups: groups}, group) when is_list(groups) do - group in groups + group_s = to_string(group) + Enum.any? groups, fn(g) -> to_string(g) == group_s end end end From e692df76196b351323896285cdb2021eb9c41c78 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 11 Sep 2017 23:45:05 +0100 Subject: [PATCH 3/4] update documentation to clarify that group names can be binaries and binaries are actually preferred --- README.md | 32 +++++++++++++++++--------------- lib/fun_with_flags.ex | 42 ++++++++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 401f0852..75fc16c5 100644 --- a/README.md +++ b/README.md @@ -165,10 +165,12 @@ end ### Group Gate -Group gates are similar to actor gates, but they apply to a category of entities rather than specific ones. They can be toggled on or off for the _name of the group_ (as an atom) instead of a specific term. +Group gates are similar to actor gates, but they apply to a category of entities rather than specific ones. They can be toggled on or off for the _name of the group_ instead of a specific term. Group gates take precendence over boolean gates but are overridden by actor gates. +Group names can be binaries or atoms. Atoms are supported for retro-compatibility with versions `<= 0.9` and binaries are therefore preferred. In fact, atoms are internally converted to binaries and are then stored and later retrieved as binaries. + The semantics to determine which entities belong to which groups are application specific. Entities could have an explicit list of groups they belong to, or the groups could be abstract and inferred from some other attribute. For example, an `:employee` group could comprise all `%User{}` structs with an email address matching the company domain, or an `:admin` group could be made of all users with `%User{admin: true}`. @@ -183,19 +185,19 @@ defmodule MyApp.User do end defimpl FunWithFlags.Group, for: MyApp.User do - def in?(%{email: email}, :employee), do: Regex.match?(~r/@mycompany.com$/, email) - def in?(%{admin: is_admin}, :admin), do: !!is_admin + def in?(%{email: email}, "employee"), do: Regex.match?(~r/@mycompany.com$/, email) + def in?(%{admin: is_admin}, "admin"), do: !!is_admin def in?(%{groups: list}, group_name), do: group_name in list end -elisabeth = %User{email: "elisabeth@mycompany.com", admin: true, groups: [:engineering, :product]} -FunWithFlags.Group.in?(elisabeth, :employee) +elisabeth = %User{email: "elisabeth@mycompany.com", admin: true, groups: ["engineering", "product"]} +FunWithFlags.Group.in?(elisabeth, "employee") true -FunWithFlags.Group.in?(elisabeth, :admin) +FunWithFlags.Group.in?(elisabeth, "admin") true -FunWithFlags.Group.in?(elisabeth, :engineering) +FunWithFlags.Group.in?(elisabeth, "engineering") true -FunWithFlags.Group.in?(elisabeth, :marketing) +FunWithFlags.Group.in?(elisabeth, "marketing") false defimpl FunWithFlags.Group, for: Map do @@ -203,7 +205,7 @@ defimpl FunWithFlags.Group, for: Map do def in?(_, _), do: false end -FunWithFlags.Group.in?(%{group: :dumb_tests}, :dumb_tests) +FunWithFlags.Group.in?(%{group: "dumb_tests"}, "dumb_tests") true ``` @@ -211,7 +213,7 @@ With the protocol implemented, actors can be used with the library functions: ```elixir FunWithFlags.disable(:database_access) -FunWithFlags.enable(:database_access, for_group: :engineering) +FunWithFlags.enable(:database_access, for_group: "engineering") FunWithFlags.enabled?(:database_access) false @@ -227,11 +229,11 @@ More examples: ```elixir alias FunWithFlags.TestUser, as: User -harry = %User{id: 1, name: "Harry Potter", groups: [:wizards, :gryffindor]} -hagrid = %User{id: 2, name: "Rubeus Hagrid", groups: [:wizards, :gamekeeper]} -dudley = %User{id: 3, name: "Dudley Dursley", groups: [:muggles]} +harry = %User{id: 1, name: "Harry Potter", groups: ["wizards", "gryffindor"]} +hagrid = %User{id: 2, name: "Rubeus Hagrid", groups: ["wizards", "gamekeeper"]} +dudley = %User{id: 3, name: "Dudley Dursley", groups: ["muggles"]} FunWithFlags.disable(:wands) -FunWithFlags.enable(:wands, for_group: :wizards) +FunWithFlags.enable(:wands, for_group: "wizards") FunWithFlags.disable(:wands, for_actor: hagrid) FunWithFlags.enabled?(:wands) @@ -247,7 +249,7 @@ FunWithFlags.clear(:wands, for_actor: hagrid) FunWithFlags.enabled?(:wands, for: hagrid) true -FunWithFlags.clear(:wands, for_group: :wizards) +FunWithFlags.clear(:wands, for_group: "wizards") FunWithFlags.enabled?(:wands, for: hagrid) false FunWithFlags.enabled?(:wands, for: harry) diff --git a/lib/fun_with_flags.ex b/lib/fun_with_flags.ex index fffd1411..2ab5b9bf 100644 --- a/lib/fun_with_flags.ex +++ b/lib/fun_with_flags.ex @@ -51,18 +51,18 @@ defmodule FunWithFlags do used in the tests. iex> alias FunWithFlags.TestUser, as: User - iex> harry = %User{id: 1, name: "Harry Potter", groups: [:wizards, :gryffindor]} + iex> harry = %User{id: 1, name: "Harry Potter", groups: ["wizards", "gryffindor"]} iex> FunWithFlags.disable(:elder_wand) iex> FunWithFlags.enable(:elder_wand, for_actor: harry) iex> FunWithFlags.enabled?(:elder_wand) false iex> FunWithFlags.enabled?(:elder_wand, for: harry) true - iex> voldemort = %User{id: 7, name: "Tom Riddle", groups: [:wizards, :slytherin]} + iex> voldemort = %User{id: 7, name: "Tom Riddle", groups: ["wizards", "slytherin"]} iex> FunWithFlags.enabled?(:elder_wand, for: voldemort) false - iex> filch = %User{id: 88, name: "Argus Filch", groups: [:staff]} - iex> FunWithFlags.enable(:magic_wands, for_group: :wizards) + iex> filch = %User{id: 88, name: "Argus Filch", groups: ["staff"]} + iex> FunWithFlags.enable(:magic_wands, for_group: "wizards") iex> FunWithFlags.enabled?(:magic_wands, for: harry) true iex> FunWithFlags.enabled?(:magic_wands, for: voldemort) @@ -103,7 +103,9 @@ defmodule FunWithFlags do * `:for_actor` - used to enable the flag for a specific term only. The value can be any term that implements the `Actor` protocol. * `:for_group` - used to enable the flag for a specific group only. - The value should be an atom. + The value should be a binary or an atom (It's internally converted + to a binary and it's stored and retrieved as a binary. Atoms are + supported for retro-compatibility with versions <= 0.9) ## Examples @@ -133,10 +135,10 @@ defmodule FunWithFlags do used in the tests. iex> alias FunWithFlags.TestUser, as: User - iex> marty = %User{name: "Marty McFly", groups: [:students, :time_travelers]} - iex> doc = %User{name: "Emmet Brown", groups: [:scientists, :time_travelers]} - iex> buford = %User{name: "Buford Tannen", groups: [:gunmen, :bandits]} - iex> FunWithFlags.enable(:delorean, for_group: :time_travelers) + iex> marty = %User{name: "Marty McFly", groups: ["students", "time_travelers"]} + iex> doc = %User{name: "Emmet Brown", groups: ["scientists", "time_travelers"]} + iex> buford = %User{name: "Buford Tannen", groups: ["gunmen", "bandits"]} + iex> FunWithFlags.enable(:delorean, for_group: "time_travelers") {:ok, true} iex> FunWithFlags.enabled?(:delorean) false @@ -187,7 +189,9 @@ defmodule FunWithFlags do * `:for_actor` - used to disable the flag for a specific term only. The value can be any term that implements the `Actor` protocol. * `:for_group` - used to disable the flag for a specific group only. - The value should be an atom. + The value should be a binary or an atom (It's internally converted + to a binary and it's stored and retrieved as a binary. Atoms are + supported for retro-compatibility with versions <= 0.9) ## Examples @@ -220,11 +224,11 @@ defmodule FunWithFlags do used in the tests. iex> alias FunWithFlags.TestUser, as: User - iex> harry = %User{name: "Harry Potter", groups: [:wizards, :gryffindor]} - iex> dudley = %User{name: "Dudley Dursley", groups: [:muggles]} + iex> harry = %User{name: "Harry Potter", groups: ["wizards", "gryffindor"]} + iex> dudley = %User{name: "Dudley Dursley", groups: ["muggles"]} iex> FunWithFlags.enable(:hogwarts) {:ok, true} - iex> FunWithFlags.disable(:hogwarts, for_group: :muggles) + iex> FunWithFlags.disable(:hogwarts, for_group: "muggles") {:ok, false} iex> FunWithFlags.enabled?(:hogwarts) true @@ -284,16 +288,18 @@ defmodule FunWithFlags do * `:for_actor` - used to clear the flag for a specific term only. The value can be any term that implements the `Actor` protocol. * `:for_group` - used to clear the flag for a specific group only. - The value should be an atom. + The value should be a binary or an atom (It's internally converted + to a binary and it's stored and retrieved as a binary. Atoms are + supported for retro-compatibility with versions <= 0.9) ## Examples iex> alias FunWithFlags.TestUser, as: User - iex> harry = %User{id: 1, name: "Harry Potter", groups: [:wizards, :gryffindor]} - iex> hagrid = %User{id: 2, name: "Rubeus Hagrid", groups: [:wizards, :gamekeeper]} - iex> dudley = %User{id: 3, name: "Dudley Dursley", groups: [:muggles]} + iex> harry = %User{id: 1, name: "Harry Potter", groups: ["wizards", "gryffindor"]} + iex> hagrid = %User{id: 2, name: "Rubeus Hagrid", groups: ["wizards", "gamekeeper"]} + iex> dudley = %User{id: 3, name: "Dudley Dursley", groups: ["muggles"]} iex> FunWithFlags.disable(:wands) - iex> FunWithFlags.enable(:wands, for_group: :wizards) + iex> FunWithFlags.enable(:wands, for_group: "wizards") iex> FunWithFlags.disable(:wands, for_actor: hagrid) iex> iex> FunWithFlags.enabled?(:wands) From 1d27c5b71521a6a7de0974755da988bb0f0a937f Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 11 Sep 2017 23:52:35 +0100 Subject: [PATCH 4/4] update the changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02a7ceb0..42cf7f4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## Unreleased +Possibly Breaking Changes: + +* Allow binaries _and_ atoms as group gate names. Binaries are now preferred (atom group names are internally converted, stored and retrieved as binaries) and atoms are still allowed for retro-compatibility. +While calling `FunWithFlags.enable(:foo, for_group: :bar)` is still allowed and continues to work as before, this change will impact implementations of the `FunWithFlags.Group` protocol that assume +that the group name is passed as an atom. +To safely upgrade, these implementations should be changed to work with the group names passed as a binary instead. See the [update to the protocol implementation used in the tests](https://github.com/tompave/fun_with_flags/pull/13/files#diff-8c1bcfc3d51e8d863953ac5b57f0da2b) for an example. + +Other changes: + * Compatibility updates for Ecto 2.2 (dev env, was fine in prod) ## v0.9.2