Class: Construct
Constant Summary collapse
- APP_NAME =
Construct is extensible, persistent, structured configuration for Ruby and humans with text editors.
'Construct'
- APP_VERSION =
'0.1.7'
- APP_AUTHOR =
'Kyle Kingsbury'
- APP_CONTRIBUTORS =
['Kyle Kingsbury', 'Spencer Miles', 'John MacKenzie']
- APP_EMAIL =
'[email protected]'
- APP_URL =
'http://github.com/aphyr/construct'
Instance Attribute Summary collapse
-
#data ⇒ Object
Returns the value of attribute data.
-
#schema ⇒ Object
Returns the value of attribute schema.
Class Method Summary collapse
-
.define(key, schema) ⇒ Object
Define a schema for a key on the class.
-
.load(yaml) ⇒ Object
Load a construct from a YAML string.
- .load_file(filename) ⇒ Object
-
.schema ⇒ Object
Returns the class schema.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #[](key) ⇒ Object
-
#[]=(key, value) ⇒ Object
Assign a value to a key.
-
#clear ⇒ Object
Clears the data in the construct.
-
#define(key, options = {}) ⇒ Object
Defines a new field in the schema.
-
#delete(key) ⇒ Object
delete simply removes the value from the data hash, but leaves the schema unchanged.
-
#dup ⇒ Object
A deep (not shallow!) clone of this construct.
-
#each ⇒ Object
Like enumerable#each.
-
#include?(*args) ⇒ Boolean
Returns true if the construct has a value set for, or the schema defines, the key.
-
#initialize(data = {}, schema = {}) ⇒ Construct
constructor
A new instance of Construct.
-
#keys ⇒ Object
Returns the keys, both set in the construct and specified in the schema.
- #load(yaml) ⇒ Object
- #method_missing(meth, *args) ⇒ Object
-
#to_hash ⇒ Object
Flattens this construct (recursively) into a hash, merging schema with values.
-
#to_yaml(opts = {}) ⇒ Object
Dumps the data (not the schema!) of this construct to YAML.
Constructor Details
#initialize(data = {}, schema = {}) ⇒ Construct
Returns a new instance of Construct.
41 42 43 44 45 46 47 |
# File 'lib/construct.rb', line 41 def initialize(data = {}, schema = {}) @data = Hash.new data.each do |key, value| self[key] = value end @schema = self.class.schema.merge(schema) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/construct.rb', line 138 def method_missing(meth, *args) meth_s = meth.to_s if meth_s[-1..-1] == '=' # Assignment if args.size != 1 raise ArgumentError.new("#{meth} takes exactly one argument") end self[meth_s[0..-2]] = args[0] elsif include? meth self[meth] else raise NoMethodError.new("no such key #{meth} in construct") end end |
Instance Attribute Details
#data ⇒ Object
Returns the value of attribute data.
39 40 41 |
# File 'lib/construct.rb', line 39 def data @data end |
#schema ⇒ Object
Returns the value of attribute schema.
39 40 41 |
# File 'lib/construct.rb', line 39 def schema @schema end |
Class Method Details
.define(key, schema) ⇒ Object
Define a schema for a key on the class. The class schema is used as the defaults on initialization of a new instance.
18 19 20 21 |
# File 'lib/construct.rb', line 18 def self.define(key, schema) key = key.to_sym if String === key self.schema[key] = schema end |
.load(yaml) ⇒ Object
Load a construct from a YAML string
24 25 26 27 |
# File 'lib/construct.rb', line 24 def self.load(yaml) hash = YAML::load(yaml) new(hash) end |
.load_file(filename) ⇒ Object
29 30 31 32 |
# File 'lib/construct.rb', line 29 def self.load_file(filename) hash = YAML::load_file(filename) new(hash) end |
.schema ⇒ Object
Returns the class schema
35 36 37 |
# File 'lib/construct.rb', line 35 def self.schema @schema ||= {} end |
Instance Method Details
#==(other) ⇒ Object
49 50 51 52 |
# File 'lib/construct.rb', line 49 def ==(other) other.respond_to? :schema and other.respond_to? :data and @schema == other.schema and @data == other.data end |
#[](key) ⇒ Object
54 55 56 57 58 59 60 61 62 |
# File 'lib/construct.rb', line 54 def [](key) key = key.to_sym if String === key if @data.include? key @data[key] elsif @schema.include? key and @schema[key].include? :default @data[key] = Marshal.load(Marshal.dump(@schema[key][:default])) end end |
#[]=(key, value) ⇒ Object
Assign a value to a key. Constructs accept only symbols as values, and will convert strings to symbols when necessary. They will also implicitly convert Hashes as values into Constructs when possible. Hence you can do:
construct.people = => ‘Awesome’, :joe => ‘suspicious’ construct.people.mary # => ‘Awesome’
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/construct.rb', line 71 def []=(key, value) key = key.to_sym if String === key raise ArgumentError.new('construct only accepts symbols (and strings) as keys.') unless key.is_a? Symbol # Convert suitable hashes into Constructs if value.is_a? Hash if value.keys.all? { |k| k.is_a? String or k.is_a? Symbol } value = Construct.new(value) end end @data[key] = value end |
#clear ⇒ Object
Clears the data in the construct.
88 89 90 |
# File 'lib/construct.rb', line 88 def clear @data.clear end |
#define(key, options = {}) ⇒ Object
Defines a new field in the schema. Fields are :default and :desc.
93 94 95 96 |
# File 'lib/construct.rb', line 93 def define(key, = {}) key = key.to_sym if String === key @schema[key] = end |
#delete(key) ⇒ Object
delete simply removes the value from the data hash, but leaves the schema unchanged. Hence the construct may still respond to include? if the schema defines that field. Use #schema.delete(:key) to remove the key entirely.
102 103 104 105 |
# File 'lib/construct.rb', line 102 def delete(key) key = key.to_sym if String === key @data.delete key end |
#dup ⇒ Object
A deep (not shallow!) clone of this construct.
108 109 110 |
# File 'lib/construct.rb', line 108 def dup Marshal.load(Marshal.dump(self)) end |
#each ⇒ Object
Like enumerable#each. Operates on each key.
113 114 115 116 117 |
# File 'lib/construct.rb', line 113 def each keys.each do |key| yield key, self[key] end end |
#include?(*args) ⇒ Boolean
Returns true if the construct has a value set for, or the schema defines, the key.
121 122 123 |
# File 'lib/construct.rb', line 121 def include?(*args) @data.include?(*args) or (@schema.include?(*args) and @schema[*args].include? :default) end |
#keys ⇒ Object
Returns the keys, both set in the construct and specified in the schema.
126 127 128 |
# File 'lib/construct.rb', line 126 def keys @data.keys | @schema.keys end |
#load(yaml) ⇒ Object
130 131 132 133 134 135 136 |
# File 'lib/construct.rb', line 130 def load(yaml) data = YAML::load(yaml) data.each do |key, value| self[key] = value end end |
#to_hash ⇒ Object
Flattens this construct (recursively) into a hash, merging schema with values. Useful for passing a Construct to a library that checks kind_of?
156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/construct.rb', line 156 def to_hash inject({}) do |hash, pair| value = pair[1] hash[pair[0]] = case value when Construct value.to_hash else value end hash end end |
#to_yaml(opts = {}) ⇒ Object
Dumps the data (not the schema!) of this construct to YAML. Keys are expressed as strings.
This gets a little complicated.
If you define a schema where the default is a Construct
conf.define :sub, :default => Construct
and then try to write to it:
conf.sub.opt = 2
That opt gets stored on the schema sub. Everything works fine… except that when it comes time to serialize there’s now data buried in the schema tree. Therefore, we write out schema objects as well when they are non-empty.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/construct.rb', line 187 def to_yaml(opts = {}) hash = {} @schema.each do |key, value| if value[:default].kind_of? Construct hashed = YAML::load(value[:default].to_yaml) next if hashed.empty? hash[key.to_s] = hashed end end @data.each do |key, value| hash[key.to_s] = value end hash.to_yaml(opts) end |