+ All Categories
Home > Technology > Cukeup nyc ian dees on elixir, erlang, and cucumberl

Cukeup nyc ian dees on elixir, erlang, and cucumberl

Date post: 13-May-2015
Category:
Upload: skills-matter
View: 670 times
Download: 0 times
Share this document with a friend
Description:
Elixir, Erlang, and Cucumberl Elixir is a new Ruby-inspired programming language that uses the powerful concurrent machinery of Erlang behind the scenes. Cucumberl is a port of Cucumber to Erlang. Let's see what happens when we put them together. In this talk, we'll discuss: How Erlang's concurrency makes it easier to write robust programs Elixir's approachable syntax How to test Erlang and Elixir programs using Cucumberl Attendees will walk away with a solid introduction to the principles of Erlang, and an appreciation of the way Elixir brings the joy of Ruby to the solidity of the Erlang runtime.
Popular Tags:
62
Cucumber and Elixir Ian Dees • @undees CukeUp! NYC 2013
Transcript
Page 1: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Cucumber and ElixirIan Dees • @undeesCukeUp! NYC 2013

Page 2: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Why Elixir?The sad state of concurrency

Page 3: Cukeup nyc ian dees on elixir, erlang, and cucumberl

int HandleMessage(MessageType type, unsigned long arg1, unsigned long arg2) { switch (type) { case SOME_MESSAGE: INFO* info = *((INFO*)arg2); doSomethingWith(info.field); return MEANINGFUL_ERROR_CODE; // ... } // ...}

Page 4: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Semaphore& s = resourceSemaphore();s.acquire();laboriouslyCopyDataFromResource();s.release();doSomethingWithData();

Page 5: Cukeup nyc ian dees on elixir, erlang, and cucumberl

• Dangerous and hard-to-use message types

• Corruption- and deadlock-prone locks

Page 6: Cukeup nyc ian dees on elixir, erlang, and cucumberl

It doesn’t have to be this way!

Page 7: Cukeup nyc ian dees on elixir, erlang, and cucumberl

A taste of Elixirhttp://elixir-lang.org

Ruby style, Erlang substance

Page 8: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Pattern matching

Page 9: Cukeup nyc ian dees on elixir, erlang, and cucumberl

defmodule Ackermann do def ack(0, n), do: n + 1 def ack(m, 0), do: ack(m - 1, 1) def ack(m, n), do: ack(m - 1, ack(m, n - 1))end

IO.puts Ackermann.ack(3, 9)

Page 10: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Actor-style concurrency

Page 11: Cukeup nyc ian dees on elixir, erlang, and cucumberl

defmodule ShoutyEcho do def echo_loop do receive do {sender, msg} -> sender <- {:ok, String.upcase(msg)} echo_loop end endend

Page 12: Cukeup nyc ian dees on elixir, erlang, and cucumberl

defmodule ShoutyEcho do def echo_loop do receive do {sender, msg} -> sender <- {:ok, String.upcase(msg)} echo_loop end endend

Page 13: Cukeup nyc ian dees on elixir, erlang, and cucumberl

defmodule ShoutyEcho do def echo_loop do receive do {sender, msg} -> sender <- {:ok, String.upcase(msg)} echo_loop end endend

Page 14: Cukeup nyc ian dees on elixir, erlang, and cucumberl

defmodule ShoutyEcho do def echo_loop do receive do {sender, msg} -> sender <- {:ok, String.upcase(msg)} echo_loop end endend

Page 15: Cukeup nyc ian dees on elixir, erlang, and cucumberl

defmodule ShoutyEcho do def echo_loop do receive do {sender, msg} -> sender <- {:ok, String.upcase(msg)} echo_loop end endend

Page 16: Cukeup nyc ian dees on elixir, erlang, and cucumberl

pid = spawn(ShoutyEcho, :echo_loop, [])pid <- {self, "Your name here"}

receive do {:ok, response} -> IO.puts response after 500 -> IO.puts "Done"end

Page 17: Cukeup nyc ian dees on elixir, erlang, and cucumberl

pid = spawn(ShoutyEcho, :echo_loop, [])pid <- {self, "Your name here"}

receive do {:ok, response} -> IO.puts response after 500 -> IO.puts "Done"end

Page 18: Cukeup nyc ian dees on elixir, erlang, and cucumberl

pid = spawn(ShoutyEcho, :echo_loop, [])pid <- {self, "Your name here"}

receive do {:ok, response} -> IO.puts response after 500 -> IO.puts "Done"end

Page 19: Cukeup nyc ian dees on elixir, erlang, and cucumberl

pid = spawn(ShoutyEcho, :echo_loop, [])pid <- {self, "Your name here"}

receive do {:ok, response} -> IO.puts response after 500 -> IO.puts "Done"end

Page 20: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Cucumberlhttps://github.com/membase/cucumberl

Page 21: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo"

Page 22: Cukeup nyc ian dees on elixir, erlang, and cucumberl

-module(graycode).

-export([given/3, main/0]).

given([the, leds, read, _Input], State, _) -> {ok, State}.

main() -> cucumberl:run("./features/graycode.feature").

Page 23: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo"

1 scenarios1 steps

Page 24: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo" When I reset the counter

Page 25: Cukeup nyc ian dees on elixir, erlang, and cucumberl

---------NO-STEP--------

a step definition snippet...'when'([i,reset,the,counter], State, _) -> undefined.

Page 26: Cukeup nyc ian dees on elixir, erlang, and cucumberl

---------NO-STEP--------

a step definition snippet...'when'([i,reset,the,counter], State, _) -> undefined.

Page 27: Cukeup nyc ian dees on elixir, erlang, and cucumberl

-module(graycode).

-export([given/3, 'when'/3, main/0]).

%% ...

'when'([i, reset, the, counter], State, _) -> {ok, State}.

%% ...

Page 28: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo" When I reset the counter

1 scenarios2 steps

Page 29: Cukeup nyc ian dees on elixir, erlang, and cucumberl

I know what you’re thinking...

Page 30: Cukeup nyc ian dees on elixir, erlang, and cucumberl

What happens with the next “When” step?

Page 31: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Feature: Gray Code Scenario: ... ... When I reset the counter

Scenario: ... ... When I press the button

Page 32: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Pattern matching!

Page 33: Cukeup nyc ian dees on elixir, erlang, and cucumberl

'when'([i, reset, the, counter], State, _) -> {ok, State};'when'([i, press, the, button], State, _) -> {ok, State}.

Page 34: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ find . -type f

./ebin/graycode.beam

./features/graycode.feature

./src/graycode.erl

Page 35: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ find . -type f

./ebin/graycode.beam

./features/graycode.feature

./src/graycode.erl

Page 36: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Just a .beam file!

Page 37: Cukeup nyc ian dees on elixir, erlang, and cucumberl

And now in Elixir!

Page 38: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo"

Page 39: Cukeup nyc ian dees on elixir, erlang, and cucumberl

-module(graycode).

-export([given/3, main/0]).

given([the, leds, read, _Input], State, _) -> {ok, State}.

main() -> cucumberl:run("./features/graycode.feature").

Page 40: Cukeup nyc ian dees on elixir, erlang, and cucumberl

defmodule :graycode do def given([:the, :leds, :read, input], _state, _) do {:ok, input} end

def main() do :cucumberl.run("./features/graycode.feature") endend

Page 41: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ iex

c("src/graycode.ex", "ebin")

Page 42: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ find . -type f

./ebin/graycode.beam

./features/graycode.feature

./src/graycode.ex

Page 43: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo"

1 scenarios1 steps

Page 44: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo" When I reset the counter

Page 45: Cukeup nyc ian dees on elixir, erlang, and cucumberl

---------NO-STEP--------

a step definition snippet...'when'([i,reset,the,counter], State, _) -> undefined.

Page 46: Cukeup nyc ian dees on elixir, erlang, and cucumberl

---------NO-STEP--------

a step definition snippet...'when'([i,reset,the,counter], State, _) -> undefined.

Page 47: Cukeup nyc ian dees on elixir, erlang, and cucumberl

def 'when'([:i, :reset, :the, :counter], _state, _) do {:ok, '...'}end

== Compilation error on file src/graycode.ex ==** (SyntaxError) ./src/graycode.ex:6: syntax error before: ')'

Page 48: Cukeup nyc ian dees on elixir, erlang, and cucumberl

How to translate?

Page 49: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Hacking Cucumberl

Page 50: Cukeup nyc ian dees on elixir, erlang, and cucumberl

%% cucumberl_gen.erl

When = process_clauses('when', lists:reverse( sets:to_list(dict:fetch('when', Dict)))),

When_ = process_clauses(when_, lists:reverse( sets:to_list(dict:fetch(when_, Dict)))),

Page 51: Cukeup nyc ian dees on elixir, erlang, and cucumberl

%% cucumberl_gen.erl

When = process_clauses('when', lists:reverse( sets:to_list(dict:fetch('when', Dict)))),

When_ = process_clauses(when_, lists:reverse( sets:to_list(dict:fetch(when_, Dict)))),

Page 52: Cukeup nyc ian dees on elixir, erlang, and cucumberl

%% cucumberl_parser.erl

string_to_atoms(StrWords) -> lists:map(fun (Y) -> list_to_atom(string:to_lower(Y)) end, string:tokens(StrWords, " ")).

list_to_valid_atom("when") -> list_to_atom("when_");list_to_valid_atom(Str) -> list_to_atom(Str).

string_to_atoms(StrWords) -> lists:map(fun (Y) -> list_to_valid_atom(string:to_lower(Y)) end, string:tokens(StrWords, " ")).

Page 53: Cukeup nyc ian dees on elixir, erlang, and cucumberl

%% cucumberl_parser.erl

string_to_atoms(StrWords) -> lists:map(fun (Y) -> list_to_atom(string:to_lower(Y)) end, string:tokens(StrWords, " ")).

list_to_valid_atom("when") -> list_to_atom("when_");list_to_valid_atom(Str) -> list_to_atom(Str).

string_to_atoms(StrWords) -> lists:map(fun (Y) -> list_to_valid_atom(string:to_lower(Y)) end, string:tokens(StrWords, " ")).

Page 54: Cukeup nyc ian dees on elixir, erlang, and cucumberl

def when_([:i, :press, :the, :button], state, _) do {:ok, _next(state)}end

Page 55: Cukeup nyc ian dees on elixir, erlang, and cucumberl

$ cucumberl

Feature: Gray Code Scenario: Reset Given the LEDs read "ooo" When I reset the counter

1 scenarios2 steps

Page 56: Cukeup nyc ian dees on elixir, erlang, and cucumberl

def then([:the, :leds, :should, :read, expected], state, _) do {expected === state, state}end

Page 57: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Scenario Outline: Counter Given the LEDs read "<n>" When I press the button Then the LEDs should read "<nplus1>" Examples: | n | nplus1 | | ... | ..o | | ..o | .oo | | .oo | .o. | | .o. | oo. | | oo. | ooo | | ooo | o.o | | o.o | o.. | | o.. | ... |

Page 58: Cukeup nyc ian dees on elixir, erlang, and cucumberl

def when_([:i, :press, :the, :button], state, _) do {:ok, _next(state)}end

defp _next(leds) do case leds do '...' -> '..o' '..o' -> '.oo' '.oo' -> '.o.' '.o.' -> 'oo.' 'oo.' -> 'ooo' 'ooo' -> 'o.o' 'o.o' -> 'o..' 'o..' -> '...' endend

Page 59: Cukeup nyc ian dees on elixir, erlang, and cucumberl

Caveats

Page 60: Cukeup nyc ian dees on elixir, erlang, and cucumberl

1. Cucumberl has no idea about the Elixir runtime

Page 61: Cukeup nyc ian dees on elixir, erlang, and cucumberl

2. Who will do whatabout When?


Recommended