Class: Loquacious::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/loquacious/configuration.rb,
lib/loquacious/configuration/help.rb,
lib/loquacious/configuration/iterator.rb,
lib/loquacious/configuration/help/string_presenter.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.



162
163
164
165
166
167
168
169
170
# File 'lib/loquacious/configuration.rb', line 162

def initialize( &block )
  @__desc = Hash.new
  @__values = Hash.new
  @__defaults = Hash.new
  @__transforms = Hash.new
  @__defaults_mode = false
  @__parent = nil
  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.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/loquacious/configuration.rb', line 178

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 <<-CODE, __FILE__, __LINE__+1
    def #{m}( *args, &block )
      value = @__values[#{m.inspect}]

      if args.empty? and !block
        return value if value.kind_of?(Configuration)
        value = @__defaults[#{m.inspect}] if value.kind_of?(Loquacious::Undefined) and @__defaults.has_key? #{m.inspect}
        if Loquacious.env_config
          env_name = Loquacious::Utility.env_var_name(__method__, self)
          if ENV.has_key? env_name
            if @__transforms.has_key? __method__
              return @__transforms[__method__].call ENV[env_name]
            else
              return ENV[env_name]
            end
          end
        end
        return value.respond_to?(:call) ? value.call : value
      end

      if block
        v = DSL.evaluate(:parent_config => self, :config_name => __method__.to_s, :defaults_mode => __defaults_mode, &block)
        if value.kind_of?(Configuration)
          value.merge! v
        else
          @__values[#{m.inspect}] = v
        end
      else
        v = (1 == args.length ? args.first : args)
        if __defaults_mode
          @__defaults[#{m.inspect}] = v
        else
          @__values[#{m.inspect}] = v
        end
      end
    end
  CODE

  __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



144
145
146
# File 'lib/loquacious/configuration.rb', line 144

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.



148
149
150
# File 'lib/loquacious/configuration.rb', line 148

def __defaults_mode
  @__defaults_mode
end

#__descObject (readonly)

Accessor for the description hash.



138
139
140
# File 'lib/loquacious/configuration.rb', line 138

def __desc
  @__desc
end

#__nameObject

Name for this configuration object



151
152
153
# File 'lib/loquacious/configuration.rb', line 151

def __name
  @__name
end

#__parentObject

Name of the parent configuration object, used for traversal



154
155
156
# File 'lib/loquacious/configuration.rb', line 154

def __parent
  @__parent
end

#__transformsObject

Hash holding the transform procs



157
158
159
# File 'lib/loquacious/configuration.rb', line 157

def __transforms
  @__transforms
end

#__valuesObject (readonly)

Accessor for configuration values



141
142
143
# File 'lib/loquacious/configuration.rb', line 141

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(:config_name => name, :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_name => name, :config => @table[name], &block)
  else
    @table[name] = DSL.evaluate(:config_name => name, &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

.parent_list(config) ⇒ Object

Returns a string array with the parent tree for the config



111
112
113
114
115
116
117
118
119
# File 'lib/loquacious/configuration.rb', line 111

def parent_list(config)
  current_parent = config.__parent
  parents = []
  until current_parent.nil? do
    parents.unshift current_parent.__name
    current_parent = current_parent.__parent
  end
  parents
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


291
292
293
# File 'lib/loquacious/configuration.rb', line 291

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


301
302
303
# File 'lib/loquacious/configuration.rb', line 301

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).



240
241
242
243
244
245
# File 'lib/loquacious/configuration.rb', line 240

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.



229
230
231
232
233
234
235
# File 'lib/loquacious/configuration.rb', line 229

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.



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/loquacious/configuration.rb', line 254

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

#parent_listObject

Returns an array of the parents in descending order



312
313
314
# File 'lib/loquacious/configuration.rb', line 312

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

#to_hashObject

Recursively convert the configuration object to a hash.



307
308
309
# File 'lib/loquacious/configuration.rb', line 307

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