Update: I created a video version of this article walking through all the tips mentioned. You can view it on youtube here — https://youtu.be/ovjsGZwv4Jw

It’s been a while since I last wrote about Elixir or Phoenix. So, when I thought about resuming my writing on Elixir, I thought I should start with something very fundamental and part of any Elixir developer’s day to day workflow — which is the Interactive Shell (IEx). In this article, I will focus on presenting a collection of tips I find very useful while using IEx.

I will use IEx version 1.10.2. Some of the things may be different or may not even work if you are using a different version of IEx.

You can launch IEx shell from the command line simply typing iex or if you want to launch a phoenix project by typing iex -S mix phx.server or typing iex -S mix while in a mix based Elixir project.

Throughout the article, I will show output from real iex session but in most cases output will be truncated and annotated to suit this article.

Tip #1: Getting Help

First thing one should know after ending up in IEx shell is how to get help built into it like below —

Erlang/OTP 22 [erts-10.7] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe] Interactive Elixir (1.10.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> h <-- Prints this help IEx.Helpers Welcome to Interactive Elixir. You are currently seeing the documentation for

the module IEx.Helpers which provides many helpers to make Elixir's shell more

joyful to work with. This message was triggered by invoking the helper h(), usually referred to as

h/0 (since it expects 0 arguments).

The ‘h’ command prints summary of available ways to get help. If you need help about a particular module or function you can do as below —

iex(1)> h(Enum) <-- Prints help about Enum module Enum Provides a set of algorithms to work with enumerables. In Elixir, an enumerable is any data type that implements the Enumerable

protocol. Lists ([1, 2, 3]), Maps (%{foo: 1, bar: 2}) and Ranges (1..3) are

common data types used as enumerables:

or for help about a particular function inside a module you can do as below —

iex(4)> h(Enum.reverse/1) <-- Prints help about reverse/1 function from Enum module def reverse(enumerable) @spec reverse(t()) :: list() Returns a list of elements in enumerable in reverse order. ## Examples iex> Enum.reverse([1, 2, 3])

[3, 2, 1]

Tip #2: Get Value of Past Expression(s)

Often time it’s useful to get value of a command executed in the past. Specially, I often forget to assign value of a long Ecto query or complicated expression and scrolling up and using arrow key to go to the beginning of the expression can be cumbersome. So, this tip helps with that.

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

[3, 2, 1]

iex(6)> reversed = v(5) <-- Assigns value from expression at line (5) to reversed

[3, 2, 1]

iex(7)> reversed

[3, 2, 1]

iex(8)>

In case, it’s the last expression whose value you need to access, a shortcut is just ‘v’ —

iex(8)> new_reversed = v <-- Assigns value from last expression

[3, 2, 1]

iex(9)> new_reversed

[3, 2, 1]

iex(10)>

Tip #3: Recompile a Project or a Module

Often time I make changes in source code while in IEx session. To compile the full project in this case, you can do —

iex(4)> recompile

Compiling 1 file (.ex)

:ok <-- Prints :ok when something has changed and compilation successful iex(2)> recompile

:noop <-- Prints :noop when nothing has changed

Sometimes I just want to compile a certain module, instead of full project. In that case, the below works —

iex(7)> r MinitwitterWeb.PostController <-- Compiles and reloads module

warning: redefining module MinitwitterWeb.PostController (current version defined in memory)

lib/minitwitter_web/controllers/post_controller.ex:1 {:reloaded, MinitwitterWeb.PostController, [MinitwitterWeb.PostController]}

Tip #4: Search and Complete Command

Sometimes for long commands executed earlier, I need to search instead of scrolling or re-typing. IEx provides nice shortcut Ctrl+r to go in search mode —

(search)`': r MinitwitterWeb.PostController <-- Ctrl+r puts in search mode

iex(9)> r MinitwitterWeb.PostController <-- TAB/Arrow puts it on a new row

Tip #5: Enable Shell History

Typically, IEx does not preserve shell history if you exit your session. But if you want to do so, you can invoke IEx as below —

iex --erl "-kernel shell_history enabled"

This will preserve shell history and will be available upon next launch. A useful thing would be to create an alias in your OS shell to launch this command automatically when iex is typed. For bash shell, you can put the below in ~/.bashrc —

alias iex='iex --erl "-kernel shell_history enabled"

Tip #6: Breaking out of Expression

IEx provides a special break trigger (#iex:break) when encountered on a line by itself will force shell to break out of any pending expression and return to normal state:

iex(17)> defmodule Break do

...(17)> def break_out do

...(17)> #iex:break <- Breaks out of current expression

** (TokenMissingError) iex:17: incomplete expression

Tip #7: The .iex.exs File

IEx looks for a local .iex.exs file or a global ~/.iex.exs file loads the first one it finds (if any). You can read about it all here — https://hexdocs.pm/iex/IEx.html#module-the-iex-exs-file

In short, you can import certain modules, bind certain variables, or create certain aliases here that will be automatically executed in shell context and will be available once shell is booted which can be very handy for a large project.

I created a sample .iex.exs with two aliases as below —

alias Minitwitter.Accounts.User

alias Minitwitter.Accounts.Relationship

So, after invoking the shell, I can refer to them as User or Relationship since these aliases will be made available —

iex(2)> Relationship

Minitwitter.Accounts.Relationship

iex(3)> User

Minitwitter.Accounts.User

Tip #8: Load a Module or Script in IEx

The c/1 command compiles a file. While in IEx session, you can do the below to compile and load a module from file —

iex(1)> c "lib/issues.ex" <-- Loads Issues module from this file

[Issues]

In case of an Elixir script (.exs), it will compile and execute the file immediately. So you will see output as below —

iex(1)> c "./elixir_book.exs" <-- Compiles and executes this script

FizBuzz

Fizz

Buzz

Tip #9: Display Information

The i/1 command can be used to display information about an Elixir term. If I used this command in IEx shell for the previously loaded Issues module, it displays information as below —

iex(4)> i Issues <-- Prints information about this term

Term

Issues

Data type

Atom

Module bytecode

[]

Source

lib/issues.ex

Version

[74242156420198707021276849165021118249]

Compile options

[:dialyzer, :no_spawn_compiler_process, :from_core, :no_auto_import]

Description

Call Issues.module_info() to access metadata.

Raw representation

:"Elixir.Issues"

Reference modules

Module, Atom

Implemented protocols

IEx.Info, Inspect, List.Chars, String.Chars

If I run it on previously loaded User alias, it displays information as below —

iex(1)> i User

Term

User

Data type

Atom

Raw representation

:"Elixir.User"

Reference modules

Atom

Implemented protocols

IEx.Info, Inspect, List.Chars, String.Chars

Tip #10: Print All Available Modules

Sometimes you may have to print all available modules in a shell in order to diagnose a problem. This can be easily done with the shortcut :+TAB.

Tip #11: List All Macros and Functions from a Module

To list all macros and functions from a module, you can use the below command —

iex(3)> exports Minitwitter.Accounts <-- Shows all functions and macros from Accounts module

authenticate_by_email_and_pass/2 authenticated?/3 change_user/1

create_user/0 create_user/1 delete_user/1

follow/2 followers/1 following/1

following?/2 following_ids/1 forget_user/1

get_user/1 get_user_by/1 list_users/1

remember_user/1 reset_hash/1 reset_user_pass/2

unfollow/2 update_user/2 valid_user?/2

Another nicer way to do it is as below —

iex(8)> Minitwitter.Accounts.module_info

[

module: Minitwitter.Accounts,

exports: [

__info__: 1,

authenticate_by_email_and_pass: 2,

authenticated?: 3,

change_user: 1,

create_user: 0,

create_user: 1,

delete_user: 1,

follow: 2,

followers: 1,

following: 1,

following?: 2,

following_ids: 1,

forget_user: 1,

get_user: 1,

get_user_by: 1,

list_users: 1,

remember_user: 1,

reset_hash: 1,

reset_user_pass: 2,

unfollow: 2,

update_user: 2,

valid_user?: 2,

module_info: 0,

module_info: 1

],

attributes: [vsn: [165218174362312500220516424562981707158]],

compile: [

version: '7.5.3',

options: [:dialyzer, :no_spawn_compiler_process, :from_core,

:no_auto_import],

source: '/Users/meraj/Development/test/elixir/Phoenix_Playground/1.4/minitwitter/lib/minitwitter/accounts/accounts.ex'

],

native: false,

md5: <<124, 75, 220, 233, 97, 246, 150, 35, 170, 236, 247, 9, 216, 63, 157,

150>>

]

With no arguments, module_info returns a keyword list, with keys: [:module, :exports, :attributes, :compile, :native, :md5] . Any of those can be passed as arguments, to scope the return value. For example, you can do Minitwitter.Accounts.module_info(:md5) to just print md5 key.

Tip #12: List All Types from a Module

The t/1 command lists all types available in a module as below —

Tip #13: Multiline Expressions

If you are pasting a multiline expression copying from somewhere, IEx may complain due to line break. To do it properly, you can surround it by parenthesis —

iex(15)> [1, [2], 3]

[1, [2], 3]

iex(16)> |> List.flatten()

** (SyntaxError) iex:16: syntax error before: '|>' <-- Error while pasting iex(16)> ([1, [2], 3] <-- Works fine when surrounded by parenthesis

...(16)> |> List.flatten()

...(16)> )

[1, 2, 3]

In this article, I presented a number of tips that I think will be very helpful for any Elixir/Phoenix developer and make his/her life somewhat easier. I hope the reading will be pleasant and useful. Happy Elixir coding!

References:

IEx official doc — https://hexdocs.pm/iex/IEx.html Minitwitter app referred in this article — https://github.com/imeraj/Phoenix_Playground/tree/master/1.4/minitwitter

For more elaborate and in depth future technical posts please follow me here or on twitter.