Properties class
The Properties class implementing all tools to load key-values from file both by name and path.
class Properties{ /// The encoding used to read the file Encoding _encoding; /// The content of the properties file in terms of key - value couples Map<String,String> _content; /// An internal reference to the source file. String _sourceFile; /// Events are enabled by default bool _enableEvents = true; /// The property added event name static const String ADD_PROPERTY_EVENTNAME = 'add'; static const String UPDATE_PROPERTY_EVENTNAME = 'update'; StreamController eventController; /** * Create a new properties instance by naming the source file using [name] * and, optionally, setting the desired [encoding]. */ Properties(String name, [Encoding encoding = Encoding.UTF_8]){ this._sourceFile = name; this._encoding = encoding; _init(); _initFromFile(); } /** * Create a new properties instance from file [path] * and, optionally, setting the desired [encoding]. */ Properties.fromFile(String path, [Encoding encoding = Encoding.UTF_8]){ this._sourceFile = path; this._encoding = encoding; _init(); _initFromFile(); } /** * Create a new properties instance using the input [jsonMap] * to load the data from. */ Properties.fromJSON(String jsonMap){ _init(); _content = JSON.parse(jsonMap) as Map<String,String>; } /** * Initialize common internal tools such as event controllers. */ _init() { eventController = new StreamController<PropertiesEvent>.broadcast(); } void _initFromFile() => _load(_read(_sourceFile, _encoding)); /** * Create the file object and read its content in lines. */ List<String> _read(String path, Encoding encoding) { var f = _getFile(path); if(f == null || !f.existsSync()) return null; return f.readAsLinesSync(this._encoding); } /** * Load properties from lines. */ _load(List<String> lines) { if(lines == null || lines.isEmpty) return null; _content = new Map<String,String>(); for(String line in lines){ line = line.trim(); if(_isProperty(line)){ List<String> keyvalue = line.split('='); if(keyvalue.length == 2 && keyvalue[0] != null) _content[keyvalue[0].trim()] = keyvalue[1].trim(); } } } /** * Determine if input line is a property or not. */ _isProperty(String line) { if(line.isEmpty || line == null) return false; if(line.startsWith('#')) return false; if(line.contains('=')) return true; return false; } /** * Get a file instance from the input string [file]. */ File _getFile(String file){ var result = new File(file); if(result.existsSync()) return result; result = new File.fromPath(new Path(file)); if(result.existsSync()) return result; throw new FileIOException('It\'s impossible to load properties from input file ${file}. File does not exist.'); } /** Loads the value of a property given its [key] */ String get(String key, {Object defval, String defkey}) { if(!?key) return null; if(_content == null) return null; if(defval == null && defkey == null) return _content[key]; if(_content[key] == null){ if(defval != null) return defval.toString(); if(defkey != null) return _content[defkey]; } return _content[key]; } /** Loads the value of a property as an integer given its [key] */ int getInt(String key, {bool throwException:false, int defval, String defkey}) { if(!?key) return null; if(_content == null) return null; var value = get(key, defval:defval, defkey:defkey); if(value == null) return null; try { return int.parse(value); } on FormatException catch (e) { if(throwException) throw e; return null; } } /** Loads the value of a property as a double given its [key] */ double getDouble(String key, {bool throwException:false, double defval, String defkey}) { if(!?key) return null; if(_content == null) return null; String value = get(key, defval:defval, defkey:defkey); if(value == null) return null; try { return double.parse(value); } on FormatException catch (e) { if(throwException) throw e; return null; } } /** Check whether the properties contains a property given its [key] */ bool contains(String key) => key != null ? _content != null ? _content.containsKey(key) : null : null; /** Rerturns the whole set of keys */ Iterable<String> get keys => _content.keys; /** Returns the whole set of values */ Collection<String> get values => _content.values; /** Returns the current number of properties */ int get size => _content.length; /** * Add a property to the instance having name [key] and * value [value]. If the property already exists its value * will be replaced. Returns true if the property was * added successfully, false otherwise. * * If and only if a new property is added an ADD event is * triggered. */ bool add(String key, String value, [bool overwriteExisting = true]){ if(key == null || value == null) return false; if(contains(key) && overwriteExisting){ _update(key, value); return true; } if(!contains(key)){ _add(key,value); return true; } return false; } /** * Internal add implementation, managing property storage and * event triggering. */ _add(String key, String value) { _content[key] = value; if(this._enableEvents) eventController.add(new AddEvent(key, value)); } /** * Internal update implementation, managing property storage and * event triggering. */ _update(String key, String newvalue) { String oldvalue = _content[key]; _content[key] = newvalue; if(this._enableEvents) eventController.add(new UpdateEvent(key, newvalue, oldvalue)); } /** * Merge input [properties] content with the current instance's properties. * By defatult already existing properties will be overwritten. Anyway user * may decide how to manage existing thanks to the optional parameter [overwriteExisting]. */ void merge(Properties properties, [bool overwriteExisting = true]){ for(String key in properties.keys){ if(overwriteExisting || _content[key] == null){ _content[key] = properties.get(key); } } } /** * Merge properties from the input [map] with the current instance's properties. * By defatult already existing properties will be overwritten. Anyway user * may decide how to manage existing thanks to the optional parameter [overwriteExisting]. */ void mergeMap(Map<String,String> map, [bool overwriteExisting = true]){ for(String key in map.keys){ if(overwriteExisting || _content[key] == null){ _content[key] = map[key]; } } } /** * Merge properties from the input [jsonMap] with the current instance's properties. * By defatult already existing properties will be overwritten. Anyway user * may decide how to manage existing thanks to the optional parameter [overwriteExisting]. */ void mergeJSON(String jsonMap, [bool overwriteExisting = true]){ var parsed = JSON.parse(jsonMap) as Map<String,String>; for(String key in parsed.keys){ if(overwriteExisting || _content[key] == null){ _content[key] = parsed[key]; } } } /** * Returns a map containg every property whos key satisifies the predicate [k] on the property key, and * optionally the predicate [v] on the corresponding value. Returns an empty map otherwise. */ Map<String,String> every(bool k(String str), [bool v(String val)]) { if(v == null) v = (String s) => true; var result = new Map<String,String>(); for (String key in _content.keys) if (k(key) && v(get(key))) result[key] = get(key); return result; } /** * Reloads the properties from file. Works for file sources only. */ reload(){ if(_sourceFile == null) return; _content.clear(); _initFromFile(); } /** * Export the content as a JSON map. If no input parameter is set, then the whole set of * properties will be exporte as a JSON map. If the [prefix] parameter is set, * then only the keys starting with [prefix] will be exported. If the [suffix] parameter is set, * then only the keys starting with [suffix] will be exported. If both are set, then only the * keys matching both will be exported. */ String toJSON({String prefix, String suffix}){ var toExport = _content; if(?prefix && ?suffix) toExport = every((key) => key.startsWith(prefix) && key.endsWith(suffix)); else if(?prefix) toExport = every((key) => key.startsWith(prefix)); else if(?suffix) toExport = every((key) => key.endsWith(suffix)); return JSON.stringify(toExport); } /** * Returns the whole content as a String. */ String toString() => _content.toString(); /** * Getter for [enableEvents] flag. */ bool get enableEvents => this._enableEvents; /** * Enable / disable events triggering on this instance. */ set enableEvents(bool enable) => this._enableEvents = enable; /** * Get the stream instance for the "property added" event. */ Stream get onAdd => eventController.stream; /** * Get the stream instance for the "property updated" event. */ Stream get onUpdate => eventController.stream; }
Static Properties
Constructors
new Properties(String name, [Encoding encoding = Encoding.UTF_8]) #
Create a new properties instance by naming the source file using name and, optionally, setting the desired encoding.
Properties(String name, [Encoding encoding = Encoding.UTF_8]){ this._sourceFile = name; this._encoding = encoding; _init(); _initFromFile(); }
new Properties.fromFile(String path, [Encoding encoding = Encoding.UTF_8]) #
Create a new properties instance from file path and, optionally, setting the desired encoding.
Properties.fromFile(String path, [Encoding encoding = Encoding.UTF_8]){ this._sourceFile = path; this._encoding = encoding; _init(); _initFromFile(); }
Properties
bool get enableEvents #
Getter for enableEvents flag.
bool get enableEvents => this._enableEvents;
set enableEvents(bool enable) #
Enable / disable events triggering on this instance.
set enableEvents(bool enable) => this._enableEvents = enable;
StreamController eventController #
eventController
final Iterable<String> keys #
Rerturns the whole set of keys
Iterable<String> get keys => _content.keys;
final Stream onAdd #
Get the stream instance for the "property added" event.
Stream get onAdd => eventController.stream;
final Stream onUpdate #
Get the stream instance for the "property updated" event.
Stream get onUpdate => eventController.stream;
final Collection<String> values #
Returns the whole set of values
Collection<String> get values => _content.values;
Methods
bool add(String key, String value, [bool overwriteExisting = true]) #
Add a property to the instance having name key and value value. If the property already exists its value will be replaced. Returns true if the property was added successfully, false otherwise.
If and only if a new property is added an ADD event is triggered.
bool add(String key, String value, [bool overwriteExisting = true]){ if(key == null || value == null) return false; if(contains(key) && overwriteExisting){ _update(key, value); return true; } if(!contains(key)){ _add(key,value); return true; } return false; }
bool contains(String key) #
Check whether the properties contains a property given its key
bool contains(String key) => key != null ? _content != null ? _content.containsKey(key) : null : null;
Map<String, String> every(bool k(String str), [bool v(String val)]) #
Returns a map containg every property whos key satisifies the predicate k on the property key, and optionally the predicate v on the corresponding value. Returns an empty map otherwise.
Map<String,String> every(bool k(String str), [bool v(String val)]) { if(v == null) v = (String s) => true; var result = new Map<String,String>(); for (String key in _content.keys) if (k(key) && v(get(key))) result[key] = get(key); return result; }
String get(String key, {Object defval, String defkey}) #
Loads the value of a property given its key
String get(String key, {Object defval, String defkey}) { if(!?key) return null; if(_content == null) return null; if(defval == null && defkey == null) return _content[key]; if(_content[key] == null){ if(defval != null) return defval.toString(); if(defkey != null) return _content[defkey]; } return _content[key]; }
double getDouble(String key, {bool throwException: false, double defval, String defkey}) #
Loads the value of a property as a double given its key
double getDouble(String key, {bool throwException:false, double defval, String defkey}) { if(!?key) return null; if(_content == null) return null; String value = get(key, defval:defval, defkey:defkey); if(value == null) return null; try { return double.parse(value); } on FormatException catch (e) { if(throwException) throw e; return null; } }
int getInt(String key, {bool throwException: false, int defval, String defkey}) #
Loads the value of a property as an integer given its key
int getInt(String key, {bool throwException:false, int defval, String defkey}) { if(!?key) return null; if(_content == null) return null; var value = get(key, defval:defval, defkey:defkey); if(value == null) return null; try { return int.parse(value); } on FormatException catch (e) { if(throwException) throw e; return null; } }
void merge(Properties properties, [bool overwriteExisting = true]) #
Merge input properties content with the current instance's properties. By defatult already existing properties will be overwritten. Anyway user may decide how to manage existing thanks to the optional parameter overwriteExisting.
void merge(Properties properties, [bool overwriteExisting = true]){ for(String key in properties.keys){ if(overwriteExisting || _content[key] == null){ _content[key] = properties.get(key); } } }
void mergeJSON(String jsonMap, [bool overwriteExisting = true]) #
Merge properties from the input jsonMap with the current instance's properties. By defatult already existing properties will be overwritten. Anyway user may decide how to manage existing thanks to the optional parameter overwriteExisting.
void mergeJSON(String jsonMap, [bool overwriteExisting = true]){ var parsed = JSON.parse(jsonMap) as Map<String,String>; for(String key in parsed.keys){ if(overwriteExisting || _content[key] == null){ _content[key] = parsed[key]; } } }
void mergeMap(Map<String, String> map, [bool overwriteExisting = true]) #
Merge properties from the input map with the current instance's properties. By defatult already existing properties will be overwritten. Anyway user may decide how to manage existing thanks to the optional parameter overwriteExisting.
void mergeMap(Map<String,String> map, [bool overwriteExisting = true]){ for(String key in map.keys){ if(overwriteExisting || _content[key] == null){ _content[key] = map[key]; } } }
reload() #
Reloads the properties from file. Works for file sources only.
reload(){ if(_sourceFile == null) return; _content.clear(); _initFromFile(); }
String toJSON({String prefix, String suffix}) #
Export the content as a JSON map. If no input parameter is set, then the whole set of properties will be exporte as a JSON map. If the prefix parameter is set, then only the keys starting with prefix will be exported. If the suffix parameter is set, then only the keys starting with suffix will be exported. If both are set, then only the keys matching both will be exported.
String toJSON({String prefix, String suffix}){ var toExport = _content; if(?prefix && ?suffix) toExport = every((key) => key.startsWith(prefix) && key.endsWith(suffix)); else if(?prefix) toExport = every((key) => key.startsWith(prefix)); else if(?suffix) toExport = every((key) => key.endsWith(suffix)); return JSON.stringify(toExport); }