final class Configuration extends AnyRef
An INI-style configuration file parser.
Configuration
implements an in-memory store for a configuration file
whose syntax is reminiscent of classic Windows .INI files, though with
many extensions.
Syntax
A configuration file is broken into sections, and each section is introduced by a section name in brackets. For example:
[main] installation.directory=/usr/local/foo program.directory: /usr/local/foo/programs [search] searchCommand: find /usr/local/foo -type f -name '*.class' [display] searchFailedMessage=Search failed, sorry.
Notes and caveats:
At least one section is required.
Sections may be empty.
It is an error to have any variable definitions before the first section header.
The section names "system" and "env" are reserved. They don't really
exist, but they're used during variable substitution (see below)
to substitute from System.properties
and the environment,
respectively.
Section Name Syntax
There can be any amount of whitespace before and after the brackets in a section name; the whitespace is ignored. Section names may consist of alphanumeric characters and underscores. Anything else is not permitted.
Variable Syntax
Each section contains zero or more variable settings. Similar to a Java
Properties
file, the variables are specified as name/value pairs,
separated by an equal sign ("=") or a colon (":"). Variable names are
case-sensitive by default, though the case-sensitivity (and other
aspects of the variable name) may be changed by subclassing
Configuration
and providing your own version of the
transformOptionName()
method. Variable names may contain
alphanumerics, underscores, and hyphens (-). Variable values may contain
anything at all. The parser ignores whitespace on either side of the "="
or ":"; that is, leading whitespace in the value is skipped. The way to
include leading whitespace in a value is escape the whitespace
characters with backslashes. (See below).
Continuation Lines
Variable definitions may span multiple lines; each line to be continued must end with a backslash ("\") character, which escapes the meaning of the newline, causing it to be treated like a space character. The following line is treated as a logical continuation of the first line. Unlike Java properties files, however, leading whitespace is not removed from continued lines.
Only variable definition lines may be continued. Section header lines, comment lines (see below) and include directives (see below) cannot span multiple lines.
Expansions of Variable Values
The configuration parser preprocesses each variable's value, replacing embedded metacharacter sequences and substituting variable references. You can use backslashes to escape the special characters that the parser uses to recognize metacharacter and variable sequences; you can also use single quotes. See Suppressing Metacharacter Expansion and Variable Substitution, below, for more details.
Metacharacters
The parser recognizes Java-style ASCII escape sequences \t
, \n
,
\r
, \\
, \
(a backslash and a space), and \
u
xxxx are
recognized and converted to single characters. Note that metacharacter
expansion is performed before variable substitution.
Variable Substitution
A variable value can interpolate the values of other variables, using
a variable substitution syntax. The general form of a variable reference
is ${sectionName.varName}
.
sectionName
is the name of the section containing the variable to
substitute; if omitted, it defaults to the current section. varName
is
the name of the variable to substitute.
If a variable reference specifies a section name, the referenced section must precede the current section. It is not possible to substitute the value of a variable in a section that occurs later in the file.
The section names "system" and "env" are reserved for special "pseudosections."
The "system" pseudosection is used to interpolate values from
System.properties
For instance, ${system.user.home}
substitutes the
value of the user.home
system property (typically, the home directory
of the user running the program). Similarly, ${system.user.name}
substitutes the user's name.
The "env" pseudosection is used to interpolate values from the
environment. On UNIX systems, for instance, ${env.HOME}
substitutes
user's home directory (and is, therefore, a synonym for
${system.user.home}
. On some versions of Windows, ${env.USERNAME}
will substitute the name of the user running the program. Note: On UNIX
systems, environment variable names are typically case-sensitive; for
instance, ${env.USER}
and ${env.user}
refer to different environment
variables. On Windows systems, environment variable names are typically
case-insensitive; ${env.USERNAME}
and ${env.username}
are
equivalent.
Notes and caveats:
Configuration
uses the
grizzled.string.template.UnixShellVariableSubstituter
class to do variable substitution, so it honors all the syntax conventions
supported by that class.
Variable substitutions are only permitted within variable values. They are ignored in variable names, section names, include directives and comments.
Variable substitution is performed after metacharacter expansion (so don't include metacharacter sequences in your variable names).
To include a literal "$" character in a variable value, escape it with a
backslash, e.g., "var=value with \$ dollar sign
"
Suppressing Metacharacter Expansion and Variable Substitution
To prevent the parser from interpreting metacharacter sequences, variable substitutions and other special characters, use the "->" assignment operator, instead of ":" or "=".
For example, suppose you want to set variable "prompt" to the literal value "Enter value. To specify a newline, use \n." The following configuration file line will do the trick:
prompt -> Enter value. To specify a newline, use \n
Similarly, to set variable "abc" to the literal string "${foo}" suppressing the parser's attempts to expand "${foo}" as a variable reference, you could use:
abc -> ${foo}
Note: It's also possible, though hairy, to escape the special meaning
of special characters via the backslash character. For instance, you can
escape the variable substitution lead-in character, '$', with a
backslash. e.g., "\$". This technique is not recommended, however,
because you have to double-escape any backslash characters that you want
to be preserved literally. For instance, to get "\t", you must specify
"\\\\t". To get a literal backslash, specify "\\\\". (Yes, that's four
backslashes, just to get a single unescaped one.) This double-escaping
is a regrettable side effect of how the configuration file parses
variable values: It makes two separate passes over the value (one for
metacharacter expansion and another for variable expansion). Each of
those passes honors and processes backslash escapes. This problem would
go away if the configuration file parser parsed both metacharacter
sequences and variable substitutions itself, in one pass. It doesn't
currently do that, because it uses the separate
grizzled.string.template.UnixShellStringTemplate
class
grizzled.GrizzledString.translateMetachars()
method to do the
variable substitution and metacharacter translation. In general, you're
better off just sticking with the "->" assignment operator.
Includes
A special include directive permits inline inclusion of another configuration file. The include directive takes two forms:
%include "path" %include "URL"
For example:
%include "/home/bmc/mytools/common.cfg" %include "http://configs.example.com/mytools/common.cfg"
If the include path is not a URL, and is not an absolute path, its location is relative to the file that's trying to include it.
The included file may contain any content that is valid for this
parser. It may contain just variable definitions (i.e., the contents of
a section, without the section header), or it may contain a complete
configuration file, with individual sections. Since
Configuration
recognizes a variable syntax that is
essentially identical to Java's properties file syntax, it's also legal
to include a properties file, provided it's included within a valid
section.
Note: Attempting to include a file from itself, either directly or indirectly, will cause the parser to throw an exception.
Comments and Blank Lines
A comment line is a one whose first non-whitespace character is a "#". A blank line is a line containing no content, or one containing only white space. Blank lines and comments are ignored.
Caller-supplied Predefined Sections
Calling applications may supply predefined sections and options, in the form of a map. These sections may then be used by other sections, via variable references. The predefined sections are defined in a map of maps. The outer map is keyed by predefined section name. The inner maps consist of options and their values. For instance, to read a configuration file, giving it access to certain command line parameters, you could do something like this:
def main(args: Array[String]): Unit = { val configFile = args(0) val name = args(1) val ipAddress = args(2) val sections = Map("args" -> Map("name" -> name, "ip" -> ipAddress)) val config = Configuration(configFile, sections) ... }
Note that contents of the configuration file can override the predefined sections.
Applications may also provide a "not found" function that is called to resolve options that are not found in the table. Such a function can be used to supply on-demand sections and values. For example, suppose you want to do something crazy, such as look up any not-found values in a database. (This is probably a very bad idea, but it makes a good example.) You might do something like this:
def findInDatabase(sectionName: String, optionName: String): Either[String, Option[String]] = { val select = "SELECT value FROM config WHERE section = ? and option = ?" ... } val config = Configuration(configFile, notFoundFunction = findInDatabase)
- Alphabetic
- By Inheritance
- Configuration
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
-
def
+(section: String, option: String, value: String): Configuration
Add a value to the configuration, returning a new object.
Add a value to the configuration, returning a new object. If the option already exists in the specified section, it is replaced in the new configuration. Otherwise, it's added. If the section doesn't exist, it's created and the option is added.
Example:
val cfg = Configuration(...) val newCfg = cfg + ("myNewSection", "optionName", "value")
- section
the section name
- option
the option name
- value
the value
- returns
a new
Configuration
object with the change applied.
-
def
++(newValues: Map[String, Map[String, String]]): Configuration
Add new sections to the configuration.
Add new sections to the configuration. Example usage:
val cfg = Configuration(...) val newCfg = cfg ++ Map( "newSection1" -> Map("option1" -> "value1", "option2" -> "value2"), "newSection2" -> Map("option1" -> "value1") )
- newValues
A map of (section -> Map(option -> value)) values
- returns
new configuration
-
def
++(values: (String, (String, String))*): Configuration
Add multiple (section -> (option -> value)) triplets to the configuration, returning the new configuration.
Add multiple (section -> (option -> value)) triplets to the configuration, returning the new configuration. Example use:
val cfg = Configuration(...) val newCfg = cfg ++ (("newSection1" -> ("option1" -> "value1")), ("newSection2" -> ("option1" -> "value1")), ("newSection1" -> ("option3" -> "value3")))
- values
one or more (section -> (option -> value)) triplets
- returns
new configuration
-
def
-(section: String, option: String): Configuration
Remove a value from the configuration, returning a new object.
Remove a value from the configuration, returning a new object. If the section or option don't exist, the original configuration is returned (not a copy). If the section and option exist, the option is removed. If the section is then empty, it's also removed.
- section
the section name
- option
the option name
- returns
a new
Configuration
object with the change applied, or the original configuration if the section or option weren't there.
-
def
--(values: Seq[(String, String)]): Configuration
Remove multiple (section -> option) pairs from the configuration, returning the new configuration.
Remove multiple (section -> option) pairs from the configuration, returning the new configuration. Example use:
val cfg = Configuration(...) val newCfg = cfg -- (("newSection1" -> "option1"), ("newSection2" -> "option1"), ("newSection1" -> "option3"))
- values
sequence of (section, option) pairs
- returns
new configuration
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
asEither[T](sectionName: String, optionName: String)(implicit converter: ValueConverter[T]): Either[String, Option[T]]
Get a value as an instance of specified type.
Get a value as an instance of specified type. This method retrieves the value of an option from a section and, using the specified (or implicit) converter, attempts to convert the option's to the specified type. If you import
grizzled.config.Configuration.Implicits._
, you'll bring implicit converters for various common types into scope.If
safe
istrue
(as defined when theConfiguration
object is built), substitutions of nonexistent variables will result in empty strings for where the substitutions were specified (e.g.,val${section1.notValid}
will result in the string "val"). Ifsafe
isfalse
, substitutions of nonexistent values will result in an error (i.e., aLeft
result).- T
the desired type of the result
- sectionName
the section from which to retrieve the value
- optionName
the name of the option whose value is to be returned
- converter
a
ValueConverter
object that will handle the actual conversion.- returns
Left(error)
on conversion error.Right(None)
if not found.Right(Some(value))
if found and converted.
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
asOpt[T](sectionName: String, optionName: String)(implicit converter: ValueConverter[T]): Option[T]
Get a value as an instance of specified type.
Get a value as an instance of specified type. This method retrieves the value of an option from a section and, using the specified (or implicit) converter, attempts to convert the option's to the specified type. If you import
grizzled.config.Configuration.Implicits._
, you'll bring implicit converters for various common types into scope.- T
the desired type of the result
- sectionName
the section from which to retrieve the value
- optionName
the name of the option whose value is to be returned
- converter
a
ValueConverter
object that will handle the actual conversion.- returns
None
if not found or not convertible,Some(value)
if found and converted. If you want to distinguish between "not found" and "cannot convert", useasEither()
.
-
def
asTry[T](sectionName: String, optionName: String)(implicit converter: ValueConverter[T]): Try[Option[T]]
Get a value as an instance of specified type.
Get a value as an instance of specified type. This method retrieves the value of an option from a section and, using the specified (or implicit) converter, attempts to convert the option's to the specified type. If you import
grizzled.config.Configuration.Implicits._
, you'll bring implicit converters for various common types into scope.If
safe
istrue
(as defined when theConfiguration
object is built), substitutions of nonexistent variables will result in empty strings for where the substitutions were specified (e.g.,val${section1.notValid}
will result in the string "val"). Ifsafe
isfalse
, substitutions of nonexistent values will result in an error (i.e., aLeft
result).- T
the desired type of the result
- sectionName
the section from which to retrieve the value
- optionName
the name of the option whose value is to be returned
- converter
a
ValueConverter
object that will handle the actual conversion.- returns
Failure(error)
on conversion error.Success(None)
if not found.Success(Some(value))
if found and converted.
-
def
clone(): AnyRef
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
finalize(): Unit
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( classOf[java.lang.Throwable] )
-
def
forMatchingSections(regex: Regex)(code: (Section) ⇒ Unit): Unit
Invoke a code block on each section whose name matches a regular expression.
Invoke a code block on each section whose name matches a regular expression.
- regex
the regular expression to match
- code
the block of code to invoke with each section
-
def
get(sectionName: String, optionName: String): Option[String]
Works like
Map.get()
, returningSome(string)
if the value is found,None
if not.Works like
Map.get()
, returningSome(string)
if the value is found,None
if not. Does not throw exceptions.- sectionName
the section name
- optionName
the option name
- returns
Some(value)
if the section and option exist,None
if either the section or option cannot be found.
-
def
getAsList(sectionName: String, optionName: String, separators: Regex = """[\s,]""".r): Option[List[String]]
Retrieve a value, splitting it into a list of strings.
Retrieve a value, splitting it into a list of strings. Returns
Some(list)
if the key is found, andNone
otherwise.- sectionName
the section name
- optionName
the option name
- separators
separator regex to use. Default: [\s,]
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
def
getEither(sectionName: String, optionName: String): Either[String, Option[String]]
Like
get()
, except that this method returns anEither
, allowing errors to be captured and processed.Like
get()
, except that this method returns anEither
, allowing errors to be captured and processed.NOTE: Prefer
tryGet()
, as this method may eventually go away.- sectionName
the section name
- optionName
the option name
- returns
Left(error)
on error.Right(None)
if not found.Right(Some(value))
if found and processed.
-
def
getOrElse(sectionName: String, optionName: String, default: String): String
Works like
Map.getOrElse()
, returning an option value or a default, if the option has no value.Works like
Map.getOrElse()
, returning an option value or a default, if the option has no value. Does not throw exceptions. Calling this function is the same as:get(sectionName, optionName).getOrElse(default)
- sectionName
the section name
- optionName
the option name
- default
the default value
- returns
The option's value if the section and option exist, the default if either the section or option cannot be found.
-
def
getSection(name: String): Option[Section]
Get a section.
Get a section. Similar to
Map.get
, this method returnsSome(Section)
if the section exists, andNone
if it does not.- name
the section to get
- returns
Some(Section)
orNone
-
def
hasSection(sectionName: String): Boolean
Determine whether the configuration contains a named section.
Determine whether the configuration contains a named section.
- sectionName
the new section's name
- returns
true
if the configuration has a section with that name,false
otherwise
-
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
def
matchingSections(regex: Regex): Seq[Section]
Return a sequence of sections whose name match matches a regular expression.
Return a sequence of sections whose name match matches a regular expression.
- regex
the regular expression to match
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
def
optionNames(sectionName: String): Iterator[String]
Get the list of option names.
Get the list of option names.
- sectionName
the section's name
- returns
a list of option names in that section. The iterator will be empty if the section doesn't exist.
-
def
options(sectionName: String): Map[String, String]
Get all options in a section.
Get all options in a section.
- sectionName
the section name
- returns
a map of all options and their values for the section. If the section doesn't exist, an empty map is returned.
-
def
sectionNames: Iterator[String]
Get the list of section names.
Get the list of section names.
- returns
the section names, in a iterator
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
-
def
toString(): String
- Definition Classes
- AnyRef → Any
-
def
tryGet(sectionName: String, optionName: String): Try[Option[String]]
Like
get()
, except that this method returns aTry
, allowing errors to be captured and processed.Like
get()
, except that this method returns aTry
, allowing errors to be captured and processed.- sectionName
the section name
- optionName
the option name
- returns
Failure(error)
on error.Success(None)
if not found.Success(Some(value))
if found and processed.
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )