Class: Caesars::Config

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

Overview

A helper for loading a DSL from a config file.

Usage:

class Staff < Caesars; end;
class StaffConfig < Caesars::Config
  dsl Staff::DSL
end
@config = StaffConfig.new(:path => '/path/2/staff_dsl.rb')
p @config.staff    # => <Staff:0x7ea450 ... >

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>



613
614
615
616
617
618
619
620
# File 'lib/caesars.rb', line 613

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.



592
593
594
# File 'lib/caesars.rb', line 592

def options
  @options
end

#pathsObject

Returns the value of attribute paths.



591
592
593
# File 'lib/caesars.rb', line 591

def paths
  @paths
end

#verboseObject

Returns the value of attribute verbose.



593
594
595
# File 'lib/caesars.rb', line 593

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


720
721
722
# File 'lib/caesars.rb', line 720

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]     # => {}


734
735
736
# File 'lib/caesars.rb', line 734

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

#caesars_initObject

Reset all config instance variables to nil.



628
629
630
631
632
633
634
635
636
# File 'lib/caesars.rb', line 628

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.



699
700
701
702
703
704
# File 'lib/caesars.rb', line 699

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)


707
708
709
710
711
712
# File 'lib/caesars.rb', line 707

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)


760
761
762
# File 'lib/caesars.rb', line 760

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]


746
747
748
# File 'lib/caesars.rb', line 746

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.



641
642
# File 'lib/caesars.rb', line 641

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.



661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'lib/caesars.rb', line 661

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, __FILE__, __LINE__
    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