String.replace在Enum.reduce中引发RuntimeError

时间:2017-04-16 08:08:16

标签: elixir

我尝试在此Elixir代码中调用String.replace,该代码从structs列表中获取其值,但这只会导致运行时错误。

String.replace函数的字符串参数全部打印出来,一切正常。为什么会这样?

以下是导致错误的行:

Enum.reduce(structList, sslCmd, fn(x, sslCmd) -> String.replace(sslCmd, "{{#{x.key}}}", x.value) end)
# Runtime error here


** (ArgumentError) argument error
    (stdlib) binary.erl:275: :binary.replace/4
    (elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/code.ex:363: Code.require_file/2

这是完整的代码:

defmodule ParamStruct do                                                                                                                         
  defstruct key: "", value: "", default: "", description: "description of parameter", label: "label on web form", required: false, order: 99     
end                                                                                                                                              

defmodule TemplateStruct do                                                                                                                      
  defstruct key: "must be unique", name: "descriptive name", code: "", executable: false, destination: "", delete_after: false,                  
  perms: "644"                                                                                                                                   
end                                                                                                                                              

defmodule ProcessList do                                                                                                                         
  def parse_list([]), do: []                                                                                                                     

  def parse_list([%{"key" => ky,"value" => val,"default" => dft, "description" => desc,"label" => lbl} | tail]) do
    [%ParamStruct{key: ky, value: val, description: desc, label: lbl, default: dft } | parse_list(tail) ]
  end                                                                                                                                            

  def create_recommend_list(%{"itemScores" => score_list})  do                                                                                   
    parse_list(score_list)                                                                                                                       
  end                                                                                                                                            
end   

params = [                                                                                                                                     
%{"key" => "ca_cert_subj_state","value" => "Greater London","default" => "Greater London","description" => "Region","label" => "State/County"},                
  %{"key" => "key-file","value" => "cacert_001","default" => "cacert_001","description" => "","label" => "Key File (without password)"},                   
  %{"key" => "key-file-pass","value" => "cacert_pass_001","default" => "cacert_pass_001","description" => "","label" => "Key File (with password)"},            
  %{"key" => "ca_cert_email","value" => "admin@domain.net","default" => "admin@domain.net","description" => "","label" => "Email"},                              
  %{"key" => "ca_cert_subj_common_name","value" => "Elixir User","default" => "domain.net","description" => "","label" => "Common Name"},                   
  %{"key" => "ca_cert_subj_country","value" => "UK","default" => "UK","description" => "Country","label" => "Country"},                            
  %{"key" => "ca_cert_subj_location","value" => "Manchester","default" => "Westchester","description" => "","label" => "Location"},                        
  %{"key" => "ca_cert_subj_organization","value" => "Elixir Programs Forum","default" => "Big Company","description" => "","label" => "Organisation"},                
  %{"key" => "ca_cert_subj_org_unit","value" => "IT Department","default" => "Infosystems and Communications","description" => "","label" => "Organisational Unit"}                                                                                                                                            
  ]          

sslCmd = '''
openssl req -x509 -new -nodes -sha256 \
 -key {{key-file-pass}}.key \
 -days 3650 \
 -out {{key-file-pass}}.pem \
 -subj "\
/C={{ca_cert_subj_country}}\
/ST={{ca_cert_subj_state}}\
/L={{ca_cert_subj_location}}\
/O={{ca_cert_subj_organization}}\
/OU={{ca_cert_subj_org_unit}}\
/CN={{ca_cert_subj_common_name}}\
/emailAddress={{ca_cert_email}}\

'''
structList = ProcessList.parse_list(params)  
#IO.inspect ProcessList.parse_list(params)
# [first | _ ] = ProcessList.parse_list(params)
# IO.puts " #{first.key} is #{first.value} "

# IO.inspect first
IO.puts sslCmd
IO.puts "list of keys and values"
IO.puts "======================="
Enum.reduce(structList, sslCmd, fn(x, sslCmd) -> IO.puts " #{x.key} is #{x.value} " end) 

Enum.reduce(structList, sslCmd, fn(x, sslCmd) -> String.replace(sslCmd, "{{#{x.key}}}", x.value) end)
# Runtime error here

** (ArgumentError) argument error
    (stdlib) binary.erl:275: :binary.replace/4
    (elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/code.ex:363: Code.require_file/2

1 个答案:

答案 0 :(得分:1)

您的问题是,sslCmdChar List, not a String,这就是您无法在其上调用String.replace的原因(仅适用于字符串a.k.a二进制文件)。

最简单的解决方案是将sslCmd的值更改为:

sslCmd = """
openssl req -x509 -new -nodes -sha256 \
 -key {{key-file-pass}}.key \
 -days 3650 \
 -out {{key-file-pass}}.pem \
 -subj ""\
/C={{ca_cert_subj_country}}\
/ST={{ca_cert_subj_state}}\
/L={{ca_cert_subj_location}}\
/O={{ca_cert_subj_organization}}\
/OU={{ca_cert_subj_org_unit}}\
/CN={{ca_cert_subj_common_name}}\
/emailAddress={{ca_cert_email}}\
"""

(注意双引号"""而不是单引号'''