【问题标题】:Elixir: How can I describe mix.exs settings correctly?Elixir:如何正确描述 mix.exs 设置?
【发布时间】:2015-10-09 00:46:27
【问题描述】:

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

  1. 混合创建项目

    $ mix new 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 设置出了问题,那是什么?

【问题讨论】:

  • 我有类似的错误信息。该代码在 IEX 中正确执行,没有错误,但在运行混合任务时抛出错误。对我有用的解决方案是“HTTPoison.start”也许这有助于在另一种情况下出现类似错误消息的人。

标签: elixir elixir-mix


【解决方案1】:

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

HTTPoison 需要启动才能正常工作。它在您的应用程序启动时启动,即在您执行mix run ... 时启动。但是当您的项目正在编译您的项目或您的依赖项未启动时,对您的依赖项的调用可能会失败。

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

【讨论】:

  • 谢谢。至少我发现只需从我的代码中省略 Httptest1.test1() 并手动从 $ iex -S mix 和 Httptest1.test1 开始,然后它就可以工作了。我的另一个问题是为什么指定的 .ex 文件没有放在 ./lib 时直接起作用。
  • 因为它没有与您的项目一起编译。当您执行 mix run ... 时,它会运行(并编译),这将使您的 HTTPoison 已经启动并运行。
  • 也就是说$ mix run httptest1.ex编译lib和依赖模块下的文件,但是在HTTPoison启动后才运行./httptest1.ex,对吗?
【解决方案2】:

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

程序;

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。完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-28
    相关资源
    最近更新 更多