By Developers, For Developers

Historical errata for Metaprogramming Elixir

PDF PgPaper PgTypeDescriptionFixed onComments
13TYPO

best of both words…. should be best of both worlds

allERROR

In the pdf format for the book, all of the letter ‘s’ and ‘S’ are invisible in normal text. The letter S is copyable (shows up in with copy/paste). So the S is in fact there in the text. Additionally, the S’s are invisible if the pdf is opened in gimp so it’s not just my pdf viewer. I am using Linux Mint Petra 16 and I suspect there may be a font issue. Contact me at jlgoldb2@asu.edu with any questions or requests. Thanks.

17TYPO

IEx output has unquoted apostrophes leading to formatting errors.

15TYPO

“Be sure to launch iex in the same directory that you created your unless.exs file…”
Then in the iex session you are told to compile:
“iex> c ”macros/unless.exs"

Should either remove the “macros” part of the compile call or tell the reader to open iex up a directory,

22TYPO

Middle of the page:

iex> c “if_recreated.exs”
[MyIf]

should be:

iex> c “if_recreated.exs”
[ControlFlow]

24TYPO

iex(1)> c “while.exs”

should be:

iex(1)> c “while_step1.exs”

25TYPO

iex> c “while.exs”

should be:

iex> c“while_step2.exs”

41ERROR

I noticed that when the `assert` functions used IO.puts to output their results right away, running `MathTest.run` always worked for all assertions.

When the `assert` functions started reporting status with either :ok or {:fail, reason}, then I noticed that `MathTest.run` was only reporting the result of the final `assert` in each test function since the test function isn’t remembering the results.

I haven’t thought about what the best solution might be, but I thought you might want to know what I noticed.

I am loving the book so far. It’s wonderful.

31,32TYPO

Similar mismatch between source file name and name used when compiling as pages above.

I won’t add any more errata that are similar.

46TYPO

the line:

text/html.html

needs to be added to mimes.txt in order for a subsequent call to valid_type? on page 47 to work.

61TYPO

Hub.linguist does not return a value because the GitHub API delivers repos a page at a time and the default page size is 30. The last repo is “labrador”. You could change the example to Hub.atlas or on page 60 change line 5 in “hub.ex” to add a parameter to the url:

“…repos?per_page=100”

(100 is the maximum per page).

Or, the macro could be rewritten to loop on pages when accessing the GitHub API.

65TYPO

“We’re going explore” => “We’re going to explore”

40TYPO

Typo in the module name, Assert.before_compile/1 should be Assertion.before_compile/1

22ERROR

The line:

defmacro my_if(expr, do: if_block), do: if(expr, do: if_block, else: nil)

The do block uses `if`

However the macro should be defined in terms of `my_if`

15ERROR

Before the code example it is suggested that iex should start from inside the directory with the unless.exs file.

If that happens then the first line of the code instead of:

iex> c “macros/unless.exs”

it should be:

iex> c “unless.exs”

22TYPO

When entering the iex shell and compiling the file the return value should be different.
So instead of:

iex> c “if_recreated.exs”
[MyIf]

it should be:

iex> c “if_recreated.exs”
[ControlFlow]

31SUGGEST

Shouldn’t the require, put_env and function definition be repeated here as in the previous page 30?

33SUGGEST

Shouldn’t the all the commands needed in iex be displayed?
as in:

iex(1)> c “macros/math_test_import.exs”
[MathTest]
iex(2)> import MathTest
nil
iex(3)> MathTest.run
..FAILURE:
Expected: 1
to be greater than: 2

.:ok
iex(4)>

35TYPO

iex result when compiling should show both MathTest and Assertion.

So this:
iex(1)> c “macros/module_extension_custom.exs”
macros/module_extension_custom.exs:1: warning: redefining module Assertion
macros/module_extension_custom.exs:3: warning: variable options is unused
macros/module_extension_custom.exs:15: warning: redefining module MathTest
[MathTest]
iex(2)> MathTest.run
Running the tests…
:ok
iex(3)>

should be:

iex(1)> c “macros/module_extension_custom.exs”
macros/module_extension_custom.exs:1: warning: redefining module Assertion
macros/module_extension_custom.exs:3: warning: variable options is unused
macros/module_extension_custom.exs:15: warning: redefining module MathTest
[MathTest, Assertion]
iex(2)> MathTest.run
Running the tests…
:ok
iex(3)>

38TYPO

iex> c “assertion.exs”
[Assertion.Test, Assertion]

should be:

iex> c “accumulated_module_attributes.exs”
[Assertion.Test, Assertion]

39TYPO

iex> c “assertion.exs”
[Assertion.Test, Assertion]

should be:

iex> c “before_compile.exs”
[Assertion.Test, Assertion]

42SUGGEST

Shouldn’t the two modules be recompiled again before running the MathTest.run?

iex> c “assertion.exs”
[Assertion.Test, Assertion]
iex> c “math_test_final.exs”
[MathTest]
iex> MathTest.run

52TYPO

iex> c “translator.exs”
[Translator]

should be:

iex> c “translator_step3.exs”
[Translator]

51TYPO

line 13 of the code, deftranslations definitions.

defp deftranslations(locales, current_path, mappings) do

should be:

defp deftranslations(locale, current_path, mappings) do

53TYPO

iex> c “translator.exs”
[Translator]

should be:

iex> c “translator_step4.exs”
[Translator]

54TYPO

line 7 on the t definition binding should be bindings

def t(locale, path, binding \\\\ [])

should be

def t(locale, path, bindings \\\\ [])

54TYPO

iex> c “translator.exs”
[Translator]

should be:
iex> c “macro_to_string.exs”
[Translator]

56TYPO

iex> c “translator.exs”
[Translator]

should be:

iex> c “translator_final.exs”
[Translator]

56TYPO

function definition should have bindings instead of binding.

def(t(locale, path, binding \\\\ []))

shoudl be:

def(t(locale, path, bindings \\\\ []))

59TYPO

Since we used cd hub previously the name of the file should be:

mix.exs

instead of:

hub/mix.exs

66TYPO

The first test file that is created is called while_test_step1.exs so the command to run the test should be:

$ elixir while_test_step1.exs

67SUGGEST

If we do not remove the first test from the file then the result should show 2 tests passing.

Otherwise we should mention that the test introduced in while_loop_step1.exs should be removed.

22TYPO

Re-creating the if Macro has an example that reuses the existing if macro. However, just changing line 2 from using if to my_if doesn’t work. An alternate version follows.

defmodule ControlFlow do
defmacro my_if(expr, args) do
if_block = Keyword.get args, :do
else_block = Keyword.get args, :else

quote do
case unquote(expr) do
result when result in [false, nil] -> unquote(else_block)
_ -> unquote(if_block)
end
end
end
end

41ERROR

Assert macro as written is broken: if test has multiple assertions, only failure in the last one will be reported (as it’s going to be the return value of the test functions). Failures in non-last asserts go unnoticed.

16TYPO

Elixir macros strike an excellent balance for safeguarding your context while allowing explicit access where neccesary. -> necessary

—Deans Charbal

21TYPO

The code
para(for i <- 1..10 do: i * 10)

is missing a coma after the range 1..10. It should be:
para(for i <- 1..10, do: i * 10)

22ERROR

This has been reported already in #78169, but it’s not just a matter of reusing my_if and not using if. The first version that has empty else block is bugged. If you do:
ControlFlow.my_if 1 == 2, do: “fail”
the result is “fail”, not nil! That gave me quite a headache. The call to is has to be quoted to make it work properly. Alternatively, to have just one defmacro, this could be implemented like the Kernel.if:

defmodule ControlFlow do
defmacro my_if(expr, clauses) do
my_if_impl(expr, clauses)
end

defp my_if_impl(expr, do: if_block) do
my_if_impl(expr, do: if_block, else: nil)
end

defp my_if_impl(expr, do: if_block, else: else_block) do
quote do
case unquote(expr) do
result when result in [false, nil] -> unquote(else_block)
_ -> unquote(if_block)
end
end
end
end

61ERROR

When I run “Hub.” in `iex -S mix` I see this:

Interactive Elixir (1.4.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Hub.
…(1)>

Elixir 1.4.0-dev, OTP 19.

41ERROR

I’m afraid I found a way to check first error assert result (related to post #78424). I just find it in my way,may be it’s not the good way.show my key code below:

defmodule Assertion2 do
…….

defmacro test(description, do: test_block1) do
test_func = String.to_atom(description)
expressions =
case test_block1 do
{:block, [], exps} -> exps
s = {:assert, _a, _b} -> [s]
end
quote do
@tests {unquote(test_func), unquote(description)}
def unquote(test_func)() do
Enum.find_index(unquote(expressions), fn r ->
r != “OK”
end)
end
end
end
…….
end

defmodule Assertion2.Test do
……..

def run(module, func_desc) do
Enum.each(func_desc, fn {func, desc} ->
case apply(module, func, []) do
nil ->
IO.write(“.”)

num ->
IO.puts(“”"

=
#{desc} MEET FAILURE : LINE #{num + 1}
=
“”")
end
end)
end

………
end

just replace these 2 functions,I got the result like this:
show my test code first:

defmodule MathTest do
use Assertion2

test “integers can be added and subtracted” do
assert 5 - 5 10 assert 1 + 1 2
assert 2 + 3 == 5
end

test “integers can be multiplied and divided” do
assert 5 * 5 25 assert 10 / 2 5
end

test “integers can be subtracted” do
assert 5 - 5 == 10
end
end

and result:

=
integers can be subtracted MEET FAILURE : LINE 1
=

.
=
integers can be added and subtracted MEET FAILURE : LINE 1
=

:ok

over
not bad right?

17ERROR

When I compile the code in callers_context.exs under Elixir 1.8 I get the following error -

(CompileError) callers_context.exs:20: undefined function info/1

I tried downloading the source code for the book, in case I was not seeing a typo I was making, but I get the same error -

(CompileError) callers_context.exs:28: undefined function info/1

16ERROR

In the code sample for macros/callers_context.exs there is an error on line 11 where it says #{inspect info(:functions)}. This does not work and gives a CompileError. It should be changed to MODULE.info(:functions) to get the code to compile and function correctly.

22TYPO

Module in code example is called ControlFlow, still, import shows MyIf:

iex>c “if_recreated.exs”
[MyIf]

Categories: