├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── lib └── side_effect.ex ├── mix.exs ├── mix.lock └── test ├── side_effect_test.exs └── test_helper.exs /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc 12 | 13 | # If the VM crashes, it generates a dump, let's ignore it too. 14 | erl_crash.dump 15 | 16 | # Also ignore archive artifacts (built via "mix archive.build"). 17 | *.ez 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: elixir 2 | sudo: false 3 | elixir: 4 | - 1.3.3 5 | otp_release: 6 | - 19.0 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Po Chen 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SideEffect 2 | 3 | simple utils for making side effect calls and return the piped-in value in pipelines 4 | 5 | ## Installation 6 | 7 | Add `side_effect` to your list of dependencies in `mix.exs`: 8 | 9 | ```elixir 10 | def deps do 11 | [{:side_effect, "~> 0.1.0"}] 12 | end 13 | ``` 14 | 15 | ## Why 16 | 17 | so instead of writing this: 18 | 19 | ```elixir 20 | def three_transformations_with_a_side_effect(x) do 21 | temp = 22 | x 23 | |> transform1() 24 | |> transform2() 25 | 26 | notify_someone(temp) 27 | 28 | transform3(temp) 29 | end 30 | ``` 31 | 32 | I'd just write: 33 | 34 | ```elixir 35 | def three_transformations_with_a_side_effect(x) do 36 | x 37 | |> transform1() 38 | |> transform2() 39 | |> SideEffect.side_apply(¬ify_someone/1) 40 | |> transform3() 41 | end 42 | ``` 43 | 44 | 45 | ## Usage 46 | 47 | ``` 48 | iex> 1 |> SideEffect.side_call(MyApp.send_notification()) |> List.wrap 49 | [1] 50 | 51 | iex> 1 |> SideEffect.side_apply(&MyApp.send_notification/1) |> List.wrap 52 | [1] 53 | 54 | iex> 1 |> SideEffect.side_apply(IO, :inspect) |> List.wrap 55 | [1] 56 | 57 | iex> 1 |> SideEffect.side_apply(IO, :inspect, [[base: :hex]]) |> List.wrap 58 | [1] 59 | ``` 60 | 61 | ```elixir 62 | defmodule M do 63 | def test(a, b, c, d), do: IO.inspect([a, b, c, d]) 64 | end 65 | 66 | b = 2 67 | 68 | SideEffect.side_apply(b, M, :test, [1, 3, 4], 1) 69 | 70 | # prints [1,2,3,4] 71 | # returns 2 72 | ``` 73 | -------------------------------------------------------------------------------- /lib/side_effect.ex: -------------------------------------------------------------------------------- 1 | defmodule SideEffect do 2 | @doc """ 3 | iex> 1 4 | ...> |> SideEffect.side_call(2) 5 | 1 6 | """ 7 | def side_call(piped_value, _) do 8 | piped_value 9 | end 10 | 11 | @doc """ 12 | iex> -1 13 | ...> |> SideEffect.side_apply(&abs/1) 14 | -1 15 | """ 16 | def side_apply(piped_value, func) when is_function(func) do 17 | func.(piped_value) 18 | piped_value 19 | end 20 | 21 | @doc """ 22 | iex> 1 23 | ...> |> SideEffect.side_apply(IO, :inspect) 24 | 1 25 | 26 | iex> 1 27 | ...> |> SideEffect.side_apply(IO, :inspect, [[base: :hex]]) 28 | ...> |> List.wrap 29 | [1] 30 | """ 31 | def side_apply(piped_value, module, func, other_args \\ [], position \\ 0) 32 | when is_atom(module) and is_atom(func) and is_list(other_args) do 33 | Kernel.apply(module, func, 34 | Enum.take(other_args, position) ++ 35 | [piped_value | Enum.drop(other_args, position)]) 36 | piped_value 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule SideEffect.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [app: :side_effect, 6 | description: description(), 7 | version: "0.1.0", 8 | elixir: "~> 1.3", 9 | build_embedded: Mix.env == :prod, 10 | start_permanent: Mix.env == :prod, 11 | deps: deps(), 12 | package: package()] 13 | end 14 | 15 | defp package do 16 | [name: :side_effect, 17 | files: ["lib", "mix.exs", "README*", "LICENSE*"], 18 | maintainers: ["Po Chen"], 19 | licenses: ["MIT"], 20 | links: %{"GitHub" => "https://github.com/princemaple/elixir-side-effect"}] 21 | end 22 | 23 | def application do 24 | [applications: [:logger]] 25 | end 26 | 27 | defp description do 28 | "simple utils for making side effect calls in pipelines" 29 | end 30 | 31 | defp deps do 32 | [{:ex_doc, ">= 0.0.0", only: :dev}] 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | %{"earmark": {:hex, :earmark, "1.0.1", "2c2cd903bfdc3de3f189bd9a8d4569a075b88a8981ded9a0d95672f6e2b63141", [:mix], []}, 2 | "ex_doc": {:hex, :ex_doc, "0.14.1", "bfed8d4e93c755e2b150be925ad2cfa6af7c3bfcacc3b609f45f6048c9d623d6", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]}} 3 | -------------------------------------------------------------------------------- /test/side_effect_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SideEffectTest do 2 | use ExUnit.Case 3 | doctest SideEffect 4 | 5 | defp echo_server do 6 | receive do 7 | {from, any} -> 8 | send from, any 9 | end 10 | echo_server 11 | end 12 | 13 | setup_all _context do 14 | [echo: spawn(&echo_server/0)] 15 | end 16 | 17 | test "it makes a call as a side effect", %{echo: echo} do 18 | assert SideEffect.side_call(1, send(echo, {self(), :sent})) == 1 19 | assert_receive :sent 20 | end 21 | 22 | test "it applies the function as a side effect", %{echo: echo} do 23 | assert SideEffect.side_apply(1, &send(echo, {self(), &1})) == 1 24 | assert_receive 1 25 | end 26 | 27 | def test(echo, a, b, c) do 28 | send echo, {self(), [a, b, c]} 29 | end 30 | 31 | test "it applies the module function as a side effect", %{echo: echo} do 32 | assert SideEffect.side_apply(1, SideEffectTest, :test, [echo, 2, 3], 1) == 1 33 | assert_receive [1, 2, 3] 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | --------------------------------------------------------------------------------