Elixir:如何正确描述 mix.exs 设置?

Elixir: How can I describe mix.exs settings correctly?

我尝试使用 HTTPoison 编写一个网络抓取工具。作为第一步,我按照如下所示的步骤编写了一个简短的 HTTP 访问代码;

  1. 通过 mix 创建项目

    $ 混合新 httptest1

  2. 在lib/httptest1.ex.上写一个短代码

    defmodule Httptest1 do
      require HTTPoison
    
      def test1 do
        ret = HTTPoison.get! "http://www.yahoo.com"
        %HTTPoison.Response{status_code: 200, body: body} = ret
        IO.inspect body
      end
    end
    
    Httptest1.test1()
    
  3. 为 HTTPoison 修改 mix.exs。

    defmodule Httptest1.Mixfile do
      use Mix.Project
    
      def project do
        [app: :httptest1,
         version: "0.0.1",
         elixir: "~> 1.0",
         build_embedded: Mix.env == :prod,
         start_permanent: Mix.env == :prod,
         deps: deps]
      end
    
      # Configuration for the OTP application
      def application do
        [applications: [:logger, :httpoison]]
      end
    
      # Dependencies can be Hex packages:
      #
      defp deps do
        [
         {:httpoison, "~> 0.6"}
        ]
      end
    end
    
  4. 运行 $ mix deps.get 依赖。

  5. 运行$ mix run,则编译失败;

    ==> idna (compile)
    Compiled src/idna.erl
    Compiled src/idna_ucs.erl
    Compiled src/punycode.erl
    (... snip ...)
    Generated httpoison app
    
    == Compilation error on file lib/httptest1.ex ==
    ** (exit) exited in: :gen_server.call(:hackney_manager, {:new_request, #PID<0.154.0>, #Reference<0.0.1.1724>, {:client, :undefined, :hackney_dummy_metrics, :hackney_tcp_transport, 'www.yahoo.com', 80, "www.yahoo.com", [connect_timeout: 5000, recv_timeout: :infinity], nil, nil, nil, true, :hackney_pool, :infinity, false, 5, false, 5, nil, nil, nil, :undefined, :start, nil, :normal, false, false, false, false, nil, :waiting, nil, 4096, "", [], :undefined, nil, nil, nil, nil, :undefined, nil}}, :infinity)
        ** (EXIT) no process
        (stdlib) gen_server.erl:212: :gen_server.call/3
        src/hackney_client/hackney_manager.erl:66: :hackney_manager.init_request/1
        src/hackney_client/hackney_manager.erl:56: :hackney_manager.new_request/1
        src/hackney_connect/hackney_connect.erl:181: :hackney_connect.socket_from_pool/4
        src/hackney_connect/hackney_connect.erl:36: :hackney_connect.connect/5
        src/hackney_client/hackney.erl:319: :hackney.request/5
        lib/httpoison.ex:60: HTTPoison.request/5
        lib/httpoison.ex:60: HTTPoison.request!/5
    

当我使用 $ iex -S mix 时,结果是一样的。

但是如果我将 httptest1.ex 移动到放置 mix.exs 的相同目录,例如 $ mv lib/httptest1.ex . 并尝试明确指定源文件; $ mix run httptest1,它工作正常。

问题: 我怀疑我的 mix.exs 设置有问题,那是什么?

lib/中的.ex全部编译。由于 Elixir 是元编程语言,因此当您编译文件时,您实际上是在 运行 编译代码。这意味着 Httptest1.test1() 在编译项目时执行。

需要启动 HTTPPoison 才能正常工作。它在您的应用程序启动时启动,也就是您执行 mix run ... 时启动。但是当你的项目正在编译你的项目或者你的依赖项没有启动时,调用你的依赖项可能会失败。

查看入门指南中的本章Supervisor and Application,了解如何在应用程序启动时运行编码。

改进了!现在我知道如何创建一个可执行的调用命令行了。

程序;

defmodule Httptest1 do
  use Application
  require HTTPoison

  def start(_type, _args) do
    import Supervisor.Spec, warn: false
    children = []
    opts = [strategy: :one_for_one, name: Httptest1.Supervisor]
    Supervisor.start_link(children, opts)
  end

  def main(args) do # entry point
    ret = HTTPoison.get! "http://www.yahoo.com"
    %HTTPoison.Response{status_code: _, body: body} = ret # no status code matching now
    IO.inspect body
  end

end

和mix.exs(均由$ mix new httptest1 --sup主管选项创建);

defmodule Httptest1.Mixfile do
  use Mix.Project

  def project do
    [app: :httptest1,
     version: "0.0.1",
     elixir: "~> 1.0",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     escript: escript,  # <<<< Added 
     deps: deps]
  end

  def escript do # define escript 
    [main_module: Httptest1]
  end

  def application do
    [applications: [:logger, :httpoison],
     mod: {Httptest1, []}] # 
  end

  defp deps do
    [
      {:httpoison, "~> 0.6"}
    ]
  end
end

然后在$ iex -S mix调用的iex中输入Httptest.test1,预期的结果出现了!谢谢。

此外,要创建命令行可执行文件,

   $ mix escript.build

然后生成./httptest1。完成。