The task is to read a configuration file in standard configuration file format,
and set variables accordingly.

For this task, we have a configuration file as follows:

# This is a configuration file in standard configuration file format
#
# Lines beginning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.

# This is the fullname parameter
FULLNAME Foo Barber

# This is a favourite fruit
FAVOURITEFRUIT banana

# This is a boolean that should be set
NEEDSPEELING

# This boolean is commented out
; SEEDSREMOVED

# Configuration option names are not case sensitive, but configuration parameter
# data is case sensitive and may be preserved by the application program.

# An optional equals sign can be used to separate configuration parameter data
# from the option name. This is dropped by the parser. 

# A configuration option may take multiple parameters separated by commas.
# Leading and trailing whitespace around parameter names and parameter data fields
# are ignored by the application program.

OTHERFAMILY Rhu Barber, Harry Barber



For the task we need to set four variables according to the configuration entries as follows:

fullname = Foo Barber
favouritefruit = banana
needspeeling = true
seedsremoved = false


We also have an option that contains multiple parameters. These may be stored in an array.

 otherfamily(1) = Rhu Barber
 otherfamily(2) = Harry Barber


Related tasks
 Update a configuration file


(ns read-conf-file.core
  (:require [clojure.java.io :as io]
            [clojure.string :as str])
  (:gen-class))
 
(def conf-keys ["fullname"
                "favouritefruit"
                "needspeeling"
                "seedsremoved"
                "otherfamily"])
 
(defn get-lines
  "Read file returning vec of lines."
  [file]
  (try 
    (with-open [rdr (io/reader file)]
      (into [] (line-seq rdr)))
    (catch Exception e (.getMessage e))))
 
(defn parse-line
  "Parse passed line returning vec: token, vec of values."
  [line]
  (if-let [[_ k v] (re-matches #"(?i)^\s*([a-z]+)(?:\s+|=)?(.+)?$" line)]
    (let [k (str/lower-case k)]
      (if v
        [k (str/split v #",\s*")]
        [k [true]]))))
 
(defn mk-conf
  "Build configuration map from lines."
  [lines]
  (->> (map parse-line lines)
       (filter (comp not nil?))
       (reduce (fn
                 [m [k v]]
                 (assoc m k v)) {})))
 
(defn output
  [conf-keys conf]
  (doseq [k conf-keys]
    (let [v (get conf k)]
      (if v
        (println (format "%s = %s" k (str/join ", " v)))
        (println (format "%s = %s" k "false"))))))
 
(defn -main
  [filename]
  (output conf-keys (mk-conf (get-lines filename))))