caesars 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -1,6 +1,13 @@
1
1
  CAESARS -- CHANGES
2
2
 
3
3
 
4
+ #### 0.7.1 (2009-06-08) ###############################
5
+
6
+ * FIXED: Updated file manifest in gemspec
7
+ * FIXED: Correct mistake in rdocs for Caesars::Config.new
8
+ * CHANGE: Caesars::** classes moved into separate files.
9
+
10
+
4
11
  #### 0.7.0 (2009-06-03) ###############################
5
12
 
6
13
  * CHANGE: Post-processing for Caesars::Config classes now occurs
data/caesars.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "caesars"
3
3
  s.rubyforge_project = "caesars"
4
- s.version = "0.7.0"
4
+ s.version = "0.7.1"
5
5
  s.specification_version = 1 if s.respond_to? :specification_version=
6
6
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
7
7
 
@@ -22,6 +22,9 @@
22
22
  bin/party.conf
23
23
  caesars.gemspec
24
24
  lib/caesars.rb
25
+ lib/caesars/config.rb
26
+ lib/caesars/exceptions.rb
27
+ lib/caesars/hash.rb
25
28
  lib/caesars/orderedhash.rb
26
29
  )
27
30
 
data/lib/caesars.rb CHANGED
@@ -8,9 +8,12 @@
8
8
  # See bin/example
9
9
  #
10
10
  class Caesars
11
+
11
12
  require 'caesars/orderedhash'
12
-
13
- VERSION = "0.7.0"
13
+ require 'caesars/exceptions'
14
+ require 'caesars/config'
15
+
16
+ VERSION = "0.7.1"
14
17
  @@debug = false
15
18
  @@chilled = {}
16
19
  @@forced_array = {}
@@ -18,7 +21,9 @@ class Caesars
18
21
  @@known_symbols = []
19
22
  @@known_symbols_by_glass = {}
20
23
  HASH_TYPE = (RUBY_VERSION =~ /1.9/) ? ::Hash : Caesars::OrderedHash
21
-
24
+
25
+ require 'caesars/hash'
26
+
22
27
  def Caesars.enable_debug; @@debug = true; end
23
28
  def Caesars.disable_debug; @@debug = false; end
24
29
  def Caesars.debug?; @@debug; end
@@ -59,52 +64,9 @@ class Caesars
59
64
  @@known_symbols_by_glass[g].member?(s.to_sym)
60
65
  end
61
66
 
62
- # A subclass of ::Hash that provides method names for hash parameters.
63
- # It's like a lightweight OpenStruct.
64
- # ch = Caesars::Hash[:tabasco => :lots!]
65
- # puts ch.tabasco # => lots!
66
- #
67
- class Hash < HASH_TYPE
68
- def method_missing(meth)
69
- self[meth] if self.has_key?(meth)
70
- end
71
-
72
- # Returns a clone of itself and all children cast as ::Hash objects
73
- def to_hash(hash=self)
74
- return hash unless hash.is_a?(Caesars::Hash) # nothing to do
75
- target = (Caesars::HASH_TYPE)[dup]
76
- hash.keys.each do |key|
77
- if hash[key].is_a? Caesars::Hash
78
- target[key] = hash[key].to_hash
79
- next
80
- elsif hash[key].is_a? Array
81
- target[key] = hash[key].collect { |h| to_hash(h) }
82
- next
83
- end
84
- target[key] = hash[key]
85
- end
86
- target
87
- end
88
-
89
- end
90
-
91
67
  # An instance of Caesars::Hash which contains the data specified by your DSL
92
68
  attr_accessor :caesars_properties
93
69
 
94
- class Error < RuntimeError
95
- attr_accessor :backtrace
96
- def initialize(obj=nil); @obj = obj; end
97
- def message; "#{self.class}: #{@obj}"; end
98
- end
99
- class SyntaxError < Caesars::Error
100
- def message
101
- msg = "Syntax error in #{@obj}"
102
- bt = @backtrace
103
- msg << " in " << bt.first.scan(/\`(.+?)'/).flatten.first if bt
104
- msg
105
- end
106
- end
107
-
108
70
  def initialize(name=nil)
109
71
  @caesars_name = name if name
110
72
  @caesars_properties = Caesars::Hash.new
@@ -576,191 +538,4 @@ class Caesars
576
538
  end
577
539
 
578
540
 
579
- # A helper for loading a DSL from a config file.
580
- #
581
- # Usage:
582
- #
583
- # class Staff < Caesars; end;
584
- # class StaffConfig < Caesars::Config
585
- # dsl Staff::DSL
586
- # end
587
- # @config = StaffConfig.new(:path => '/path/2/staff_dsl.rb')
588
- # p @config.staff # => <Staff:0x7ea450 ... >
589
- #
590
- class Caesars::Config
591
- attr_accessor :paths
592
- attr_reader :options
593
- attr_reader :verbose
594
-
595
- @@glasses = []
596
-
597
- # Used by postprocess to tell refresh to reload all configs.
598
- class ForceRefresh < RuntimeError
599
- # The list of config types that need to be refreshed. This is currently
600
- # for informational-purposes only. It does not affect which files/config
601
- # types are refreshed. See Caesars::Config::ForcedRefresh
602
- attr_reader :glasses
603
- def initialize(*glasses); @glasses = glasses; end
604
- def message; "Force refresh of: #{@glasses.join(',')}"; end
605
- end
606
-
607
- # +args+ is a last of config file paths to load into this instance.
608
- # If the last argument is a hash, it's assumed to be a list of
609
- # options. The available options are:
610
- #
611
- # <li>:verbose => true or false</li>
612
- #
613
- def initialize(*args)
614
- # We store the options hash b/c we reapply them when we refresh.
615
- @options = args.last.kind_of?(Hash) ? args.pop : {}
616
- @paths = args.empty? ? [] : args
617
- @options = {}
618
- @forced_refreshes = 0
619
- refresh
620
- end
621
-
622
- def verbose=(enable)
623
- @verbose = enable == true
624
- @options[:verbose] = @verbose
625
- end
626
-
627
- # Reset all config instance variables to nil.
628
- def caesars_init
629
- # Remove instance variables used to populate DSL data
630
- keys.each { |confname| instance_variable_set("@#{confname}", nil) }
631
- # Re-apply options
632
- @options.each_pair do |n,v|
633
- self.send("#{n}=", v) if respond_to?("#{n}=")
634
- end
635
- check_paths # make sure files exist
636
- end
637
-
638
- # This method is a stub. It gets called by refresh after each
639
- # config file has be loaded. You can use it to run file specific
640
- # processing on the configuration before it's used elsewhere.
641
- def postprocess
642
- end
643
-
644
- # Clear all current configuration (sets all config instance
645
- # variables to nil) and reload all config files in +@paths+.
646
- # After each path is loaded, Caesars::Config.postprocess is
647
- # called. If a ForceRefresh exception is raise, refresh is
648
- # run again from the start. This is useful in the case
649
- # where one DSL can affect the parsing of another. Note that
650
- # refresh only clears the instance variables, the class vars
651
- # for each of the DSLs are not affected so all calls to
652
- # +forced_array+, +forced_hash+, +chill+ and +forced_ignore+
653
- # are unaffected.
654
- #
655
- # Rudy has an example of forced refreshing in action. See
656
- # the files (http://github.com/solutious/rudy):
657
- #
658
- # * +lib/rudy/config.rb+
659
- # * +lib/rudy/config/objects.rb+.
660
- #
661
- def refresh
662
- caesars_init # Delete all current configuration
663
- @@glasses.each { |glass| extend glass }
664
-
665
- begin
666
- current_path = nil # used in error messages
667
- @paths.each do |path|
668
- current_path = path
669
- puts "Loading config from #{path}" if @verbose || Caesars.debug?
670
- dsl = File.read path
671
- # eval so the DSL code can be executed in this namespace.
672
- eval dsl, binding, __FILE__, __LINE__
673
- end
674
-
675
- # Execute Caesars::Config.postprocesses after all files are loaded.
676
- postprocess # Can raise ForceRefresh
677
-
678
- rescue Caesars::Config::ForceRefresh => ex
679
- @forced_refreshes += 1
680
- if @forced_refreshes > 3
681
- STDERR.puts "Too many forced refreshes (#{@forced_refreshes})"
682
- exit 9
683
- end
684
- STDERR.puts ex.message if @verbose || Caesars.debug?
685
- refresh
686
-
687
- #rescue Caesars::Error => ex
688
- # STDERR.puts ex.message
689
- # STDERR.puts ex.backtrace if Caesars.debug?
690
- rescue ArgumentError, SyntaxError => ex
691
- newex = Caesars::SyntaxError.new(current_path)
692
- newex.backtrace = ex.backtrace
693
- raise newex
694
- end
695
- end
696
-
697
- # Checks all values of +@paths+, raises an exception for nil
698
- # values and file paths that don't exist.
699
- def check_paths
700
- @paths.each do |path|
701
- raise "You provided a nil value" unless path
702
- raise "Config file #{path} does not exist!" unless File.exists?(path)
703
- end
704
- end
705
-
706
- # Do any of the known DSLs have config data?
707
- def empty?
708
- keys.each do |obj|
709
- return false if self.respond_to?(obj.to_sym)
710
- end
711
- true
712
- end
713
-
714
- # Specify a DSL class (+glass+) to include in this config.
715
- #
716
- # class CoolDrink < Caesars::Config
717
- # dsl CoolDrink::Flavours::DSL
718
- # end
719
- #
720
- def self.dsl(glass)
721
- @@glasses << glass
722
- end
723
-
724
- # Provide a hash-like interface for Config classes.
725
- # +name+ is the name of a DSL config.
726
- #
727
- # class CoolDrink < Caesars::Config
728
- # dsl CoolDrink::Flavours::DSL
729
- # end
730
- #
731
- # cd = CoolDrink.new('/path/2/config')
732
- # cd[:flavours] # => {}
733
- #
734
- def [](name)
735
- self.send(name) if respond_to?(name)
736
- end
737
-
738
- # Returns the list of known DSL config names.
739
- # class CoolDrink < Caesars::Config
740
- # dsl CoolDrink::Flavours::DSL
741
- # end
742
- #
743
- # cd = CoolDrink.new('/path/2/config')
744
- # cd.keys # => [:flavours]
745
- #
746
- def keys
747
- @@glasses.collect { |glass| glass.methname }
748
- end
749
-
750
- # Is +name+ a known configuration type?
751
- #
752
- # class CoolDrink < Caesars::Config
753
- # dsl CoolDrink::Flavours::DSL
754
- # end
755
- #
756
- # cd = CoolDrink.new('/path/2/config')
757
- # cd.has_key?(:taste) # => false
758
- # cd.has_key?(:flavours) # => true
759
- #
760
- def has_key?(name)
761
- respond_to?(name)
762
- end
763
- end
764
-
765
-
766
541
 
@@ -0,0 +1,190 @@
1
+
2
+ # A helper for loading a DSL from a config file.
3
+ #
4
+ # Usage:
5
+ #
6
+ # class Staff < Caesars; end;
7
+ # class StaffConfig < Caesars::Config
8
+ # dsl Staff::DSL
9
+ # end
10
+ # @config = StaffConfig.new('/path/2/staff_dsl.rb')
11
+ # p @config.staff # => <Staff:0x7ea450 ... >
12
+ #
13
+ class Caesars
14
+ class Config
15
+ attr_accessor :paths
16
+ attr_reader :options
17
+ attr_reader :verbose
18
+
19
+ @@glasses = []
20
+
21
+ # Used by postprocess to tell refresh to reload all configs.
22
+ class ForceRefresh < RuntimeError
23
+ # The list of config types that need to be refreshed. This is currently
24
+ # for informational-purposes only. It does not affect which files/config
25
+ # types are refreshed. See Caesars::Config::ForcedRefresh
26
+ attr_reader :glasses
27
+ def initialize(*glasses); @glasses = glasses; end
28
+ def message; "Force refresh of: #{@glasses.join(',')}"; end
29
+ end
30
+
31
+ # +args+ is a last of config file paths to load into this instance.
32
+ # If the last argument is a hash, it's assumed to be a list of
33
+ # options. The available options are:
34
+ #
35
+ # <li>:verbose => true or false</li>
36
+ #
37
+ def initialize(*args)
38
+ # We store the options hash b/c we reapply them when we refresh.
39
+ @options = args.last.kind_of?(Hash) ? args.pop : {}
40
+ @paths = args.empty? ? [] : args
41
+ @options = {}
42
+ @forced_refreshes = 0
43
+ refresh
44
+ end
45
+
46
+ def verbose=(enable)
47
+ @verbose = enable == true
48
+ @options[:verbose] = @verbose
49
+ end
50
+
51
+ # Reset all config instance variables to nil.
52
+ def caesars_init
53
+ # Remove instance variables used to populate DSL data
54
+ keys.each { |confname| instance_variable_set("@#{confname}", nil) }
55
+ # Re-apply options
56
+ @options.each_pair do |n,v|
57
+ self.send("#{n}=", v) if respond_to?("#{n}=")
58
+ end
59
+ check_paths # make sure files exist
60
+ end
61
+
62
+ # This method is a stub. It gets called by refresh after each
63
+ # config file has be loaded. You can use it to run file specific
64
+ # processing on the configuration before it's used elsewhere.
65
+ def postprocess
66
+ end
67
+
68
+ # Clear all current configuration (sets all config instance
69
+ # variables to nil) and reload all config files in +@paths+.
70
+ # After each path is loaded, Caesars::Config.postprocess is
71
+ # called. If a ForceRefresh exception is raise, refresh is
72
+ # run again from the start. This is useful in the case
73
+ # where one DSL can affect the parsing of another. Note that
74
+ # refresh only clears the instance variables, the class vars
75
+ # for each of the DSLs are not affected so all calls to
76
+ # +forced_array+, +forced_hash+, +chill+ and +forced_ignore+
77
+ # are unaffected.
78
+ #
79
+ # Rudy has an example of forced refreshing in action. See
80
+ # the files (http://github.com/solutious/rudy):
81
+ #
82
+ # * +lib/rudy/config.rb+
83
+ # * +lib/rudy/config/objects.rb+.
84
+ #
85
+ def refresh
86
+ caesars_init # Delete all current configuration
87
+ @@glasses.each { |glass| extend glass }
88
+
89
+ begin
90
+ current_path = nil # used in error messages
91
+ @paths.each do |path|
92
+ current_path = path
93
+ puts "Loading config from #{path}" if @verbose || Caesars.debug?
94
+ dsl = File.read path
95
+ # eval so the DSL code can be executed in this namespace.
96
+ eval dsl, binding, __FILE__, __LINE__
97
+ end
98
+
99
+ # Execute Caesars::Config.postprocesses after all files are loaded.
100
+ postprocess # Can raise ForceRefresh
101
+
102
+ rescue Caesars::Config::ForceRefresh => ex
103
+ @forced_refreshes += 1
104
+ if @forced_refreshes > 3
105
+ STDERR.puts "Too many forced refreshes (#{@forced_refreshes})"
106
+ exit 9
107
+ end
108
+ STDERR.puts ex.message if @verbose || Caesars.debug?
109
+ refresh
110
+
111
+ #rescue Caesars::Error => ex
112
+ # STDERR.puts ex.message
113
+ # STDERR.puts ex.backtrace if Caesars.debug?
114
+ rescue ArgumentError, SyntaxError => ex
115
+ newex = Caesars::SyntaxError.new(current_path)
116
+ newex.backtrace = ex.backtrace
117
+ raise newex
118
+ end
119
+ end
120
+
121
+ # Checks all values of +@paths+, raises an exception for nil
122
+ # values and file paths that don't exist.
123
+ def check_paths
124
+ @paths.each do |path|
125
+ raise "You provided a nil value" unless path
126
+ raise "Config file #{path} does not exist!" unless File.exists?(path)
127
+ end
128
+ end
129
+
130
+ # Do any of the known DSLs have config data?
131
+ def empty?
132
+ keys.each do |obj|
133
+ return false if self.respond_to?(obj.to_sym)
134
+ end
135
+ true
136
+ end
137
+
138
+ # Specify a DSL class (+glass+) to include in this config.
139
+ #
140
+ # class CoolDrink < Caesars::Config
141
+ # dsl CoolDrink::Flavours::DSL
142
+ # end
143
+ #
144
+ def self.dsl(glass)
145
+ @@glasses << glass
146
+ end
147
+
148
+ # Provide a hash-like interface for Config classes.
149
+ # +name+ is the name of a DSL config.
150
+ #
151
+ # class CoolDrink < Caesars::Config
152
+ # dsl CoolDrink::Flavours::DSL
153
+ # end
154
+ #
155
+ # cd = CoolDrink.new('/path/2/config')
156
+ # cd[:flavours] # => {}
157
+ #
158
+ def [](name)
159
+ self.send(name) if respond_to?(name)
160
+ end
161
+
162
+ # Returns the list of known DSL config names.
163
+ # class CoolDrink < Caesars::Config
164
+ # dsl CoolDrink::Flavours::DSL
165
+ # end
166
+ #
167
+ # cd = CoolDrink.new('/path/2/config')
168
+ # cd.keys # => [:flavours]
169
+ #
170
+ def keys
171
+ @@glasses.collect { |glass| glass.methname }
172
+ end
173
+
174
+ # Is +name+ a known configuration type?
175
+ #
176
+ # class CoolDrink < Caesars::Config
177
+ # dsl CoolDrink::Flavours::DSL
178
+ # end
179
+ #
180
+ # cd = CoolDrink.new('/path/2/config')
181
+ # cd.has_key?(:taste) # => false
182
+ # cd.has_key?(:flavours) # => true
183
+ #
184
+ def has_key?(name)
185
+ respond_to?(name)
186
+ end
187
+
188
+ end
189
+ end
190
+
@@ -0,0 +1,17 @@
1
+
2
+
3
+ class Caesars
4
+ class Error < RuntimeError
5
+ attr_accessor :backtrace
6
+ def initialize(obj=nil); @obj = obj; end
7
+ def message; "#{self.class}: #{@obj}"; end
8
+ end
9
+ class SyntaxError < Caesars::Error
10
+ def message
11
+ msg = "Syntax error in #{@obj}"
12
+ bt = @backtrace
13
+ msg << " in " << bt.first.scan(/\`(.+?)'/).flatten.first if bt
14
+ msg
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+
2
+ # A subclass of ::Hash that provides method names for hash parameters.
3
+ # It's like a lightweight OpenStruct.
4
+ # ch = Caesars::Hash[:tabasco => :lots!]
5
+ # puts ch.tabasco # => lots!
6
+ #
7
+ class Caesars
8
+ class Hash < HASH_TYPE
9
+ def method_missing(meth)
10
+ self[meth] if self.has_key?(meth)
11
+ end
12
+
13
+ # Returns a clone of itself and all children cast as ::Hash objects
14
+ def to_hash(hash=self)
15
+ return hash unless hash.is_a?(Caesars::Hash) # nothing to do
16
+ target = (Caesars::HASH_TYPE)[dup]
17
+ hash.keys.each do |key|
18
+ if hash[key].is_a? Caesars::Hash
19
+ target[key] = hash[key].to_hash
20
+ next
21
+ elsif hash[key].is_a? Array
22
+ target[key] = hash[key].collect { |h| to_hash(h) }
23
+ next
24
+ end
25
+ target[key] = hash[key]
26
+ end
27
+ target
28
+ end
29
+
30
+ end
31
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caesars
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-03 00:00:00 -04:00
12
+ date: 2009-06-08 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,6 +33,9 @@ files:
33
33
  - bin/party.conf
34
34
  - caesars.gemspec
35
35
  - lib/caesars.rb
36
+ - lib/caesars/config.rb
37
+ - lib/caesars/exceptions.rb
38
+ - lib/caesars/hash.rb
36
39
  - lib/caesars/orderedhash.rb
37
40
  has_rdoc: true
38
41
  homepage: http://github.com/delano/caesars