DEV Community

bbronek
bbronek

Posted on • Edited on

Beginning my journey with elixir Part II. Modules, Enum, Loops, Strings, Recursion, Tests.

So it's time for the second part of my journey with elixir.
I will try to explain in a clear way things I have lastly learned and also show you how to use the newly acquired knowledge to write some simple programs.
That being said, I encourage you to read and learn something really interesting 😃

Alt Text

1.Modules

Modules are used to organize functions in their own namespace, it is useful to allocate functions to modules in relation to their functionality.
Example :

defmodule Greetings do
 @moduledoc """
  Provides a function `greet/1` to greet a human
  """
  @doc """
  Prints a hello message

  ## Parameters

    - name: String 

  ## Examples

      iex> Greeter.greet("user324")
      "Good morning! user324"

      iex> Greeter.greet("Peter")
      "Good morning! Peter"

  """
  @greeting "Good morning!"

  def greet(name) do
    ~s(#{@greeting} #{name}.)
  end
end

defmodule Greetings2 do
  alias Greetings, as: Hi

  def main do
    Hi.greet("John")
  end
end

Enter fullscreen mode Exit fullscreen mode

As you can see I used the @greeting attribute to use it as a greeting in the greet function. The ~s is a sigil. What is it? Here is an answer: Sigils are special syntax to working with literals, you can read more about this here. I also used the alias to use functions from another module in a different one.

2.Enum

The Enum is a module to work with enumerables.
I will only show a few functions from this module because it contains over 70 functions. It will be all?, any?, chunk_every, chunk_by, each, map, min, filter, reduce, sort and uniq

-all?

iex>Enum.all?(["one","two","three"], fn(x) -> String.length(x) == 4 end)
false
Enum.all?(["one","two","thre"], fn(x) -> String.length(x) == 3 end)
true

Enter fullscreen mode Exit fullscreen mode

-any?

iex>Enum.any?(["one","two","three"], fn(x) -> String.length(x) == 4 end)
true
Enum.any?(["one","two","thre"], fn(x) -> String.length(x) == 5 end)
false

Enter fullscreen mode Exit fullscreen mode

-chunk_every

iex>Enum.chunk_every(["one","two","three"], 2) 
[["one", "two"], ["three"]]

Enter fullscreen mode Exit fullscreen mode

-chunk_by

iex>Enum.chunk_by(["world","universe","hi"], fn(x) -> String.length(x) end) 
[["world"], ["universe"], ["hi"]]

Enter fullscreen mode Exit fullscreen mode

-each

iex>Enum.each(["How","are","you","?"], fn(x) -> IO.puts(x) end) 
How
are
you
?
:ok


Enter fullscreen mode Exit fullscreen mode

-map

iex> Enum.map([0, 1, 2, 3], fn(x) -> x * x end)
[0, 1, 4, 9]

Enter fullscreen mode Exit fullscreen mode

-min

iex> Enum.min([1, 32, 42, -10])
-10
Enter fullscreen mode Exit fullscreen mode

-filter

iex> Enum.filter([1, 2, 3, 4], fn(x) -> rem(x, 2) == 0 end)
[2, 4]

Enter fullscreen mode Exit fullscreen mode

-reduce

iex> Enum.reduce(["a","b","c"], fn(x,acc)-> x <> acc end)
"cba"

Enter fullscreen mode Exit fullscreen mode

Explanation: acc is the first element of the list.
This how it works:

1. x = 'b' acc = 'a' -> out: "ba"
2. x = 'c' acc = "ba" -> out: "cba"
"cba"

Enter fullscreen mode Exit fullscreen mode

-sort

iex> Enum.sort([%{:val => 4}, %{:val => 1}], fn(x, y) -> x[:val] > y[:val] end)
[%{val: 4}, %{val: 1}]

Enter fullscreen mode Exit fullscreen mode

-uniq

iex>  Enum.uniq([1, 2, 3, 2, 1, 1, 1, 1, 1])
[1, 2, 3]

Enter fullscreen mode Exit fullscreen mode

3.Loops

-for loop


iex>for {_key, val} <- [one: 1, two: 2, three: 3], do: IO.puts _key

one
two
three

Enter fullscreen mode Exit fullscreen mode

iex> import Integer
Integer
iex> for x <- 1..20, is_even(x), do: IO.puts x
2
4
6
8
10
12
14
16
18
20

Enter fullscreen mode Exit fullscreen mode

-functional approach source


defmodule Loop do
   def print_multiple_times(msg, n) when n <= 1 do
      IO.puts msg
   end

   def print_multiple_times(msg, n) do
      IO.puts msg
      print_multiple_times(msg, n - 1)
   end
end

Enter fullscreen mode Exit fullscreen mode

Results :

iex> c("file.ex")
[Loop]
iex> Loop.print_multiple_times("HI",3)
HI
HI
HI
:ok
Enter fullscreen mode Exit fullscreen mode

4.Strings

-You can use ASCII to assign a string value.

iex> string = <<104,101,108,108,111>>
"Hello"

Enter fullscreen mode Exit fullscreen mode

-Easy for returning an ASCII value of a char :

iex>?a
97

Enter fullscreen mode Exit fullscreen mode

Anagram program :

defmodule Anagram do
  def anagrams?(a, b) when is_binary(a) and is_binary(b) do
    sort_string(a) == sort_string(b)
  end

  def sort_string(string) do
    string
    |> String.downcase()
    |> String.graphemes()
    |> Enum.sort()
  end
end

Enter fullscreen mode Exit fullscreen mode

Useful link grapheme.

5.Short view of recursion.

defmodule Rec do
  def rec(a,b) do
    if a<=b do
      IO.puts "Hi #{a}"
      a = a + 1
      rec(a,b)
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

Results:

[Rec]
iex> Rec.rec(2,7)
Hi 2
Hi 3
Hi 4
Hi 5
Hi 6
Hi 7
nil

Enter fullscreen mode Exit fullscreen mode

6. Tests

I wrote a simple program and I hope that it will be useful in understanding the methods of testing.

defmodule App do

    def get_name do
      IO.gets("What is yout name? ")
      |>String.trim
    end

    def get_number do
      IO.getn("Give a number: [0-9] ",1)
    end

    def main() do
      name = get_name()
      IO.puts("Hello #{name}")
      number = get_number()
      name
    end

end

ExUnit.start

defmodule Tests do
  alias App
  use ExUnit.Case

  test "check if name is valid" do
    refute String.match?(App.main,~r/[0-9]/)
  end
end

Enter fullscreen mode Exit fullscreen mode

Explanation: IO.getn(string,size) , ~r/[0-9]/ (regex);

Before testing, you have to launch it by ExUnit.start,
to use the test condition I had to write before it use ExUnit.Case. ' refute String.match?(App.main,~r/[0-9]/) '
refute it is the same as unless, you can also use assert in testing which means 'should' or 'expect to be' .

Result:

What is your name? qwer45
Hello qwer45
Give a number: [0-9] 5

1) test check if name is valid (Tests)
     tests.exs:27
     Expected false or nil, got true
     code: refute String.match?(App.main, ~r"[0-9]")
     arguments:

         # 1
         "qwer45"

         # 2
         ~r/[0-9]/

     stacktrace:
       tests.exs:28: (test)



Finished in 4.8 seconds (0.07s on load, 4.7s on tests)
1 test, 1 failure


Enter fullscreen mode Exit fullscreen mode

This all for part II in the next part I plan to write about using dates and times, custom mix tasks, more about iex, error handling, and executable files. Have a nice day ✋

Top comments (0)