0

I'm attempting to call String.replace in this Elixir code which gets its values from a list of structs, but it just results in a runtime error.

The string parameters to the String.replace function are all printed out and it all seems normal. Why is this happening?


Here's the line responsible for the error:

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

This is the full code:

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 Answer 1

1

Your problem here is that sslCmd is a Char List, not a String and that's why you can't call String.replace on it (which only works on Strings a.k.a Binaries).

The simplest solution is to change the value of sslCmd to this:

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}}\
"""

(Notice the double quotes """ instead of the single ones ''')

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks - someone else mentioned it but I thought it applied to the parameters to the String.replace. The anonymous functon for the String.replace is supposed to update the sslCmd is not working, which I suppose is due to immutability. How can I restructure and what variables do I need to add to avoid that?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.