2016-04-17 51 views
6

Jestem całkiem nowym użytkownikiem Elixir i funkcjonalnymi językami programowania w ogóle.Eliksir - Metoda wywołania w module według nazwy String

W Elixir, chcę wywołać jedną konkretną funkcję w modułach, biorąc pod uwagę nazwę modułu jako ciąg.

Mam następujący (bardzo źle) działający kod, który dość dużo robi to, co chcę:

module_name = elem(elem(Code.eval_file("module.ex", __DIR__), 0), 1) 
apply(module_name, :helloWorld, []) 

to (przynajmniej tak to rozumiem) kompiluje (już skompilowany moduł) module.ex w bieżącym katalogu. Wyodrębniam nazwę modułów (nie jako String, nie wiem, jaki typ danych faktycznie jest) z dwóch krotek i uruchamiam na nich metodę helloWorld.

Istnieją dwa problemy z tym kodem:

  1. wypisuje ostrzeżenie jak redefining module Balance. Z pewnością nie chcę, aby tak się działo w produkcji.

  2. AFAIK ten kod kompiluje module.ex. Ale ponieważ moduł module.ex jest już skompilowany i załadowany, nie chce, aby tak się stało.

Nie muszę wywoływać metod w tych modułach przez nazwę pliku, nazwa modułu też byłaby w porządku. Ale musi to być dynamiczne, np. wpisanie "Księgi" w wierszu poleceń powinno, po sprawdzeniu, czy moduł istnieje, wywołać funkcję Book.helloWorld.

Dzięki.

Odpowiedz

9

Cóż, to jest to, gdzie pytanie pomaga: Zrobisz to sam, gdy tylko zapytasz. ;)

Teraz wystarczy użyć apply(String.to_existing_atom("Elixir.Module"), :helloWorld, []). (może nazwa "Moduł" jest niedozwolona, ​​nie wiem)

+2

Mała uwaga: należy użyć to_existing_atom miarę możliwości. Atomy nie zbierają śmieci! –

+0

Dzięki! Nie wiedziałem, że atomy nie są zebrane śmieci. Zmodyfikuje moją odpowiedź. – lschuermann

1

Należy również pamiętać, że nazwa modułu to atom, więc zwykle nie jest potrzebne String.to_existing_atom. Rozważmy następujący kod:

defmodule T do 
    def first([]), do: nil 
    def first([h|t]), do: h 
end 

W tym przypadku można po prostu wykonaj zastosowanie w ten sposób:

apply(T,:first,[[1,2,3]]) 
#=> 1 

Or tym przykładzie (poniżej liście jest Elixir moduł List):

apply(List,:first,[[1,2,3]]) 
#=> 1 

Mam na myśli powiedzieć, że jeśli znasz nazwę modułu, nie jest konieczne przekazywanie go jako ciąg, a następnie przekształcenie go w istniejący atom. Po prostu użyj nazwy bez cudzysłowów.

+0

Tak, to jest całkowicie poprawne.Ale w moim przypadku celem było sprawienie, by nazwa modułu była dynamiczna. Oczywiście, jeśli znasz nazwę modułu, to też by się udało. – lschuermann

6

Pamiętaj, że zawsze powinieneś poprzedzać swoje moduły "Eliksirem".

defmodule Test do 
    def test(text) do 
    IO.puts("#{text}") 
    end 
end 

apply(String.to_existing_atom("Elixir.Test"), :test, ["test"]) 

drukuje "test" i zwroty: {OK}