- Creating a ReasonML Native App: What We Are Building
- Creating a ReasonML Native App: Installing, Editing, Configuring
- Creating a ReasonML Native App: Building and Running
- Creating a ReasonML Native App: Command Line Arguments
- Creating a ReasonML Native App: Curses Terminal Interface
- Creating a ReasonML Native App: Python Plugins
- Creating a ReasonML Native App: Files I/Os
- Creating a ReasonML Native App: Native Promises
- Creating a ReasonML Native App: Web Requests
- Creating a ReasonML Native App: Shell Commands
- Creating a ReasonML Native App: Handling CSV Files
- Creating a ReasonML Native App: Native JSON Handling
- Creating a ReasonML Native App: Memoizing DNS queries
This is going to be a fairly short post, as it focuses on using the config-file
library. As previously mentioned, when I mention a library in RasonML’s native context, chances are pretty good that I am referring to one of OCaml’s many available libraries.
Our configuration files are not going to be json-formatted of xml-based; instead they are a tad…OCaml-ish, which of course is instantly betrayed by our use of comments:
host_info = {
(* Server ip address or host name *)
ip = "127.0.0.1"
(* User name (or none if no login is required) *)
user = user
...
}
This library’s usage is pretty straightforward: after opening the library, we instantiate a new group
object. The first thing we will do is create a default configuration file with sane values. Thus far, we have:
open Config_file;
let group = new group;
...
group#write("config/default.cfg");
objectname#member
and not using dot notation. This behavior is inherited from OCaml.To be clear, this code does not do much of anything: it is writing an empty configuration file. What we need to do, before writing the file, is create a few entries:
let _ip = (new string_cp)(
~group,
["host_info", "ip"],
"127.0.0.1",
"Server ip address or host name");
...
The library supports several types of configuration objects:
- int_cp, float_cp, bool_cp, string_cp, list_cp, option_cp, enumeration_cp, tuple2_cp, tuple3_cp, tuple4_cp, string2_cp, font_cp, filename_cp
We construct an object with:
- which group this preference belongs to, the key’s hierarchy, a default value and a description.
myname = myname
=> ~myname
But, what if you want to make a preference optional?
This is the option_cp
type. Use a wrapper to turn objects into these option types. For instance, to provide an optional string:
let _start_at = (new option_cp)(
string_wrappers,
~group,
["run_info", "start_at"],
None,
"Only start test when matching this record timestamp/duration");
Rather than None
obviously our default value could have been Some("my-time")
Reading
Reading a configuration file is just as straightforward:
let read_config_file = (dir_path) => {
group#read(
~on_type_error=
(groupable_cp, raw_cp, output, filename, in_channel) =>
{
/*
* Handle read error. Parameter names can be retrieved using
* String.concat(".", groupable_cp#get_name),
*/
},
sprintf("%s/default.cfg", dir_path));
};
Bonus: reading a .ignore file line-by-line
This is helpful for quick prototyping: how do you read an arbitrary collection of strings from a file?
let read_ignore_list = (dir_path, name) =>
List.fold_left((accu, item) =>
StringSet.add(item, accu),
StringSet.empty,
Str.split(
Str.regexp("\n"),
my_read_file_function(sprintf("%s/ignored.%s", dir_path, name)))
);
Comments powered by Talkyard.