Class: Loquacious::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/loquacious/configuration.rb,
lib/loquacious/configuration/help.rb,
lib/loquacious/configuration/iterator.rb

Overview

A Configuration provides a “blank slate” for storing configuration properties along with descriptions and default values. Configurations are accessed by name, and hence, the configuration properties can be retrieved from any location in your code.

Each property has an associated description that can be displayed to the user via the Configuration::Help class. This is the main point of the Loquacious library - tell the user what all yoru configruation properties actually do!

Each configurationp property can also have a default value that is returned if no value has been set for that property. Each property should hae a sensible default - the user should not have to configure every property in order to use a piece of code.

Defined Under Namespace

Classes: DSL, Error, Help, Iterator

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ Configuration

Create a new configuration object and initialize it using an optional block of code.



140
141
142
143
144
145
146
# File 'lib/loquacious/configuration.rb', line 140

def initialize( &block )
  @__desc = Hash.new
  @__values = Hash.new
  @__defaults = Hash.new
  @__defaults_mode = false
  DSL.evaluate(:config => self, &block) if block
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

When invoked, an attribute reader and writer are defined for the method. Any arguments given are used to set the value of the attributes. If a block is given, then the attribute is a nested configuration and the block is evaluated in the context of a new configuration object.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/loquacious/configuration.rb', line 154

def method_missing( method, *args, &block )
  m = method.to_s.delete('=').to_sym

  __eigenclass_eval "def #{m}=( value ) @__values[#{m.inspect}] = value; end", __FILE__, __LINE__
  __eigenclass_eval "def \#{m}( *args, &block )\nvalue = @__values[\#{m.inspect}]\n\nif args.empty? and !block\nreturn value if value.kind_of?(Configuration)\nvalue = @__defaults[\#{m.inspect}] if value.kind_of?(Loquacious::Undefined) and @__defaults.has_key? \#{m.inspect}\nreturn value.respond_to?(:call) ? value.call : value\nend\n\nif block\nv = DSL.evaluate(:defaults_mode => __defaults_mode, &block)\nif value.kind_of?(Configuration)\nvalue.merge! v\nelse\n@__values[\#{m.inspect}] = v\nend\nelse\nv = (1 == args.length ? args.first : args)\nif __defaults_mode\n@__defaults[\#{m.inspect}] = v\nelse\n@__values[\#{m.inspect}] = v\nend\nend\nend\n", __FILE__, __LINE__+1

  __desc[m] = nil unless __desc.has_key? m

  default = ((__defaults_mode or args.empty?) and !block) ? Loquacious::Undefined.new(m.to_s) : nil
  self.__send("#{m}=", default)
  self.__send("#{m}", *args, &block)
end

Instance Attribute Details

#__defaultsObject (readonly)

Accessor for configuration defaults



131
132
133
# File 'lib/loquacious/configuration.rb', line 131

def __defaults
  @__defaults
end

#__defaults_modeObject

Flag to switch the configuration object into defaults mode. This allows default values to be set instead regular values.



135
136
137
# File 'lib/loquacious/configuration.rb', line 135

def __defaults_mode
  @__defaults_mode
end

#__descObject (readonly)

Accessor for the description hash.



125
126
127
# File 'lib/loquacious/configuration.rb', line 125

def __desc
  @__desc
end

#__valuesObject (readonly)

Accessor for configuration values



128
129
130
# File 'lib/loquacious/configuration.rb', line 128

def __values
  @__values
end

Class Method Details

.defaults_for(name, &block) ⇒ Object

call-seq:

Configuration.defaults_for( name ) { block }

Set the default values for the configuration associated with the given name. A block is required by this method.

Default values do not interfere with normal configuration values. If both are defined for a particualr configruation setting, then the regular configuration value will be returned.

Defaults allow the user to define configuration values before the library defaults have been loaded. They prevent library defaults from overriding user settings.



64
65
66
67
68
69
70
71
72
# File 'lib/loquacious/configuration.rb', line 64

def defaults_for( name, &block )
  raise "defaults require a block" if block.nil?

  if @table.has_key? name
    DSL.evaluate(:config => @table[name], :defaults_mode => true, &block)
  else
    @table[name] = DSL.evaluate(:defaults_mode => true, &block)
  end
end

.for(name, &block) ⇒ Object

call-seq:

Configuration.for( name )
Configuration.for( name ) { block }

Returns the configuration associated with the given name. If a block is given, then it will be used to create the configuration.

The same name can be used multiple times with different configuration blocks. Each different block will be used to add to the configuration; i.e. the configurations are additive.



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/loquacious/configuration.rb', line 38

def for( name, &block )
  if block.nil?
    return @table.has_key?(name) ? @table[name] : nil
  end

  if @table.has_key? name
    DSL.evaluate(:config => @table[name], &block)
  else
    @table[name] = DSL.evaluate(&block)
  end
end

.help_for(name, opts = {}) ⇒ Object Also known as: help

call-seq:

Configuration.help_for( name, opts = {} )

Returns a Help instance for the configuration associated with the given name. See the Help#initialize method for the options that can be used with this method.



81
82
83
# File 'lib/loquacious/configuration.rb', line 81

def help_for( name, opts = {} )
  ::Loquacious::Configuration::Help.new(name, opts)
end

.to_hash(config) ⇒ Object

call-seq:

Configuration.to_hash( config )

Recursively convert a configuration object to a hash.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/loquacious/configuration.rb', line 91

def to_hash( config )
  cache = { nil => {} }

  Iterator.new(config).each do |node|
    ary = node.name.split('.')
    name = ary.pop.to_sym
    parent = ary.empty? ? nil : ary.join('.')

    if node.config?
      cache[node.name] = cache[parent][name] = {}
    else
      cache[parent][name] = node.obj
    end
  end

  return cache[nil]
end

Instance Method Details

#[](key) ⇒ Object

Provides hash accessor notation for configuration values.

config = Configuration.for('app') {
           port  1234
         }
config[:port]  #=> 1234
config.port    #=> 1234


257
258
259
# File 'lib/loquacious/configuration.rb', line 257

def []( key )
  self.__send(key)
end

#[]=(key, value) ⇒ Object

Provides hash accessor notation for configuration values.

config = Configuration.for('app')
config[:port] = 8808
config.port            #=> 8808


267
268
269
# File 'lib/loquacious/configuration.rb', line 267

def []=( key, value )
  self.__send(key, value)
end

#__eigenclass_eval(code, file, line) ⇒ Object

Evaluate the given code string in the context of this object’s eigenclass (singleton class).



206
207
208
209
210
211
# File 'lib/loquacious/configuration.rb', line 206

def __eigenclass_eval( code, file, line )
  ec = class << self; self; end
  ec.module_eval code, file, line
rescue StandardError
  Kernel.raise Error, "cannot evalutate this code:\n#{code}\n"
end

#__send(symbol, *args, &block) ⇒ Object

Only invoke public methods on the Configuration instances.



195
196
197
198
199
200
201
# File 'lib/loquacious/configuration.rb', line 195

def __send( symbol, *args, &block )
  if self.respond_to? symbol
    self.__send__(symbol, *args, &block)
  else
    self.method_missing(symbol, *args, &block)
  end
end

#merge!(other) ⇒ Object

Merge the contents of the other configuration into this one. Values from the other configuratin will overwite values in this configuration.

This function is recursive. Nested configurations will be merged with their counterparts in the other configuration.



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/loquacious/configuration.rb', line 220

def merge!( other )
  return self if other.equal? self
  Kernel.raise Error, "can only merge another Configuration" unless other.kind_of?(Configuration)

  other_values = other.__values
  other_defaults = other.__defaults

  other.__desc.each do |key,desc|
    value = @__values[key]
    other_value = other_values[key]

    if value.kind_of?(Configuration) and other_value.kind_of?(Configuration)
      value.merge! other_value
    elsif !other_value.kind_of?(Loquacious::Undefined)
      self.__send__(key, other_value)
    end

    if other_defaults.has_key? key
      @__defaults[key] = other_defaults[key]
    end

    if desc
      __desc[key] = desc
    end
  end

  self
end

#to_hashObject

Recursively convert the configuration object to a hash.



273
274
275
# File 'lib/loquacious/configuration.rb', line 273

def to_hash
  ::Loquacious::Configuration.to_hash(self)
end