From dcf5f427f2921a85a4fd6dd099192c030dd29994 Mon Sep 17 00:00:00 2001 From: Krzysztof Wende Date: Thu, 12 May 2016 19:09:38 +0200 Subject: [PATCH 1/2] Strategy to match on first or on all matches --- lib/slacker/matcher.ex | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/slacker/matcher.ex b/lib/slacker/matcher.ex index 1ef83df..812cb9e 100644 --- a/lib/slacker/matcher.ex +++ b/lib/slacker/matcher.ex @@ -21,13 +21,24 @@ defmodule Slacker.Matcher do defmacro __before_compile__(_env) do quote do def match!(slacker, %{"text" => text} = msg) do - Enum.each(@regex_patterns, fn {pattern, [m, f]} -> - match = Regex.run(pattern, text) - if match do - [_text | captures] = match - :erlang.apply(m, f, [slacker, msg] ++ captures) - end - end) + case @strategy || :many do + :one -> + match = Enum.find(Enum.reverse(@regex_patterns), fn {pattern, [m, f]} -> + text =~ pattern + end) + if {pattern, [m, f]} = match do + [_text | captures] = Regex.run(pattern, text) + apply(m, f, [slacker, msg] ++ captures) + end + :many -> + Enum.each(@regex_patterns, fn {pattern, [m, f]} -> + match = Regex.run(pattern, text) + if match do + [_text | captures] = match + :erlang.apply(m, f, [slacker, msg] ++ captures) + end + end) + end end end end From 5b31b15dce7417b3a2734f7de4152e761830764c Mon Sep 17 00:00:00 2001 From: Krzysztof Wende Date: Thu, 12 May 2016 21:54:45 +0200 Subject: [PATCH 2/2] state --- lib/slacker/matcher.ex | 16 +++++++++------- mix.lock | 2 +- test/slacker/matcher_test.exs | 16 ++++++++-------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/slacker/matcher.ex b/lib/slacker/matcher.ex index 812cb9e..a95fdfb 100644 --- a/lib/slacker/matcher.ex +++ b/lib/slacker/matcher.ex @@ -12,7 +12,7 @@ defmodule Slacker.Matcher do # some integrations don't provide a "text" field, ignore them def handle_cast({:handle_incoming, "message", %{"text" => _} = msg}, state) do - match!(self, msg) + state = match!(self, msg, state) {:noreply, state} end end @@ -20,7 +20,7 @@ defmodule Slacker.Matcher do defmacro __before_compile__(_env) do quote do - def match!(slacker, %{"text" => text} = msg) do + def match!(slacker, %{"text" => text} = msg, state) do case @strategy || :many do :one -> match = Enum.find(Enum.reverse(@regex_patterns), fn {pattern, [m, f]} -> @@ -28,14 +28,16 @@ defmodule Slacker.Matcher do end) if {pattern, [m, f]} = match do [_text | captures] = Regex.run(pattern, text) - apply(m, f, [slacker, msg] ++ captures) + apply(m, f, [slacker, msg] ++ captures ++ [state]) end :many -> - Enum.each(@regex_patterns, fn {pattern, [m, f]} -> + Enum.reduce(@regex_patterns, state, fn {pattern, [m, f]}, state -> match = Regex.run(pattern, text) if match do [_text | captures] = match - :erlang.apply(m, f, [slacker, msg] ++ captures) + :erlang.apply(m, f, [slacker, msg] ++ captures ++ [state]) + else + state end end) end @@ -52,8 +54,8 @@ defmodule Slacker.Matcher do quote do if is_binary(unquote(pattern)) do - def match!(slacker, %{"text" => unquote(pattern)} = msg) do - :erlang.apply(unquote(m), unquote(f), [slacker, msg]) + def match!(slacker, %{"text" => unquote(pattern)} = msg, state) do + :erlang.apply(unquote(m), unquote(f), [slacker, msg, state]) end else @regex_patterns {unquote(pattern), [unquote(m), unquote(f)]} diff --git a/mix.lock b/mix.lock index 782fe88..09dc295 100644 --- a/mix.lock +++ b/mix.lock @@ -8,4 +8,4 @@ "poison": {:hex, :poison, "1.4.0"}, "ranch": {:hex, :ranch, "1.0.0"}, "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.4"}, - "websocket_client": {:git, "git://github.com/jeremyong/websocket_client.git", "f465f229958293949e4a192bea65a7e47bb2f762", []}} + "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "f465f229958293949e4a192bea65a7e47bb2f762", []}} diff --git a/test/slacker/matcher_test.exs b/test/slacker/matcher_test.exs index a31e0b8..15f206b 100644 --- a/test/slacker/matcher_test.exs +++ b/test/slacker/matcher_test.exs @@ -9,36 +9,36 @@ defmodule Slacker.MatcherTest do match ~r/say hi to robot #([0-9]+)/, :say_hello match ~r/say bye to robot #([0-9]+)/, :say_goodbye - def say_hi(pid, msg) do + def say_hi(pid, msg, _state) do send pid, "#{msg["text"]} there" end - def say_hello(pid, msg) do + def say_hello(pid, msg, _state) do send pid, "#{msg["text"]} again" end - def say_hello(pid, _msg, robot_number) do + def say_hello(pid, _msg, robot_number, _state) do send pid, "hello, robot #{robot_number}" end - def say_goodbye(pid, _msg, robot_number) do + def say_goodbye(pid, _msg, robot_number, _state) do send pid, "bye, robot #{robot_number}" end end test "match!/2 matches strings" do - Test.match!(self, %{"text" => "hi"}) + Test.match!(self, %{"text" => "hi"}, %{}) assert_receive "hi there" - Test.match!(self, %{"text" => "hello"}) + Test.match!(self, %{"text" => "hello"}, %{}) assert_receive "hello again" end test "match!/3 matches regexes" do - Test.match!(self, %{"text" => "say hi to robot #123"}) + Test.match!(self, %{"text" => "say hi to robot #123"}, %{}) assert_receive "hello, robot 123" - Test.match!(self, %{"text" => "say bye to robot #123"}) + Test.match!(self, %{"text" => "say bye to robot #123"}, %{}) assert_receive "bye, robot 123" end end