Compile MongooseIM on OS X with openssl

Another tricky thing I always struggle with: Get MongooseIM compiled on OS X (since they removed openssl). So if you have openssl installed via homebrew just do

diff --git a/apps/ejabberd/rebar.config b/apps/ejabberd/rebar.config
index c693471..4e5ff1f 100644
--- a/apps/ejabberd/rebar.config
+++ b/apps/ejabberd/rebar.config
@@ -8,8 +8,15 @@
 {require_otp_vsn, "R?1[678]"}.

 {port_specs,
- [{".*", "priv/lib/tls_drv.so", ["c_src/tls_drv.c"], [{env, [{"LDFLAGS", "$LDFLAGS -lssl"}]}]},
-  {".*", "priv/lib/ejabberd_zlib_drv.so", ["c_src/ejabberd_zlib_drv.c"], [{env, [{"LDFLAGS", "$LDFLAGS -lz"}]}]}]}.
+ [{".*", "priv/lib/tls_drv.so", ["c_src/tls_drv.c"], [{env, [{".*apple-darwin.*", "CFLAGS", "$CFLAGS -I/usr/local/opt/openssl/include"},
+                                                             {".*apple-darwin.*", "LDFLAGS", "$LDFLAGS -L/usr/local/opt/openssl/lib"},
+                                                             {"LDFLAGS", "$LDFLAGS -lssl"}]}]},
+  {".*", "priv/lib/ejabberd_zlib_drv.so", ["c_src/ejabberd_zlib_drv.c"], [{env, [{"LDFLAGS", "$LDFLAGS -lz"}]}]},
+  {".*", "priv/lib/sha_drv.so", ["c_src/sha_drv.c"], [{env, [{".*apple-darwin.*", "CFLAGS", "$CFLAGS -I/usr/local/opt/openssl/include"},
+                                                             {".*apple-darwin.*", "LDFLAGS", "$LDFLAGS -L/usr/local/opt/openssl/lib"},
+                                                             {"LDFLAGS", "$LDFLAGS -lcrypto"}]}]},
+  {".*", "priv/lib/xml.so", ["c_src/xml.c"], []},
+  {".*", "priv/lib/expat_erl.so", ["c_src/expat_erl.c"], [{env, [{"LDFLAGS", "$LDFLAGS -lexpat"}]}]}]}.

 {xref_checks, [undefined_function_calls,
                undefined_functions,

Flattr this!

Permalink

Mailing list archived

The old mailing list archives have been added to the site, mainly for referencing purposes.

The mailing list has been shut down and all personal information has been deleted.

If you need help with a project, consider either opening a ticket on that project’s issues tracker or going through the community channels (erlang-questions, #ninenines or #erlang on Freenode).

Prefer tickets; often when people have issues it highlights an underlying problem in the project or its documentation.

Thanks.

Permalink

The minimum knowledge you need to start Metaprogramming in Elixir

Metaprogramming is writing code that writes code. In Elixir, we use macros to transform our internal program structure (AST) in compile time to something else. For example, the if macro is transformed to case during compilation, we call this macro expansion.

1
2
3
4
5
6
7
8
9
10
11
12
if true do
  IO.puts "yea"
end

# becomes

case(true) do
  x when x in [false, nil] ->
    nil
  _ ->
    IO.puts("yea")
end

The Abstract Syntax Tree (AST) and AST literal

The internal representation of Elixir code is an abstract syntax tree which is the protagonist in program transformation. Elixir also refers to an AST as a quoted expression.

The quoted expression is composed of three-element tuples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# simple one: AST for 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}

# nested one:
# AST for
# def hello do
#   IO.puts "hello"
# end

{:def, [context: Elixir, import: Kernel],
 [{:hello, [context: Elixir],
   [[do: {{:., [], [{:__aliases__, [alias: false], [:IO]}, :puts]}, [],
      ["hello"]}]]}]}

Essentially, All tuples in the AST follow the same pattern:

{function_call, meta_data_for_context, argument_list}

During compilation, all of our source code will be transformed into AST before producing final bytecode. However, there are five Elixir literals that will remain the same format as their high-level source.

The following example shows the differences between Elixir literal and other normal data types:

1
2
3
4
5
6
7
8
# AST for {1, 2, 3}
{:{}, [], [1, 2, 3]}

# AST for %{a: :hello}
{:%{}, [], [a: :hello]}

# AST for {1, 2} (AST literal)
{1, 2}

Macro

Macros receive AST as arguments and provide AST as return values. The returned AST is injected back into the global program’s compile tree, in this way, macros enable syntactic extensions and code generation.

  • Syntactic extensions: e.g. we can implement while which is not available in Elixir or create DSL
  • Code generation: e.g. generate function from external data

Return AST

There are three ways to create quoted expressions in Elixir:

  1. Manually construct it
  2. Macro.escape
  3. quote/unquote to compose AST
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
defmodule MyMacro do
  @opts: %{time: :am}

  # case 1
  defmacro one_plus_two do
    {:+, [], [1, 2]}
  end

  # case 2
  defmacro say_hi do
    quote do
      IO.puts "hello world"
    end
  end

  # case 3
  defmacro ops do
    Macro.escape(@opts)
  end
end

defmodule MyModule do
  import Mymacro

  def case1 do
    IO.puts one_plus_two()
  end

  def case2 do
    say_hi()
  end

  def case3 do
    IO.inspect ops()
  end
end

#=> c "example.exs"
#=> MyModule.case1()
#=> "3"
#=> MyModule.case2()
#=> "hello world"
#=> MyModule.case3()
#=> %{time: :am}

In this example, we define three macros using defmacro, all of them return quoted expressions, then we import MyMacro module into MyModule. During compilation, these macros will be expanded and the returned AST will be injected into MyModule's compile tree.

It's difficult to construct an AST by hand. We should almost always should use quote and Macro.escape to build up an AST using Elixir's own syntax. The main differences between these two are:

  • quote returns AST of passed in code block.

  • Macro.escape returns AST of passed in value.

Here are some examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
data = {1, 2, 3}

quote do: {1, 2, 3}
#=> {:{}, [], [1, 2, 3]} (AST of {1, 2, 3})

quote do: data
#=> {:data, [], Elixir} (data is not inject into returned AST)

quote do: IO.inspect(1)
#=> {{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [], [1]}
quote do: IO.inspect(data)
#=>{{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [],
 [{:data, [], Elixir}]}

Macro.escape(data)
#=> {:{}, [], [1, 2, 3]}

IO.inspect(1)
|> Macro.escape()
#=> :error

Notice that data variable is not injected into the AST returned by quote block, in order to do that, we need to use unquote, which we will discuss later.

Receive AST

Let's take an example to see how macros receive AST:

1
2
3
4
5
6
7
8
9
10
defmodule M do
  defmacro macro_args(a, b) do
    IO.inspect a
    IO.inspect b
  end
end

#=> c "example.exs"
{:+, [line: 22], [1, 1]}
2

After compiling the module, we can see the results: {{:+, [line: 22], [1, 1]}} and 2, they are both quoted expressions. Remember that number is an AST literal so its quoted expressions remains the same as itself.

Combining this fact with the pattern of AST, we can easily do pattern matching to get what we want from the argument for further AST composition.

Keep in mind that code passed into a macro is not evaluated or executed. As we saw earlier, Macros receive AST as arguments and provide AST as return values.

unquote

unquote injects quoted expressions into the AST returned by quote. You can only use unquote inside quote blocks.

To make it easier to understand, you can think quote/unquote as string interpolation. When you do quote, it's like creating string using "". When you do unquote, it's like injecting value into string by "#{}". However, instead of manipulating string, we are composing AST.

There are two types of unquote:

  • Normal unquote
1
2
3
4
data = {1, 2, 3}
quote do
  IO.inspect(unquote(data))
end

It looks correct, but when we evaluate the AST, we will get an error:

How come? It's because we forget an important concept:

unquote injects AST into AST returned by quote.

{1, 2, 3} is not an AST literal, so we need to get the quoted expressions. first by using Macro.escape.

1
2
3
4
data = {1, 2, 3}
quote do
  IO.inspect(unquote(Macro.escape(data)))
end
  • Unquote fragment

Unquote fragment is added to support dynamic generation of functions and nested macros.

1
2
3
4
5
6
7
8
9
10
11
defmodule MyModule do
  Enum.each [foo: 1, bar: 2, baz: 3], fn { k, v } ->
    def unquote(k)(arg) do
      unquote(v) + arg
    end
  end
end

#=> MyModule.foo(1) #2
#=> MyModule.bar(1) #3
#=> MyModule.baz(2) #4

In this example, we use unquote(k) as function name to generate functions from keys of a Keyworld list.

You might wonder why we can use unquote without quote. It's because def is macro, its arguments will be quoted automatically as we discussed above.

Besides, we need quote(v) inside function body because of scope rule in Elixir:

for named function, any variable coming from the surrounding scope has to be unquoted inside a function clause body.

Bind_quoted

bind_quoted does two things:

1 prevent accidental reevaluation of bindings.

If we have two same unquote inside quote block, the unquote will be evaluated twice, this can cause problem. We can use bind_quoted to fix it:

1
2
3
4
5
6
7
8
9
10
11
12
13
# bad
defmacro my_macro(x) do
  quote do
     IO.inspect unquote(x) * unquote(x)
  end
end

# good
defmacro my_macro(x) do
  quote bind_quoted: [x: x] do
     IO.inspect x * x
  end
end

2 Defer the execution of unquote via unquote: false

unquote: false is the default behavior of bind_quoted.

The order of execution is:

when a macro module is compiled, code in the macro context will run first (IO.puts 1). Normal code in quote block will not be executed until the returned AST is injected into caller module. However, unquote code will "break the wall" and run in macro's context.

Macro module

1
2
3
4
5
6
7
8
9
10
11
12
13
defmodule M do
  defmacro my_macro(name) do
    # macro context
    IO.puts 1

    quote do
      # caller context
      IO.puts 4
      unquote(IO.puts 2)
    end
  end
end

Caller Module

1
2
3
4
5
defmodule Create do
  import M
  IO.puts 3
  my_macro("hello")
end

According to the explanation above, we can know the result of the example is: 1 2 3 4.

If we use bind_quoted in the example, the order will change. The unquote code will be treated as normal code and run in caller's context. Therefore, the result for the following example is: 1 3 4 2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
defmodule M do
  defmacro my_macro(name) do
    IO.puts 1

    quote bind_quoted: [name: name] do
      IO.puts 4

      def unquote(name)() do
        unquote(IO.puts 2)
        IO.puts "hello #{unquote(name)}"
      end
    end
  end
end
1
2
3
4
5
defmodule Create do
  import M
  IO.puts 3
  my_macro(:hello)
end

This is helpful because when we change my_macro(:hello) in caller module to

1
2
  [:foo, :bar]
  |> Enum.each(&my_macro(&1))

Our code will still work because the each function is executed before the injected AST.

How to do experiments

The best way to learn is trial and error. Elixir provides a few functions that can help us: IO.inspect, Code.eval_quoted, Macro.to_string, and Macro.expand/Macro.expand_once. Let's find out more about each one:

  • IO.inspect

We can use IO.inspect to output the details of macro arguments or whatever we want.

  • Code.eval_quoted

eval_quoted helps to evalute AST we created:

1
2
3
4
5
6
7
data = {1, 2, 3}
ast = quote do
  IO.inspect(unquote(Macro.escape(data)))
end
Code.eval_quoted(ast)

#=> {1, 2, 3}
  • Macro.to_string

It converts the given quoted expressions to a string.

1
2
Macro.to_string(ast)
#=> "IO.inspect({1, 2, 3})"
  • Macro.expand/Macro.expand_once

Macro.expand will receive an AST node and recursively expand it. We can also expand AST once a time using Macro.expand_once.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ast = quote do: if true, do: IO.puts 1
Macro.expand_once(ast, __ENV__)

{:case, [optimize_boolean: true],
     [true,
      [do: [{:->, [],
         [[{:when, [],
            [{:x, [counter: 0], Kernel},
             {:in, [context: Kernel, import: Kernel],
              [{:x, [counter: 0], Kernel}, [false, nil]]}]}], nil]},
        {:->, [],
         [[{:_, [], Kernel}],
          {{:., [], [{:__aliases__, [alias: false, counter: 0], [:IO]}, :puts]}, [],
           [1]}]}]]]}

Resources

Now we know the basic about metaprogramming in Elixir, it's time to write simple macro, do some experiments and read source code of Elixir or Phoenix.

Also, there are two great resouces:

Great book to read. A lot of practical examples in the book that teach you how to write macros.

Permalink

Using Ecto Changesets for HTML input validations

All web applications with user submitted input have some constraints on what input is acceptable. We as developers have two methods to make sure what the user entered falls within those constraints.

Client Side Validation where your application checks form data prior to a network call and prevents the call from happening if it finds the data invalid.

Server Side Validation where your application sends data to the server and waits for it to tell you if the data is valid or not.

Both are means to the same end but have their advantages and disadvantages.

Server Side Validation (Necessary)

Pros

  • Source of truth / "Last line of defense"
  • Can be tied to DB logic
  • Knows context of the user, session, or other data
  • More powerful and secure

Cons

  • Slow to get feedback due to network latency
  • Sending the entire form just to get one error

Client Side Validations (Optional)

Pros

  • Immediate validation
  • Preventative
  • Semantically accurate
  • Nicer feeling feedback due to styling with CSS selectors

Cons

  • Have to keep it in sync with server side
  • Brittle
  • Not a substitute for server side validation

Generally client side validations are optional, faster, and provide better UX, while server side validations are necessary, stronger, and better tied to your data schema.

Ideally you utilize both, but they're a pain to keep in sync. In a perfect world your application's back end validations automatically apply to the client. We're going to explore how Phoenix and Ecto give us the power to help us do exactly that.

We can leverage Phoenix and Ecto.Changeset on our front end with just a few lines of code. This doesn't work for everything (uniqueness constraints for example), but there are some nice things we can validate for: min/max, length, and required fields. Ecto changesets within Phoenix support validate_length, validate_number, validate_required which correspond to the HTML input validations minlength/maxlength, min/max, and required.

Our goal is to have the validations defined in a schema's changeset function automatically apply the correct HTML input validation to our form.

Let's write some code.


The Code

Let's work with a schema named foo with the following changeset function:

1
2
3
4
5
6
def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:name])
  |> validate_required([:name])
  |> validate_length(:name, min: 2, max: 4)
end

By default our form should have something like this:

1
<%= text_input f, :name, class: "form-control" %>

Which generates this markup:

1
<input class="form-control" id="foo_name" name="foo[name]" type="text">

It works, but we have to wait for a server round trip to get any validations. We can add client side validation by appending opts by hand like this:

1
<%= text_input f, :name, class: "form-control", required: true, minlength: 2, maxlength: 4 %>

Which generates this markup:

1
<input class="form-control" id="foo_name" maxlength="4" minlength="2" name="foo[name]" required="required" type="text">

This is better, but if we ever changed the max to something else we would have to remember to change it in two different places!

We can do better by using input_validations. This function generates the HTML validation attributes from our Ecto changeset for us.

Now we can define our own functions which simply add on those generated input validations to our text and number inputs...

1
2
3
4
5
6
7
8
9
alias Phoenix.HTML.Form

def text_input(form, field, opts \\ []) do
  Form.text_input(form, field, opts ++ Form.input_validations(form, field))
end

def number_input(form, field, opts \\ []) do
  Form.number_input(form, field, opts ++ Form.input_validations(form, field))
end

Keep the same markup we had initially...

1
<%= text_input f, :name, class: "form-control" %>

... and get the semantically correct markup with no changes to the template!

1
<input class="form-control" id="foo_name" maxlength="4" minlength="2" name="foo[name]" required="required" type="text">

Other validations

This will also work for number validations. Say our changeset function had a line like

1
|> validate_number(:count, greater_than: 2, less_than: 9)

That would give us this markup

1
<input class="form-control" id="foo_count" max="8" min="3" name="foo[count]" required="required" step="1" type="number">

Using this in your application

To leverage this in your own Phoenix application, we'll use a module that we will automatically import in all our views.

First define the module with our custom text_input and number_input functions in web/views/valid_inputs.ex

1
2
3
4
5
6
7
8
9
10
11
defmodule HelloPhoenix.ValidInputs do
  alias Phoenix.HTML.Form

  def text_input(form, field, opts \\ []) do
    Form.text_input(form, field, opts ++ Form.input_validations(form, field))
  end

  def number_input(form, field, opts \\ []) do
    Form.number_input(form, field, opts ++ Form.input_validations(form, field))
  end
end

Then in web/web.ex just have Phoenix make it available for all our views.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def view do
  quote do
    use Phoenix.View, root: "web/templates"

    # Import convenience functions from controllers
    import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]

    # Use all HTML functionality (forms, tags, etc)
    use Phoenix.HTML

    # vvvv BEGIN OUR CODE vvvv
    import Phoenix.HTML.Form, except: [number_input: 2, number_input: 3, text_input: 3]
    import HelloPhoenix.ValidInputs
    # ^^^^ END OUR CODE ^^^^

    import HelloPhoenix.Router.Helpers
    import HelloPhoenix.ErrorHelpers
    import HelloPhoenix.Gettext
  end
end

And we're done! Now that your inputs have constraints, you can use CSS selectors like :invalid and :required to make things look a bit nicer for the user.

Custom Validations

There's also a lesser known pattern HTML attribute for regex validations. The JavaScript and Elixir regex engines are not 100% compatible so it's not supported by default in input_validations but we can add it ourselves as an exercise in custom validations.

1
|> validate_format(:email, ~r/.+@.+/)
1
2
3
4
5
6
7
8
9
10
11
12
def text_input(form, field, opts \\ []) do
  Form.text_input(form, field, extend_opts(form, field, opts))
end

defp extend_opts(form, field, opts) do
  defaults = opts ++ Form.input_validations(form, field)

  case form.source.validations[field] do
    {:format, regex} -> [{:pattern, Regex.source(regex)} | defaults]
    _ -> defaults
  end
end
1
<input class="form-control" id="foo_email" name="foo[email]" pattern=".+@.+" type="text">

Because we're just composing and calling functions, we can extend our initial implementation easily without having to inherit or monkey patch from an existing View module. Going further, you can tweak your text_input and number_input to, for example, take an optional validate parameter to include opt in/opt out functionality.

The takeaway

Using simple functions available in Phoenix, your application can automatically apply some of your in-place server side validations to your front end markup to improve your UX in only a few lines of code!

Permalink

Elixir for Rubyists

When I started my first project in Elixir I was still thinking in Ruby. At first, this was not much of a setback: both Ruby and Elixir share similar syntax and are high-level, readable, fun programming languages. The fast-growing, supportive community is reminiscent of Ruby during the early days of Rails.

Some features in Ruby map directly to features in Elixir:

Ruby Elixir
irb iex
rake tasks mix (built in)
bundler dependencies mix (built in)
binding.pry IEx.pry (built in)
Polymorphism Protocols
Lazy Enumerables Streams
Metaprogramming Macros (used sparingly)
Rails Phoenix

Some aspects look different at a first glance. For example, Elixir code looks a bit more verbose than Ruby code. Module names are spelled out in most function calls. Modules being used in the current file are explicitly included. State is passed into functions as arguments. Before explaining how macros can extend the language, its documentation page explicitly discourages its use.

Elixir can indeed be thought of as Ruby for the Erlang VM, and this first approach is sufficient for small projects. While Elixir resembles Ruby, there are notable differences.

Elixir is Erlang in Ruby’s clothing

Elixir programs compile to the Erlang VM (BEAM). Erlang was developed at Ericsson in 1986, has been Open Source since 1998, and is maintained by the Open Telecom Platform (OTP) unit at Ericsson.

Performance

The WhatsApp development team was able to establish two million TCP connections on a single box using Erlang alone. How is it so performant?

The Erlang VM runs as one operating system process, and by default runs one OS thread per core. Elixir programs use all CPU cores.

Erlang processes have no connection to OS processes or threads. Erlang processes are lightweight (grow and shrink dynamically) with small memory footprint, fast to create and terminate, and the scheduling overhead is low. An Erlang system running over one million (Erlang) processes may run one operating system process. Erlang processes share no state with each other, and communicate through asynchronous messages. This makes it the first popular actor-based concurrency implementation.

If process is waiting for a message (stuck in receive operator) it will never be queued for execution until a message is found. This is why millions of mostly idle processes are able to run on a single machine without reaching high CPU usage.

Erlang’s garbage collector works under certain assumptions that help its efficiency. Every variable is immutable, so once a variable is created, the value it points to never changes. Values are copied between processes, so memory referenced in a process is (almost always) isolated. And the garbage collector runs per process, which are relatively small. See section 4 of Programming the Parallel World for a detailed overview of Erlang processes and garbage collection.

In short, Erlang is faster than other platforms because it doesn’t allow mutability or shared memory by default.

Fault tolerance

Erlang’s architecture is share-nothing: each node is independent from each other and self-sufficient. Software in Erlang can be architected in such a way that there is no single point of failure and allows for non-disruptive upgrades.

Paraphrasing José Valim at The Changelog podcast, fault-tolerance in Erlang means “keep the system running”: it’s ok to maybe drop a user’s phone call, but it’s not ok to drop everyone’s phone call.

Unlike the web, telecommunication companies can’t call everyone and say there will be an outage between 6 and 6:30am. They have to keep the lights always on.

Pure functions

Erlang is a functional programming language. Functional programming treats computation as the evaluation of functions, and avoids mutable state and data. A pure function shows referential transparency: calls to the function can be replaced by their return values without changing the semantics of the program. We want pure functions because they are deterministic, easier to test, and easier to reason about.

Erlang’s immutable data structures and single assignment variables help with writing pure functions. Researchers classified on average between 30% and 50% of pure functions while analyzing different sizeable Erlang code bases. It’s possible to have side effects too: we can dynamically load and unload code, and change the operating system’s environment variables.

Ruby doesn’t enforce isolated state. Values can be mutated in place (string.gsub!). A getter is a canonical example of an impure function: each time it’s called with same arguments it might return different results according to the object’s internal state.

Other Erlang features available in Elixir

  • Distributed
  • Soft real-time (think telecommunications’ quality of service)
  • Highly available
  • Hot code swapping

Elixir on its own merits

The Pipe Operator

Let’s say we want to convert blog post titles into permalinks. For a title like ExMachina Hits 1.0 - More Flexible, More Useful and Support for Ecto 2.0 we expect a permalink like exmachina-hits-1-0-more-flexible-more-useful-and-support-for-ecto-2-0.

A Ruby implementation is:

title.
  downcase.
  gsub(/\W/, " "). # convert non-word chars (like -,!) into spaces
  split.    # drop extra whitespace
  join("-") # join words with dashes

Each call returns a String object or an object that implements Enumerable, and so we can chain String or Enumerable methods on each result. We’d like to give names to each step, so that the code comments are not necessary. How can we make the code look like the following?

text.
  downcase.
  replace_non_words_with_spaces.
  drop_extra_whitespace.
  join_with_dashes

To make this work we’d need to monkey patch the String class to define replace_non_words_with_spaces and drop_extra_whitespace, and Enumerable to define join_with_dashes.

Now let’s think of the same feature in Elixir. In a functional fashion, the code might look like:

Enum.join(
  String.split(
    String.replace(
      String.downcase(title), ~r/\W/, " "
    )
  ),
  "-"
)

We can make this more readable by using local variables:

downcased = String.downcase(title)
non_words_to_spaces = String.replace(downcased, ~r/\W/, " ")
whitespace_to_dashes = Enum.join(String.split(non_words_to_spaces), "-")

But Elixir provides a more idiomatic approach. The pipe operator introduces the expression on the left-hand side as the first argument to the function call on the right-hand side. It allow us to write code in the following shape:

title
|> String.downcase
|> String.replace(~r/\W/, " ")
|> String.split
|> Enum.join("-")

Each step can be extracted into an intention-revealing function:

title
|> downcased
|> non_words_to_spaces
|> whitespace_to_dashes

There are two implementations of function composition in Ruby similar to the pipe operator. Fabio Akita created the chainable_methods RubyGem that wraps a value into an object that implements pipe operator behavior. To get the final result one needs to call unwrap as last method call. Mike Burns authored the method_missing RubyGem that allows chaining functions with a * operator.

=, the match operator

In Elixir, the = operator is the match operator. It enables us to assign and then match values. Let’s take a look:

iex> {a, b, 42} = {:hello, "world", 42}
{:hello, "world", 42}
iex> a
:hello
iex> b
"world"
iex> :hello = a
:hello
iex> "world" = a
** (MatchError) no match of right hand side value: :hello

Pattern Matching and Multiple Function Clauses

Pattern matching allows to match simple values, data structures, and even functions. Function declarations support guards and multiple clauses. If a function has several clauses, Elixir will try each clause until it finds one that matches.

Let’s see an example. In this template we want to add an active class name to an li element only if the currently assigned document is the same as the one we are currently iterating over. The template follows (@conn.assigns looks like a hash of hashes):

<%= for document <- documents do %>
  <li class="<%= active_class(@conn.assigns, document.id) %>">
    <%= document.title %>
  </li>
<% end %>

A typical active_class implementation would include a conditional that checks if the argument is contained in the list (in Ruby, enumerable.include?(item)). Our Elixir implementation reads:

def active_class(%{document: %{id: id}}, id), do: "active"
def active_class(_, _), do: ""

In this implementation, we match the hash for a key called document, and if there is one, we match over its id. The function clause defines that same id as second argument, and if the call matches, the "active" string will be returned. The second clause matches any other case, for which we return the empty string.

Pattern matching spares us from conventional control-flow structures. Programs are composed of many small functions clauses, with guard clauses or pattern matching to trigger the right behavior according to how the arguments match. Code ends up being more declarative than imperative.

Macros

Macros for metaprogramming is another feature that Elixir adds on top of Erlang. This is a topic for another blog post.

When is Elixir a better fit than Ruby?

I believe Elixir and Ruby are interchangeable for simple web applications with no high-traffic or that don’t require very short response times.

Some people prefer the compile time checks that we don’t get in Ruby. Following TDD and keeping high code quality I don’t see meaningful differences in the cost of maintaining a small or medium project depending on the language on which it was developed.

For some applications though, Elixir makes better technical sense:

Scale

Elixir makes scaling easier than Ruby. Phoenix’ 10x throughput of a comparable Rails application means that you would need to add caching or hosts to your Elixir deployment later than in a Rails deployment.

Elixir processes are identified by a node and its process id. Sending processes to other hosts is the same as spawning them in the current host. In any case there is no shared state between processes or hosts, which is a problem one has to consciously take care of in Ruby.

Supervision trees and the ability to configure how to recover from failure when processes die are built-in features that aid with horizontal scaling.

High-availability Systems

Fault tolerance and hot code swapping are two features that Elixir counts with and help with the deployment of highly-available systems.


We are happily and productively building projects in Elixir. To read more of what we are learning, check out our elixir posts.

Permalink

Customizing `mix phoenix.gen.*` tasks

Because I am who I am, I've deviated from some default Phoenix file layouts. For example, rather than models having a single changeset function with two parameters you combine in different ways, I've tentatively decided I'd rather have variants like new_action_changeset, create_action_changeset, update_action_changeset, etc. That means a model should start out looking like this:

Similar changes are needed in the controller - and in model tests - and in controller tests. It would be tedious to run the default mix.phoenix.html task and then edit those files to support my quirkiness, so I needed to customize the "gen" process.

That's easy enough, but a checklist can't hurt for newbies like me.

[Update: José Valim points out the instructions below assume you want to keep the old mix tasks working. If you just want to replace them, skip past this first task list to the second.]

  1. You'll need two directories for copies of the Phoenix versions: lib/mix/tasks/ and priv/templates/. Those correspond to deps/phoenix/lib/mix/tasks/ and deps/phoenix/priv/templates/. (You could edit the Phoenix versions in place, but then later Phoenix releases would clobber your changes.)

     mkdir -p lib/mix/tasks/ priv/templates/
    
  2. Make copies of the templates you care about. Each task has a directory full of templates. If (as I do) you want to change the phoenix.gen.html task, you'll need two directories (because that task depends on the phoenix.gen.model task).

     cp -r deps/phoenix/priv/templates/phoenix.gen.html priv/templates
     cp -r deps/phoenix/priv/templates/phoenix.gen.model priv/templates
    
  3. You'll need the corresponding tasks. I gave mine the same name, but with a 2 on the end. (So that they'd show up next to the originals in mix help.)

    cp deps/phoenix/lib/mix/tasks/phoenix.gen.model.ex lib/mix/tasks/phoenix.gen.model2.ex
    cp deps/phoenix/lib/mix/tasks/phoenix.gen.html.ex lib/mix/tasks/phoenix.gen.html2.ex
    
  4. Because of the name change, elixir files need to be edited. And it doesn't hurt to describe the change:

  5. Edit your new template files.

  6. Compile.

    mix compile
    

That's all there is to it.


Update: if you know you won't ever want to use the default tasks, you can simplify the above like this:

  1. You'll need this directory for copies of the Phoenix versions: priv/templates/. It corresponds to deps/phoenix/priv/templates/. (You could edit the Phoenix versions in place, but then later Phoenix releases would clobber your changes.)

     mkdir -p priv/templates/
    
  2. Make copies of the templates you care about. Each task has a directory full of templates. If (as I do) you want to change the phoenix.gen.html task, you'll need two directories (because that task depends on the phoenix.gen.model task).

     cp -r deps/phoenix/priv/templates/phoenix.gen.html priv/templates
     cp -r deps/phoenix/priv/templates/phoenix.gen.model priv/templates
    
  3. Edit your new template files.

  4. Compile.

    mix compile
    

That's all there is to it.

Permalink

Copyright © 2016, Planet Erlang. No rights reserved.
Planet Erlang is maintained by Proctor.