Class: Caesars::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/caesars/config.rb

Defined Under Namespace

Classes: ForceRefresh

Constant Summary collapse

@@glasses =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Config

args is a last of config file paths to load into this instance. If the last argument is a hash, it’s assumed to be a list of options. The available options are:

<li>:verbose => true or false</li>



37
38
39
40
41
42
43
44
# File 'lib/caesars/config.rb', line 37

def initialize(*args)
  # We store the options hash b/c we reapply them when we refresh.
  @options = args.last.kind_of?(Hash) ? args.pop : {}
  @paths = args.empty? ? [] : args
  @options = {}
  @forced_refreshes = 0
  refresh
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



16
17
18
# File 'lib/caesars/config.rb', line 16

def options
  @options
end

#pathsObject

Returns the value of attribute paths.



15
16
17
# File 'lib/caesars/config.rb', line 15

def paths
  @paths
end

#verboseObject

Returns the value of attribute verbose.



17
18
19
# File 'lib/caesars/config.rb', line 17

def verbose
  @verbose
end

Class Method Details

.dsl(glass) ⇒ Object

Specify a DSL class (glass) to include in this config.

class CoolDrink < Caesars::Config
  dsl CoolDrink::Flavours::DSL
end


144
145
146
# File 'lib/caesars/config.rb', line 144

def self.dsl(glass)
  @@glasses << glass
end

Instance Method Details

#[](name) ⇒ Object

Provide a hash-like interface for Config classes. name is the name of a DSL config.

class CoolDrink < Caesars::Config
  dsl CoolDrink::Flavours::DSL
end

cd = CoolDrink.new('/path/2/config')
cd[:flavours]     # => {}


158
159
160
# File 'lib/caesars/config.rb', line 158

def [](name)
  self.send(name) if respond_to?(name)
end

#caesars_initObject

Reset all config instance variables to nil.



52
53
54
55
56
57
58
59
60
# File 'lib/caesars/config.rb', line 52

def caesars_init
  # Remove instance variables used to populate DSL data
  keys.each { |confname| instance_variable_set("@#{confname}", nil) }
  # Re-apply options
  @options.each_pair do |n,v|
    self.send("#{n}=", v) if respond_to?("#{n}=")
  end
  check_paths     # make sure files exist
end

#check_pathsObject

Checks all values of @paths, raises an exception for nil values and file paths that don’t exist.



123
124
125
126
127
128
# File 'lib/caesars/config.rb', line 123

def check_paths
  @paths.each do |path|
    raise "You provided a nil value" unless path
    raise "Config file #{path} does not exist!" unless File.exists?(path)
  end
end

#empty?Boolean

Do any of the known DSLs have config data?

Returns:

  • (Boolean)


131
132
133
134
135
136
# File 'lib/caesars/config.rb', line 131

def empty?
  keys.each do |obj|
    return false if self.respond_to?(obj.to_sym)
  end
  true
end

#has_key?(name) ⇒ Boolean

Is name a known configuration type?

class CoolDrink < Caesars::Config
  dsl CoolDrink::Flavours::DSL
end

cd = CoolDrink.new('/path/2/config')
cd.has_key?(:taste)        # => false
cd.has_key?(:flavours)     # => true

Returns:

  • (Boolean)


184
185
186
# File 'lib/caesars/config.rb', line 184

def has_key?(name)
  respond_to?(name)
end

#keysObject

Returns the list of known DSL config names.

class CoolDrink < Caesars::Config
  dsl CoolDrink::Flavours::DSL
end

cd = CoolDrink.new('/path/2/config')
cd.keys           # => [:flavours]


170
171
172
# File 'lib/caesars/config.rb', line 170

def keys
  @@glasses.collect { |glass| glass.methname }
end

#postprocessObject

This method is a stub. It gets called by refresh after each config file has be loaded. You can use it to run file specific processing on the configuration before it’s used elsewhere.



65
66
# File 'lib/caesars/config.rb', line 65

def postprocess
end

#refreshObject

Clear all current configuration (sets all config instance variables to nil) and reload all config files in @paths. After each path is loaded, Caesars::Config.postprocess is called. If a ForceRefresh exception is raise, refresh is run again from the start. This is useful in the case where one DSL can affect the parsing of another. Note that refresh only clears the instance variables, the class vars for each of the DSLs are not affected so all calls to forced_array, forced_hash, chill and forced_ignore are unaffected.

Rudy has an example of forced refreshing in action. See the files (github.com/solutious/rudy):

  • lib/rudy/config.rb

  • lib/rudy/config/objects.rb.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/caesars/config.rb', line 85

def refresh
  caesars_init    # Delete all current configuration
  @@glasses.each { |glass| extend glass }
  
  begin
    current_path = nil  # used in error messages
    @paths.each do |path|
      current_path = path
      puts "Loading config from #{path}" if @verbose || Caesars.debug?
      dsl = File.read path
      # eval so the DSL code can be executed in this namespace.
      eval dsl, binding, path
    end

    # Execute Caesars::Config.postprocesses after all files are loaded. 
    postprocess # Can raise ForceRefresh

  rescue Caesars::Config::ForceRefresh => ex
    @forced_refreshes += 1
    if @forced_refreshes > 3
      STDERR.puts "Too many forced refreshes (#{@forced_refreshes})"
      exit 9
    end
    STDERR.puts ex.message if @verbose || Caesars.debug?
    refresh

  #rescue Caesars::Error => ex
  #  STDERR.puts ex.message
  #  STDERR.puts ex.backtrace if Caesars.debug?
  rescue ArgumentError, SyntaxError => ex
    newex = Caesars::SyntaxError.new(current_path)
    newex.backtrace = ex.backtrace
    raise newex
  end
end