2017-04-16 51 views
0

我试图在此Elixir代码中调用String.replace,该代码从structs列表中获取其值,但它只是导致运行时错误。String.replace在Enum.reduce中引发RuntimeError

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" => "[email protected]","default" => "[email protected]","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

你的问题就在这里是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}}\ 
""" 

(注意双引号""",而不是单个的人'''

+0

谢谢 - 别人提起过,但我认为这应用于'String.replace'的参数。 String.replace的匿名函数应该更新sslCmd不工作,我认为这是由于不变性。我该如何重组以及为避免这种情况需要添加哪些变量? – vfclists