Can I extend iex helpers?

I’d like to add some custom helper functions to iex. I use .iex.exs and can define a module there with my custom functions. But I can’t figure out how to auto-import the module into my iex environment. I’ve tried hacking the iex bash script (at /usr/local/bin/iex), browsed thru the iex source - no luck. Is there a way to extend IEx.Helpers, or auto-import my .iex.exs module?

1 Like

I may be over simplifying, since I haven’t actually done this, but I would expect something like this in .iex.exs to work:

defmodule MyHelpers do
  #details
end
import MyHelpers

If you do in fact have that import step, can you show us your code to help with diagnosis?

My .iex.exs is exactly as you suggested.

When I run iex, I see this error message:

** (CompileError) .iex.exs:11: module MyHelpers is not loaded but was defined. This happens when you depend on a module in the same context it is defined. ... If the module is defined at the top-level and you are trying to use it at the top-level, such is not supported by Elixir

Right! I was just testing that out as I saw your reply :frowning:

Are you looking to do something project-specific or global? Project-specific isn’t hard. You can have MyHelpers in your normal source tree, and import MyHelpers in .iex.exs and it works.

If you need something global, then it’ll be more complicated because you’ll need the compiled BEAM file stored somewhere like your home dir and use some sort of Code.load_file/2 or Code.require_file/2 call.

Looking for a global solution. I believe I tried Code.load_file, but I’ll give it another shot…

So Code.load_file didn’t work, but I found a solution:

  1. create a helper module (cd ~ && vim my_helpers.ex)
  2. compile the helper module (elixirc my_helpers.ex)
  3. add an import statement to .iex.exs (import MyHelpers)
  4. test in iex

What happens is that iex auto-loads the compiled beam file - then you can auto-import the helper module in .iex.exs.

You can tweak the beam-path by hacking the iex shell script (at /usr/local/bin/iex).

@gregvaughn thanks for your suggestions! :slight_smile:

1 Like

I’m glad you got it working! I wasn’t so much help, just a kernel of an idea. The Code module also has ways to adjust the BEAM’s load path, which might help you avoid hacking the shell script (and having to remember to re-hack it each time you upgrade).

I couldn’t figure out how to load .beam files with the Code module. I ended up putting my helper source and beam files in ~/.iex, then made a bash alias ie=iex -pa ~/.iex. The -pa bit adds the .iex directory to the load path.

3 Likes

I actually figured this out about a year ago, forgot my answer and have been poking around the various lists to find the answer I wrote. Thanks for figuring this out, my search skills were failing.

You can use Code.prepend_path/append_path to update the path that the Beam uses to load files.
Unfortunately, they don’t work in this context, I haven’t found a work around yet other than the -pa
option.

I bet an escript could be made to simplify all this…

Doesn’t work for me unfortunately.

I have the Elixir.IEXHelper.beam file in my home folder and in
.iex.ex I have
import IEXHelper
I get
** (CompileError) /Users/chazsconi/.iex.exs:1: module IEXHelper is not loaded and could not be found

Any suggestions for how to fix this?

You need to start iex with the -pa option to append your home dir to the iex search path. Try iex -pa ~/

Also FYI you can use import_if_available - prevents the error message if the module is not found.

That works

Thanks @andy !

Is there an easy way to define an IEx helper now? I’d prefer to keep the helper definition inside .iex.exs if possible.

3 Likes

Unfortunately, no, because it is not possible to import a module in the same file as in which it was defined: you will get above compile error scenario.

1 Like

Ah, ok. I’ll just define the helper somewhere else then.

1 Like

In Elixir v1.14+ you will be able to import the module as you define it in .iex.exs files, as we now evaluate it line by line: Evaluate --dot-iex line by line · elixir-lang/elixir@395b053 · GitHub

14 Likes