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:

  • :verbose => true or false
  • 
    
    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

    #options ⇒ Object (readonly)

    Returns the value of attribute options.

    
    
    16
    17
    18
    # File 'lib/caesars/config.rb', line 16
    
    def options
      @options
    end

    #paths ⇒ Object

    Returns the value of attribute paths.

    
    
    15
    16
    17
    # File 'lib/caesars/config.rb', line 15
    
    def paths
      @paths
    end

    #verbose ⇒ Object

    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_init ⇒ Object

    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_paths ⇒ Object

    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

    #keys ⇒ Object

    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

    #postprocess ⇒ Object

    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

    #refresh ⇒ Object

    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 (http://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