Skip to content

Commit

Permalink
Added the new configuration class for handling configuration values. …
Browse files Browse the repository at this point in the history
…Includes passing specs. Dependent classes need to be updated, including a new defined bootup process.
  • Loading branch information
mtodd committed Jun 17, 2008
1 parent 78a19ed commit 29a179e
Show file tree
Hide file tree
Showing 7 changed files with 726 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG
@@ -1,3 +1,6 @@
== 0.5.1 WIP
* major refectoring of the configuration object/interface

== 0.5.0 2008-05-29
* major refactor, completely incompatible with 0.4.0 applications
* new application-centric structure and design [#13 resolved]
Expand Down
27 changes: 6 additions & 21 deletions lib/halcyon.rb
Expand Up @@ -11,24 +11,26 @@
# Halcyon.config #=> {:allow_from => :all, :logging => {...}, ...}
# Halcyon.paths #=> {:config => Halcyon.root/'config', ...}
# Halcyon.logger #=> #<Logger>
# Halcyon.version #=> "0.5.0"
# Halcyon.version #=> "0.5.1"
#
module Halcyon

VERSION = [0,5,1] unless defined?(Halcyon::VERSION)

autoload :Application, 'halcyon/application'
autoload :Client, 'halcyon/client'
autoload :Config, 'halcyon/config'
autoload :Controller, 'halcyon/controller'
autoload :Exceptions, 'halcyon/exceptions'
autoload :Logging, 'halcyon/logging'
autoload :Runner, 'halcyon/runner'

include Halcyon::Config::Helpers

class << self

attr_accessor :app
attr_accessor :logger
attr_accessor :config
attr_accessor :paths

def version
VERSION.join('.')
Expand All @@ -37,23 +39,11 @@ def version
# The root directory of the current application.
#
# Returns String:root_directory
#
def root
self.config[:root] || Dir.pwd rescue Dir.pwd
end

def configurable(attribute)
eval <<-"end;"
def #{attribute.to_s}
Halcyon.config[:#{attribute.to_s}]
end
def #{attribute.to_s}=(value)
value = value.to_mash if value.is_a?(Hash)
Halcyon.config[:#{attribute.to_s}] = value
end
end;
end
alias_method :configurable_attr, :configurable

# Tests for Windows platform (to compensate for numerous Windows-specific
# bugs and oddities.)
#
Expand All @@ -73,11 +63,6 @@ def linux?

end

# Creates <tt>Halcyon.db</tt> to alias <tt>Halcyon.config[:db]</tt>.
# Also creates the complementary assignment method, <tt>Halcyon.db=</tt>
# that aliases <tt>Halcyon.config[:db]=</tt>.
configurable_attr :db

end

# Include the klass#logger and klass.logger accessor methods into Object.
Expand Down
226 changes: 226 additions & 0 deletions lib/halcyon/config.rb
@@ -0,0 +1,226 @@
module Halcyon

# Application configuration map.
#
class Config

attr_accessor :config

autoload :Helpers, 'halcyon/config/helpers'
autoload :Paths, 'halcyon/config/paths'
autoload :File, 'halcyon/config/file'

# Creates an empty configuration hash (Mash) and sets up the configuration
# to whatever the settings are provided, merging over the defaults.
#
# Examples:
#
# Halcyon::Config.new(:environment => :development)
#
# OR
#
# Halcyon::Config.new(:allow_from => :all)
#
# OR
#
# Halcyon::Config.new
#
# OR
#
# Halcyon::Config.new do |c|
# c[:foo] = true
# end
#
def initialize(config={}, &block)
env = config.delete(:environment)
self.config = Mash.new
self.setup(self.defaults(env).merge(config))
self.use(&block) if block_given?
end

# Sets the configuration up with the values given.
#
def configure(config={})
config.each do |(key, val)|
self.config[key] = val
end
end

# Sets up the configuration by storing the settings provided (via param or
# via block).
#
# Usage:
#
# Halcyon.config.setup do |c|
# c[:foo] = true
# end
#
# or
#
# Halcyon.config.setup(:foo => true)
#
def setup(config={})
if block_given?
yield(self.config.dup)
end
# merge new settings
self.configure(config)
end

# Yields and returns the configuration.
#
# Examples:
#
# Halcyon.config.use do |c|
# c[:foo] = true
# end
#
def use
if block_given?
yield self.config
end
self.config
end

# Allows retrieval of single key config values and setting single config
# values.
#
# Examples:
#
# Halcyon.config.app #=> 'AppName'
# Halcyon.config[:app] #=> 'AppName'
#
def method_missing(method, *args)
if method.to_s[-1,1] == '='
self.put(method.to_s.tr('=',''), *args)
else
self.get(method)
end
end

# Get the configuration value associated with the key.
#
# Examples:
#
# Halcyon.config.get(:app) #=> 'AppName'
#
def get(key)
self.config[key]
end

# Put the configuration value associated with the key or setup with a hash.
#
# Examples:
#
# Halcyon.config.put(:app, 'AppName')
#
# OR
#
# Halcyon.config.put(:app => 'AppName')
#
def put(key_or_config_hash, value = nil)
if value.nil? and key_or_config_hash.is_a?(Hash)
self.configure(key_or_config_hash)
else
self.config[key_or_config_hash] = value
end
end

# Removes the configuration value from the hash.
#
# Examples:
#
# Halcyon.config.delete(:app) #=> 'AppName'
#
def delete(key)
self.config.delete(key)
end

# Alias for the <tt>get</tt> method.
#
# Examples:
#
# Halcyon.config[:foo] #=> true
#
def [](key)
self.get(key)
end

# Alias for the <tt>put</tt> method. (Restricted to the key/value pair.)
#
# Examples:
#
# Halcyon.config[:foo] = true
#
def []=(key, value)
self.put(key, value)
end

# Returns the configuration rendered as YAML.
#
def to_yaml
require 'yaml'
self.config.to_hash.to_yaml
end

# Returns the configuration as a hash.
#
def to_hash
self.config.to_hash
end

# Default configuration values.
#
# Defaults to the configuration for <tt>:development</tt>.
#
def defaults(env = nil)
base = {
:allow_from => 'all',
:logging => {
:type => 'Logger',
:level => 'debug'
},
:root => nil,
:app => nil,
:environment => nil,
:paths => Paths.new
}
case (env || :development)
when :development
base.merge({
:environment => :development
})
when :test
base.merge({
:environment => :test,
:logging => {
:type => 'Logger',
:level => 'warn',
:file => 'log/test.log'
}
})
when :console
base.merge({
:environment => :console
})
when :production
base.merge({
:environment => :production,
:logging => {
:type => 'Logger',
:level => 'warn',
:file => 'log/production.log'
}
})
end
end

def inspect
attrs = ""
self.config.keys.each {|key| attrs << " #{key}=#{self.config[key].inspect}"}
"#<Halcyon::Config#{attrs}>"
end

end

end
87 changes: 87 additions & 0 deletions lib/halcyon/config/file.rb
@@ -0,0 +1,87 @@
module Halcyon
class Config

# Class to assist with loading configuration from a file.
#
# Examples:
#
# Halcyon::Config::File.new(file_name_or_path).to_hash #=> {...}
#
class File

attr_accessor :path
attr_accessor :content

# Creates a profile with the default paths.
#
def initialize(file)
if ::File.exist?(file)
self.path = file
elsif ::File.exist?(Halcyon.paths.for(:config)/file)
self.path = Halcyon.paths.for(:config)/file
else
raise ArgumentError.new("Could not find #{self.path} (it does not exist).")
end
self.content = ::File.read(self.path)
end

# Returns the loaded configuration file's contents parsed by the
# marshal format loader (defaulting to YAML, also providing JSON).
#
# Examples:
#
# p = Halcyon.paths.for(:config)/'config.yml'
# c = Halcyon::Config::File.new(p)
# c.to_hash #=> the contents of the config file parsed as YAML
# c.to_hash(:from_json) #=> same as above only parsed as JSON
# # parsing errors will happen if you try to use the wrong marshal
# # load method
#
def to_hash(from = :from_yaml)
case from
when :from_yaml
require 'yaml'
YAML.load(self.content)
when :from_json
JSON.parse(self.content)
end
end

def inspect
"#<Halcyon::Config::File #{self.path}>"
end

class << self

# Provides a convenient way to load the configuration and return the
# appropriate hash contents.
#
def load(path)
file = File.new(path)
case path
when /\.(yaml|yml)/
file.to_hash
when /\.(json)/
file.to_hash(:from_json)
end
end

# Loads the configuration file and parses it's contents as YAML.
# This is a shortcut method.
#
def load_from_yaml(path)
self.new(path).to_hash
end

# Loads the configuration file and parses it's contents as JSON.
# This is a shortcut method.
#
def load_from_json(path)
self.new(path).to_hash(:from_json)
end

end

end
end
end

0 comments on commit 29a179e

Please sign in to comment.