Как получить доступ к ключам, связанным с Config, когда указано имя модуля - PullRequest
0 голосов
/ 17 декабря 2018

Когда я смотрю на файлы конфигурации в Phoenix, я создаю конфигурацию, подобную этой:

config :myapp,
  http: 4000

Я могу ссылаться на этот ключ в моем коде так:

Application.fetch_env!(:myapp, :http)

ИногдаКонфигурация, кажется, специфична для модуля, как показано ниже, имеет MyApp.Endpoint.

Это просто разбивает конфигурацию на разделы вроде?Как мне ссылаться на порт http, как показано ниже в моем коде, если мне нужно тоже?

config :myapp, MyApp.Endpoint,
  http: [port: 4000],
  debug_errors: true

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Иногда конфигурация кажется специфической для модуля, например, у MyApp.Endpoint ниже.

Это просто разбивает конфигурацию на разделы вроде?

tldr;

Да.С помощью вашего конфигурационного файла вы создаете что-то вроде этого:

[
  {:ecto_repos, [MyApp.Repo]},
  {.Repo,
   [
     username: "postgres",
     password: "postgres",
     database: "myapp_dev",
     hostname: "localhost",
     pool_size: 10
   ]},

  {:http, [port: 4000]},   <===**** HERE ****
  {:included_applications, []},

  {MyAppWeb.Endpoint,     <====**** HERE ****
   [
     url: [host: "localhost"],
     secret_key_base: "rchq5yMDPqqEBzFR+wIoqpc+kNquiyNDYUp/K8aF2Yj6POl/gjfj0H0rljE06LI5",
     render_errors: [view: MyAppWeb.ErrorView, accepts: ["html", "json"]],
     pubsub: [name: Rum.PubSub, adapter: Phoenix.PubSub.PG2],
     http: [port: 4000],
     debug_errors: true,
     code_reloader: true,
     check_origin: false,
     watchers: [
       node: [
         "node_modules/webpack/bin/webpack.js",
         "--mode",
         "development",
         "--watch-stdin",
         {:cd, "/Users/7stud/phoenix_apps/book/myapp/assets"}
       ]
     ],
     live_reload: [
       patterns: [~r/priv\/static\/.*(js|css|png|jpeg|jpg|gif|svg)$/,
        ~r/priv\/gettext\/.*(po)$/, ~r/lib\/myapp_web\/views\/.*(ex)$/,
        ~r/lib\/myapp_web\/templates\/.*(eex)$/]
     ]
   ]},

Как мне ссылаться на порт http, как показано ниже в моем коде, если мне это тоже нужно?

config :myapp, MyApp.Endpoint,
  http: [port: 4000],
  debug_errors: true

Если вы посмотрите на этот раздел конфигурации и удалите символы новой строки, вы получите:

config :myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true

И, если вы добавите несколько скобок, вы получите:

config(:myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true)

Этовызов функции, где первый аргумент :myapp, второй аргумент MyApp.Endpoint, а затем эта часть:

http: [port: 4000], debug_errors: true

является Keyword list.Отступив на мгновение ... в эликсире вы можете определить функции следующим образом:

  def go(x, y, z) do
    IO.puts x
    IO.puts y
    IO.inspect z
  end

и вызывать их следующим образом:

My.go(10, 20, a: 1, b: 2)

, что выдаст:

10
20
[a: 1, b: 2]

Это показывает, что если последние аргументы в вызове функции имеют определенный синтаксис, то все последние аргументы будут собраны в нечто, называемое Keyword list, и переданы функции в качестве одного аргумента.Таким образом, несмотря на то, что, похоже, вы вызываете My.go() с четырьмя аргументами, вы действительно вызываете его с тремя аргументами.

В результате этот вызов функции:

config(:myapp, MyApp.Endpoint, http: [port: 4000], debug_errors: true)

вызывает определение функции config/3.

Почему вы можете вызывать функцию config/3, если такая функция не определена в файле конфигурации?Эта строка:

use Mix.Config

вставляет определение функции config/3 в файл.Это проблема с эликсиром: происходит много волшебных вещей, которые затрудняют выяснение, откуда берутся определения функций.

На данный момент вы знаете, что функция config/3 выполняетсявызывается в файле конфигурации:

config :myapp, MyApp.Endpoint,
  http: [port: 4000],
  debug_errors: true

Кроме того, строка use Mix.Config в верхней части файла конфигурации является подсказкой, что config/3 может быть определено в этом модуле, так что вы можете просмотреть Mix.Config docs .Конечно же, есть функция config/3, которая описана в документации.В документах также описана функция config/2, которая вызывается здесь:

config :myapp,
  http: 4000

Если вы читаете документы для config/2, то, кажется, довольно легко понять, как все работает: когда вы устанавливаете ключи изначения с config/2, вы можете получить определенное значение, связанное с ключом, вызвав:

Application.get_env(:myapp, key)  

Например,

Application.get_env(:myapp, :http)
#=> 4000

Однако, когда вы устанавливаете ключи и значения с помощью config/3, вы не можете получить конкретное значение, связанное с ключом - вместо этого вы в конечном итоге получаете полный список пар ключ / значение:

keyword_list = Application.get_env(:myapp, module)

config/3 создает вложенную структуру, где модуль являетсяkey и его значение - это список ключевых слов, составленный из пар ключ / значение, которые вы указываете в файле конфигурации, например:

  http: [port: 4000],
  debug_errors: true

Еще один способ обдумать это, подумав о вложенной карте:

%{
  myapp: %{
    http: 4000,  #<== config/2
    my_app_endpoint: %{http: [port: 4000, debug_errors: true]}  #<== config/3
  }

... и Application.get_env() позволяет указывать только два ключа, например:

Application.get_env(:myapp, :http)  #=> 4000

или:

Application.get_env(:myapp, :my_app_endpoint)  #=> %{http: [port: 4000, debug_errors: true]}

После получениясписок ключевых слов:

keyword_list = Application.get_env(:myapp, module)

тогда вы должны использовать свой гензнание elixir для извлечения значения, связанного с определенным ключом, из списка ключевых слов:

all = Application.get_all_env(:myapp)
IO.inspect all  #=> lots of stuff (which is not a keyword list)

keyword_list = Application.get_env(:myapp, MyApp.Endpoint)
IO.inspect keyword_list #=> a keyword list with lots of key/value pairs 
http = Keyword.get(keyword_list, :http)
IO.inspect http  #=> [port: 4000]
port = Keyword.get(http_keyword_list, :port)
IO.inspect port  #=>4000
0 голосов
/ 17 декабря 2018

В этом случае вы получаете от звонка fetch_env!/2 список ключевых слов .Вы можете получить к нему доступ так же, как с картой:

Application.fetch_env!(:myapp, :http)[:port]

ИЛИ преобразовать его в карту, и сделать это следующим образом:

Application.fetch_env!(:myapp, :http) |> Map.new |> Map.get(:port)

РЕДАКТИРОВАТЬ - на основе@ Комментарий BrettBeatty

Вы также можете использовать функцию Keyword.get/2:

:myapp |> Application.get_env(:http) |> Keyword.get(:port)
...