我在主模块中以这种方式定义一个常量:
@end_digits_adjusters [11, 12, 14, 21, 22, 23]
以下是我试图测试的方法:
defmodule PriceOptimizerTest do
use ExUnit.Case
doctest PriceOptimizer
test "get_random_adjuster() randomizer" do
adj_num = PriceOptimizer.get_random_adjuster()
is_in? = adj_num in @end_digits_adjusters
assert is_in? == true
end
end
这不起作用。但是当我在测试中明确指定常量值时,它确实有效。像这样......
is_in? = adj_num in [11, 12, 14, 21, 22, 23]
我错过了一个让Elixir能够识别测试中模块常数的步骤吗?
答案 0 :(得分:4)
在其他语言中流行的共享常量在Elixir中不是一种流行的模式。我个人发现,大多数时候我不需要使用这种模式。但是有一些应用程序我已经在它们上构建了很多继电器。
当我需要它们时,我有一个常量模块,我使用以下模块:
defmodule Constants do
@moduledoc """
An alternative to use @constant_name value approach to defined reusable
constants in elixir.
This module offers an approach to define these in a
module that can be shared with other modules. They are implemented with
macros so they can be used in guards and matches
## Examples:
Create a module to define your shared constants
defmodule MyConstants do
use Constants
define something, 10
define another, 20
end
Use the constants
defmodule MyModule do
require MyConstants
alias MyConstants, as: Const
def myfunc(item) when item == Const.something, do: Const.something + 5
def myfunc(item) when item == Const.another, do: Const.another
end
"""
defmacro __using__(_opts) do
quote do
import Constants
end
end
@doc "Define a constant"
defmacro constant(name, value) do
quote do
defmacro unquote(name), do: unquote(value)
end
end
@doc "Define a constant. An alias for constant"
defmacro define(name, value) do
quote do
constant unquote(name), unquote(value)
end
end
@doc """
Import an hrl file.
Create constants for each -define(NAME, value).
"""
defmacro import_hrl(file_name) do
list = parse_file file_name
quote bind_quoted: [list: list] do
for {name, value} <- list do
defmacro unquote(name)(), do: unquote(value)
end
end
end
defp parse_file(file_name) do
for line <- File.stream!(file_name, [], :line) do
parse_line line
end
|> Enum.filter(&(not is_nil(&1)))
end
defp parse_line(line) do
case Regex.run ~r/-define\((.+),(.+)\)\./, line do
nil -> nil
[_, name, value] ->
{String.strip(name) |> String.downcase |> String.to_atom, String.strip(value) |> parse_value}
_ -> nil
end
end
defp parse_value(string) do
case Integer.parse string do
:error -> filter_string(string)
{num, _} -> num
end
end
defp filter_string(string), do: String.replace(string, "\"", "")
end
情侣笔记:
require
陈述。 define
是一个宏。#define
语句列表只是几个关键点:)答案 1 :(得分:1)
我担心,Elixir's module attributes仅在定义的模块中可用。这是因为在编译阶段这些属性在代码中处于联机状态。
如果你想让它们公开可访问,你需要用函数包装它,例如:
defmodule MyMod do
@test "hello"
def test, do: @test
end
所以:
MyMod.test # => "hello"
希望有所帮助!