configurability 1.0.10 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data.tar.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,11 @@
1
+ == v1.1.0 [2012-04-25] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ Add a 'defaults' API that allows defaults to be gathered from any
4
+ object with configurability and merged into a hash keyed by the
5
+ object's config_key. This hash can be used to generate an initial
6
+ unified config file for all configurable parts of a given system.
7
+
8
+
1
9
  == v1.0.10 [2012-03-13] Michael Granger <ged@FaerieMUD.org>
2
10
 
3
11
  - Fix log level message.
data/Manifest.txt CHANGED
@@ -10,7 +10,7 @@ lib/configurability.rb
10
10
  lib/configurability/behavior.rb
11
11
  lib/configurability/config.rb
12
12
  lib/configurability/deferredconfig.rb
13
- lib/configurability/logformatter.rb
13
+ lib/configurability/logging.rb
14
14
  spec/configurability/config_spec.rb
15
15
  spec/configurability/deferredconfig_spec.rb
16
16
  spec/configurability_spec.rb
data/README.rdoc CHANGED
@@ -1,14 +1,19 @@
1
1
  = Configurability
2
2
 
3
- * http://bitbucket.org/ged/configurability
3
+ home :: https://bitbucket.org/ged/configurability
4
+ code :: https://bitbucket.org/ged/configurability
5
+ docs :: http://deveiate.org/code/configurability
6
+ github :: https://github.com/ged/configurability
4
7
 
5
8
 
6
9
  == Description
7
10
 
8
- Configurability is a mixin that allows you to add configurability to one or
9
- more objects or classes. You can assign them each a subsection of the
10
- configuration, and then later, when the configuration is loaded, the
11
- configuration is split up and sent to the objects that will use it.
11
+ Configurability is a unified, unintrusive, assume-nothing configuration system
12
+ for Ruby. It lets you keep the configuration for multiple objects in a single
13
+ config file, load the file when it's convenient for you, and distribute the
14
+ configuration when you're ready, sending it everywhere it needs to go with a
15
+ single action.
16
+
12
17
 
13
18
 
14
19
  == Installation
@@ -93,6 +98,9 @@ as a Symbol:
93
98
 
94
99
  === Changing How an Object Is Configured
95
100
 
101
+ [:FIXME:] Explain the 'at least once' configuration call, and how to handle
102
+ being called with 'nil'.
103
+
96
104
  You can also change what happens when an object is configured by implementing
97
105
  a `#configure` method that takes the config section as an argument:
98
106
 
@@ -216,19 +224,27 @@ then dump it to a YAML string:
216
224
 
217
225
  config.dump
218
226
  # => "--- \ndatabase: \n development: \n adapter: sqlite3\n
219
- database: db/dev.db\n pool: 5\n timeout: 5000\n testing: \n
220
- adapter: mysql\n database: t_fixedassets\n pool: 2\n timeout:
221
- 5000\n production: \n adapter: postgres\n database:
222
- fixedassets\n pool: 25\n timeout: 50\nldap: \n uri:
223
- ldap://ldap.acme.com/dc=acme,dc=com\n bind_dn:
224
- cn=web,dc=acme,dc=com\n bind_pass: Mut@ge.Mix@ge\nbranding: \n
225
- header: \"#333\"\n title: \"#dedede\"\n anchor: \"#9fc8d4\"\n"
227
+ database: db/dev.db\n pool: 5\n timeout: 5000\n testing: \n
228
+ adapter: mysql\n database: t_fixedassets\n pool: 2\n timeout:
229
+ 5000\n production: \n adapter: postgres\n database:
230
+ fixedassets\n pool: 25\n timeout: 50\nldap: \n uri:
231
+ ldap://ldap.acme.com/dc=acme,dc=com\n bind_dn:
232
+ cn=web,dc=acme,dc=com\n bind_pass: Mut@ge.Mix@ge\nbranding: \n
233
+ header: \"#333\"\n title: \"#dedede\"\n anchor: \"#9fc8d4\"\n"
226
234
 
227
235
  or write it back to the file it was loaded from:
228
236
 
229
237
  config.write
230
238
 
231
239
 
240
+ == Configuration Defaults
241
+
242
+ Configurability also supports an API for generating a new config file with
243
+ defaults for all objects with Configurability.
244
+
245
+ [:FIXME:] Finish up the documentation
246
+
247
+
232
248
  == Development
233
249
 
234
250
  You can submit bug reports, suggestions, clone it with Mercurial, and
data/Rakefile CHANGED
@@ -10,6 +10,7 @@ end
10
10
  Hoe.plugin :mercurial
11
11
  Hoe.plugin :yard
12
12
  Hoe.plugin :signing
13
+ Hoe.plugin :deveiate
13
14
 
14
15
  Hoe.plugins.delete :rubyforge
15
16
 
@@ -25,6 +26,7 @@ hoespec = Hoe.spec 'configurability' do
25
26
  self.dependency 'simplecov', '~> 0.3', :developer
26
27
 
27
28
  self.spec_extras[:licenses] = ["BSD"]
29
+ self.spec_extras[:rdoc_options] = ['-f', 'fivefish', '-t', 'Configurability Toolkit']
28
30
  self.require_ruby_version( '>= 1.8.7' )
29
31
 
30
32
  self.hg_sign_tags = true if self.respond_to?( :hg_sign_tags= )
@@ -11,14 +11,19 @@ require 'yaml'
11
11
  module Configurability
12
12
 
13
13
  # Library version constant
14
- VERSION = '1.0.10'
14
+ VERSION = '1.1.0'
15
15
 
16
16
  # Version-control revision constant
17
- REVISION = %q$Revision: 0dcd8dcebc87 $
17
+ REVISION = %q$Revision: e56100a012e3 $
18
+
19
+
20
+ require 'configurability/logging'
21
+ extend Configurability::Logging
18
22
 
19
- require 'configurability/logformatter'
20
23
  require 'configurability/deferredconfig'
21
24
 
25
+ autoload :Config, 'configurability/config'
26
+
22
27
 
23
28
  ### The objects that have had Configurability added to them
24
29
  @configurable_objects = []
@@ -31,16 +36,6 @@ module Configurability
31
36
  ### are the config section it was called with
32
37
  @configured = Hash.new( false )
33
38
 
34
- ### Logging
35
- @default_logger = Logger.new( $stderr )
36
- @default_logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
37
-
38
- @default_log_formatter = Configurability::LogFormatter.new( @default_logger )
39
- @default_logger.formatter = @default_log_formatter
40
-
41
- @logger = @default_logger
42
-
43
-
44
39
  class << self
45
40
 
46
41
  # the Array of objects that have had Configurability added to them
@@ -52,17 +47,15 @@ module Configurability
52
47
  # the hash of configure methods => config sections which have already been installed
53
48
  attr_reader :configured
54
49
 
55
- # the log formatter that will be used when the logging subsystem is
56
- # reset
57
- attr_accessor :default_log_formatter
50
+ end
58
51
 
59
- # the logger that will be used when the logging subsystem is reset
60
- attr_accessor :default_logger
61
52
 
62
- # the logger that's currently in effect
63
- attr_accessor :logger
64
- alias_method :log, :logger
65
- alias_method :log=, :logger=
53
+ ### Get the library version. If +include_buildnum+ is true, the version string will
54
+ ### include the VCS rev ID.
55
+ def self::version_string( include_buildnum=false )
56
+ vstring = "%s %s" % [ self.name, VERSION ]
57
+ vstring << " (build %s)" % [ REVISION[/: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
58
+ return vstring
66
59
  end
67
60
 
68
61
 
@@ -128,14 +121,6 @@ module Configurability
128
121
  end
129
122
 
130
123
 
131
- ### Reset the global logger object to the default
132
- def self::reset_logger
133
- self.logger = self.default_logger
134
- self.logger.level = Logger::WARN
135
- self.logger.formatter = self.default_log_formatter
136
- end
137
-
138
-
139
124
  ### Install the appropriate section of the +config+ into the given +object+.
140
125
  def self::install_config( config, object )
141
126
  section = object.config_key.to_sym
@@ -155,8 +140,7 @@ module Configurability
155
140
  section = nil
156
141
  end
157
142
  else
158
- self.log.info " don't know how to get the %p section of the config from %p" %
159
- [ section, config ]
143
+ self.log.info " no %p section in %p; configuring with nil" % [ section, config ]
160
144
  section = nil
161
145
  end
162
146
 
@@ -174,10 +158,42 @@ module Configurability
174
158
  end
175
159
 
176
160
 
161
+ ### Gather defaults from objects with Configurability in the given +collection+
162
+ ### object. Objects that wish to add a section to the defaults should implement
163
+ ### a #defaults method in the same scope as #configure that returns the Hash of
164
+ ### default, or set one of the constants in the default implementation of
165
+ ### #defaults. The hash for each object will be merged into the +collection+
166
+ ### via #merge!.
167
+ def self::gather_defaults( collection={} )
168
+ self.configurable_objects.each do |obj|
169
+ next unless obj.respond_to?( :defaults )
170
+ unless subhash = obj.defaults
171
+ Configurability.log.warn "No defaults for %p; skipping" % [ obj ]
172
+ next
173
+ end
174
+ section = obj.config_key.to_sym
175
+
176
+ collection.merge!( section => subhash )
177
+ end
178
+
179
+ return collection
180
+ end
181
+
182
+
183
+ ### Gather the default configuration in a Configurability::Config object and return it.
184
+ def self::default_config
185
+ return self.gather_defaults( Configurability::Config.new )
186
+ end
187
+
188
+
177
189
  #############################################################
178
190
  ### A P P E N D E D M E T H O D S
179
191
  #############################################################
180
192
 
193
+ #
194
+ # :section: Configuration API
195
+ #
196
+
181
197
  ### Get (and optionally set) the +config_key+ (a Symbol).
182
198
  def config_key( sym=nil )
183
199
  @config_key = sym unless sym.nil?
@@ -198,5 +214,31 @@ module Configurability
198
214
  end
199
215
 
200
216
 
217
+ #
218
+ # :section: Configuration Defaults API
219
+ #
220
+
221
+ ### The default implementation of the method called by ::gather_defaults when
222
+ ### gathering configuration defaults. This method expects either a
223
+ ### +DEFAULT_CONFIG+ or a +CONFIG_DEFAULTS+ constant to contain the configuration
224
+ ### defaults, and will just return +nil+ if neither exists.
225
+ def defaults
226
+
227
+ return nil unless respond_to?( :const_defined? )
228
+
229
+ Configurability.log.debug "Looking for defaults in %p's constants." % [ self ]
230
+ if self.const_defined?( :DEFAULT_CONFIG )
231
+ Configurability.log.debug " found DEFAULT_CONFIG"
232
+ return self.const_get( :DEFAULT_CONFIG ).dup
233
+ elsif self.const_defined?( :CONFIG_DEFAULTS )
234
+ Configurability.log.debug " found CONFIG_DEFAULTS"
235
+ return self.const_get( :CONFIG_DEFAULTS ).dup
236
+ else
237
+ Configurability.log.debug " no default constants."
238
+ return nil
239
+ end
240
+ end
241
+
242
+
201
243
  end # module Configurability
202
244
 
@@ -140,9 +140,17 @@ class Configurability::Config
140
140
  ### Write the configuration object using the specified name and any
141
141
  ### additional +args+.
142
142
  def write( path=@path, *args )
143
+ unless path.is_a?( String ) || path.is_a?( Pathname )
144
+ args.unshift( path )
145
+ path = @path
146
+ end
147
+
143
148
  raise ArgumentError,
144
149
  "No name associated with this config." unless path
145
- path.open( File::WRONLY|File::CREAT|File::TRUNC ) do |ofh|
150
+
151
+ self.log.info "Writing config to %s with args: %p" % [ path, args ]
152
+ path = Pathname( path )
153
+ path.open( File::WRONLY|File::CREAT|File::TRUNC, *args ) do |ofh|
146
154
  ofh.print( self.dump )
147
155
  end
148
156
  end
@@ -254,6 +262,12 @@ class Configurability::Config
254
262
  end
255
263
 
256
264
 
265
+ ### Delegate logging to the module's Logger.
266
+ def log
267
+ Configurability.logger
268
+ end
269
+
270
+
257
271
  #######
258
272
  private
259
273
  #######
@@ -0,0 +1,300 @@
1
+ # -*- ruby -*-
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # encoding: utf-8
4
+
5
+ require 'logger'
6
+ require 'date'
7
+
8
+ require 'configurability' unless defined?( Configurability )
9
+
10
+
11
+ # A mixin that provides a top-level logging subsystem based on Logger.
12
+ module Configurability::Logging
13
+
14
+ ### Logging
15
+ # Log levels
16
+ LOG_LEVELS = {
17
+ 'debug' => Logger::DEBUG,
18
+ 'info' => Logger::INFO,
19
+ 'warn' => Logger::WARN,
20
+ 'error' => Logger::ERROR,
21
+ 'fatal' => Logger::FATAL,
22
+ }.freeze
23
+ LOG_LEVEL_NAMES = LOG_LEVELS.invert.freeze
24
+
25
+
26
+ ### Inclusion hook
27
+ def self::extended( mod )
28
+ super
29
+
30
+ class << mod
31
+ # the log formatter that will be used when the logging subsystem is reset
32
+ attr_accessor :default_log_formatter
33
+
34
+ # the logger that will be used when the logging subsystem is reset
35
+ attr_accessor :default_logger
36
+
37
+ # the logger that's currently in effect
38
+ attr_accessor :logger
39
+ alias_method :log, :logger
40
+ alias_method :log=, :logger=
41
+ end
42
+
43
+ mod.default_logger = mod.logger = Logger.new( $stderr )
44
+ mod.default_logger.level = case
45
+ when $DEBUG then Logger::DEBUG
46
+ when $VERBOSE then Logger::INFO
47
+ else Logger::WARN end
48
+ mod.default_log_formatter = Configurability::Logging::Formatter.new( mod.default_logger )
49
+ end
50
+
51
+
52
+ ### Reset the global logger object to the default
53
+ def reset_logger
54
+ self.logger = self.default_logger
55
+ self.logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
56
+ self.logger.formatter = self.default_log_formatter
57
+ end
58
+
59
+
60
+ ### Returns +true+ if the global logger has not been set to something other than
61
+ ### the default one.
62
+ def using_default_logger?
63
+ return self.logger == self.default_logger
64
+ end
65
+
66
+
67
+ # A alternate formatter for Logger instances.
68
+ class Formatter < Logger::Formatter
69
+
70
+ # The format to output unless debugging is turned on
71
+ DEFAULT_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"
72
+
73
+ # The format to output if debugging is turned on
74
+ DEFAULT_DEBUG_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"
75
+
76
+
77
+ ### Initialize the formatter with a reference to the logger so it can check for log level.
78
+ def initialize( logger, format=DEFAULT_FORMAT, debug=DEFAULT_DEBUG_FORMAT ) # :notnew:
79
+ @logger = logger
80
+ @format = format
81
+ @debug_format = debug
82
+
83
+ super()
84
+ end
85
+
86
+ ######
87
+ public
88
+ ######
89
+
90
+ # The Logger object associated with the formatter
91
+ attr_accessor :logger
92
+
93
+ # The logging format string
94
+ attr_accessor :format
95
+
96
+ # The logging format string that's used when outputting in debug mode
97
+ attr_accessor :debug_format
98
+
99
+
100
+ ### Log using either the DEBUG_FORMAT if the associated logger is at ::DEBUG level or
101
+ ### using FORMAT if it's anything less verbose.
102
+ def call( severity, time, progname, msg )
103
+ args = [
104
+ time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
105
+ time.usec, # %2$d
106
+ Process.pid, # %3$d
107
+ Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
108
+ severity, # %5$s
109
+ progname, # %6$s
110
+ msg # %7$s
111
+ ]
112
+
113
+ if @logger.level == Logger::DEBUG
114
+ return self.debug_format % args
115
+ else
116
+ return self.format % args
117
+ end
118
+ end
119
+ end # class Formatter
120
+
121
+
122
+ # A ANSI-colorized formatter for Logger instances.
123
+ class ColorFormatter < Logger::Formatter
124
+
125
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
126
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
127
+ ANSI_ATTRIBUTES = {
128
+ 'clear' => 0,
129
+ 'reset' => 0,
130
+ 'bold' => 1,
131
+ 'dark' => 2,
132
+ 'underline' => 4,
133
+ 'underscore' => 4,
134
+ 'blink' => 5,
135
+ 'reverse' => 7,
136
+ 'concealed' => 8,
137
+
138
+ 'black' => 30, 'on_black' => 40,
139
+ 'red' => 31, 'on_red' => 41,
140
+ 'green' => 32, 'on_green' => 42,
141
+ 'yellow' => 33, 'on_yellow' => 43,
142
+ 'blue' => 34, 'on_blue' => 44,
143
+ 'magenta' => 35, 'on_magenta' => 45,
144
+ 'cyan' => 36, 'on_cyan' => 46,
145
+ 'white' => 37, 'on_white' => 47
146
+ }
147
+
148
+
149
+ ### Create a string that contains the ANSI codes specified and return it
150
+ def self::ansi_code( *attributes )
151
+ attributes.flatten!
152
+ attributes.collect! {|at| at.to_s }
153
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
154
+ attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
155
+
156
+ if attributes.empty?
157
+ return ''
158
+ else
159
+ return "\e[%sm" % attributes
160
+ end
161
+ end
162
+
163
+
164
+ ### Colorize the given +string+ with the specified +attributes+ and
165
+ ### return it, handling line-endings, color reset, etc.
166
+ def self::colorize( *args )
167
+ string = ''
168
+
169
+ if block_given?
170
+ string = yield
171
+ else
172
+ string = args.shift
173
+ end
174
+
175
+ ending = string[/(\s)$/] || ''
176
+ string = string.rstrip
177
+
178
+ return self.ansi_code( args.flatten ) + string + self.ansi_code( 'reset' ) + ending
179
+ end
180
+
181
+
182
+ # Color settings
183
+ LEVEL_FORMATS = {
184
+ :debug => colorize( :bold, :black ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"},
185
+ :info => colorize( :normal ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
186
+ :warn => colorize( :bold, :yellow ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
187
+ :error => colorize( :red ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
188
+ :fatal => colorize( :bold, :red, :on_white ) {"[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"},
189
+ }
190
+
191
+
192
+ ### Initialize the formatter with a reference to the logger so it can check for log level.
193
+ def initialize( logger, settings={} ) # :notnew:
194
+ settings = LEVEL_FORMATS.merge( settings )
195
+
196
+ @logger = logger
197
+ @settings = settings
198
+
199
+ super()
200
+ end
201
+
202
+ ######
203
+ public
204
+ ######
205
+
206
+ # The Logger object associated with the formatter
207
+ attr_accessor :logger
208
+
209
+ # The formats, by level
210
+ attr_accessor :settings
211
+
212
+
213
+ ### Log using the format associated with the severity
214
+ def call( severity, time, progname, msg )
215
+ args = [
216
+ time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
217
+ time.usec, # %2$d
218
+ Process.pid, # %3$d
219
+ Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
220
+ severity, # %5$s
221
+ progname, # %6$s
222
+ msg # %7$s
223
+ ]
224
+
225
+ return self.settings[ severity.downcase.to_sym ] % args
226
+ end
227
+
228
+ end # class Formatter
229
+
230
+
231
+ # An alternate formatter for Logger instances that outputs +div+ HTML
232
+ # fragments.
233
+ class HtmlFormatter < Logger::Formatter
234
+
235
+ # The default HTML fragment that'll be used as the template for each log message.
236
+ HTML_LOG_FORMAT = %q{
237
+ <div class="log-message %5$s">
238
+ <span class="log-time">%1$s.%2$06d</span>
239
+ [
240
+ <span class="log-pid">%3$d</span>
241
+ /
242
+ <span class="log-tid">%4$s</span>
243
+ ]
244
+ <span class="log-level">%5$s</span>
245
+ :
246
+ <span class="log-name">%6$s</span>
247
+ <span class="log-message-text">%7$s</span>
248
+ </div>
249
+ }
250
+
251
+ ### Override the logging formats with ones that generate HTML fragments
252
+ def initialize( logger, format=HTML_LOG_FORMAT ) # :notnew:
253
+ @logger = logger
254
+ @format = format
255
+ super()
256
+ end
257
+
258
+
259
+ ######
260
+ public
261
+ ######
262
+
263
+ # The HTML fragment that will be used as a format() string for the log
264
+ attr_accessor :format
265
+
266
+
267
+ ### Return a log message composed out of the arguments formatted using the
268
+ ### formatter's format string
269
+ def call( severity, time, progname, msg )
270
+ args = [
271
+ time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
272
+ time.usec, # %2$d
273
+ Process.pid, # %3$d
274
+ Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
275
+ severity.downcase, # %5$s
276
+ progname, # %6$s
277
+ escape_html( msg ).gsub(/\n/, '<br />') # %7$s
278
+ ]
279
+
280
+ return self.format % args
281
+ end
282
+
283
+
284
+ #######
285
+ private
286
+ #######
287
+
288
+ ### Escape any HTML special characters in +string+.
289
+ def escape_html( string )
290
+ return string.
291
+ gsub( '&', '&amp;' ).
292
+ gsub( '<', '&lt;' ).
293
+ gsub( '>', '&gt;' )
294
+ end
295
+
296
+ end # class HtmlFormatter
297
+
298
+
299
+ end # module Configurability
300
+
@@ -10,7 +10,6 @@ BEGIN {
10
10
  $LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
11
11
  }
12
12
 
13
- require 'tempfile'
14
13
  require 'logger'
15
14
  require 'fileutils'
16
15
  require 'rspec'
@@ -48,6 +47,11 @@ describe Configurability::Config do
48
47
  setup_logging( :fatal )
49
48
  end
50
49
 
50
+ after( :each ) do
51
+ Configurability.configurable_objects.clear
52
+ Configurability.reset
53
+ end
54
+
51
55
  after( :all ) do
52
56
  reset_logging()
53
57
  end
@@ -135,7 +139,7 @@ describe Configurability::Config do
135
139
 
136
140
  context "created with in-memory YAML source" do
137
141
 
138
- before(:each) do
142
+ before( :each ) do
139
143
  @config = Configurability::Config.new( TEST_CONFIG )
140
144
  end
141
145
 
@@ -206,7 +210,7 @@ describe Configurability::Config do
206
210
 
207
211
  # saving if changed since loaded
208
212
  context " whose internal values have been changed since loaded" do
209
- before(:each) do
213
+ before( :each ) do
210
214
  @config = Configurability::Config.new( TEST_CONFIG )
211
215
  @config.section.subsection.anothersection = 11451
212
216
  end
@@ -226,42 +230,50 @@ describe Configurability::Config do
226
230
 
227
231
  # loading from a file
228
232
  context " loaded from a file" do
229
- before(:all) do
230
- @tmpfile = Tempfile.new( 'test.conf', '.' )
231
- @tmpfile.print( TEST_CONFIG )
232
- @tmpfile.close
233
+ before( :all ) do
234
+ filename = Dir::Tmpname.make_tmpname( './test', '.conf' )
235
+ @tmpfile = Pathname( filename )
236
+ @tmpfile.open( 'w', 0644 ) {|io| io.print(TEST_CONFIG) }
233
237
  end
234
238
 
235
- after(:all) do
236
- @tmpfile.delete
239
+ after( :all ) do
240
+ @tmpfile.unlink
237
241
  end
238
242
 
239
-
240
- before(:each) do
241
- @config = Configurability::Config.load( @tmpfile.path )
243
+ before( :each ) do
244
+ @config = Configurability::Config.load( @tmpfile.to_s )
242
245
  end
243
246
 
244
247
 
245
248
  ### Specifications
246
249
  it "remembers which file it was loaded from" do
247
- @config.path.should == Pathname( @tmpfile.path ).expand_path
250
+ @config.path.should == @tmpfile.expand_path
248
251
  end
249
252
 
250
253
  it "writes itself back to the same file by default" do
251
254
  @config.port = 114411
252
255
  @config.write
253
- otherconfig = Configurability::Config.load( @tmpfile.path )
256
+ otherconfig = Configurability::Config.load( @tmpfile.to_s )
254
257
 
255
258
  otherconfig.port.should == 114411
256
259
  end
257
260
 
261
+ it "can be written to a different file" do
262
+ path = Dir::Tmpname.make_tmpname( './another-', '.config' )
263
+
264
+ @config.write( path )
265
+ File.read( path ).should =~ /section:\n subsection/
266
+
267
+ File.unlink( path )
268
+ end
269
+
258
270
  it "includes the name of the file in its inspect output" do
259
- @config.inspect.should include( File.basename(@tmpfile.path) )
271
+ @config.inspect.should include( File.basename(@tmpfile.to_s) )
260
272
  end
261
273
 
262
274
  it "yields itself if a block is given at load-time" do
263
275
  yielded_self = nil
264
- config = Configurability::Config.load( @tmpfile.path ) do
276
+ config = Configurability::Config.load( @tmpfile.to_s ) do
265
277
  yielded_self = self
266
278
  end
267
279
  yielded_self.should equal( config )
@@ -270,7 +282,7 @@ describe Configurability::Config do
270
282
  it "passes itself as the block argument if a block of arity 1 is given at load-time" do
271
283
  arg_self = nil
272
284
  yielded_self = nil
273
- config = Configurability::Config.load( @tmpfile.path ) do |arg|
285
+ config = Configurability::Config.load( @tmpfile.to_s ) do |arg|
274
286
  yielded_self = self
275
287
  arg_self = arg
276
288
  end
@@ -288,23 +300,23 @@ describe Configurability::Config do
288
300
 
289
301
  # reload if file changes
290
302
  context " whose file changes after loading" do
291
- before(:all) do
292
- @tmpfile = Tempfile.new( 'test.conf', '.' )
293
- @tmpfile.print( TEST_CONFIG )
294
- @tmpfile.close
303
+ before( :all ) do
304
+ filename = Dir::Tmpname.make_tmpname( './test', '.conf' )
305
+ @tmpfile = Pathname( filename )
306
+ @tmpfile.open( 'w', 0644 ) {|io| io.print(TEST_CONFIG) }
295
307
  end
296
308
 
297
- after(:all) do
298
- @tmpfile.delete
309
+ after( :all ) do
310
+ @tmpfile.unlink
299
311
  end
300
312
 
301
313
 
302
- before(:each) do
314
+ before( :each ) do
303
315
  old_date = Time.now - 3600
304
- File.utime( old_date, old_date, @tmpfile.path )
305
- @config = Configurability::Config.load( @tmpfile.path )
316
+ File.utime( old_date, old_date, @tmpfile.to_s )
317
+ @config = Configurability::Config.load( @tmpfile.to_s )
306
318
  now = Time.now + 10
307
- File.utime( now, now, @tmpfile.path )
319
+ File.utime( now, now, @tmpfile.to_s )
308
320
  end
309
321
 
310
322
 
@@ -324,7 +336,7 @@ describe Configurability::Config do
324
336
  end
325
337
 
326
338
  it "reapplies its defaults when reloading" do
327
- config = Configurability::Config.load( @tmpfile.path, :defaultskey => 8 )
339
+ config = Configurability::Config.load( @tmpfile.to_s, :defaultskey => 8 )
328
340
  config.reload
329
341
  config.defaultskey.should == 8
330
342
  end
@@ -333,7 +345,7 @@ describe Configurability::Config do
333
345
 
334
346
  # merging
335
347
  context " created by merging two other configs" do
336
- before(:each) do
348
+ before( :each ) do
337
349
  @config1 = Configurability::Config.new
338
350
  @config2 = Configurability::Config.new( TEST_CONFIG )
339
351
  @merged = @config1.merge( @config2 )
@@ -36,7 +36,7 @@ describe Configurability::DeferredConfig do
36
36
  end
37
37
 
38
38
  it "calls Configurability.install_config with itself when a 'configure' method is defined" do
39
- config = double( "config object", :testing => :testing_config )
39
+ config = { :testing => :testing_config }
40
40
  Configurability.configure_objects( config )
41
41
 
42
42
  a_class = Class.new do
@@ -287,6 +287,79 @@ describe Configurability do
287
287
 
288
288
  end
289
289
 
290
+
291
+ describe "defaults hash" do
292
+
293
+ it "can generate a Hash of defaults for all objects with Configurability" do
294
+ Configurability.gather_defaults.should be_a( Hash )
295
+ end
296
+
297
+ it "fetches defaults from a CONFIG_DEFAULTS constant if the object defines one" do
298
+ klass = Class.new do
299
+ extend Configurability
300
+ config_key :testconfig
301
+ self::CONFIG_DEFAULTS = { :one => 1, :types => {:one => true} }
302
+ Configurability.log.debug "Defaults: %p" % [ self.defaults ]
303
+ end
304
+
305
+ Configurability.gather_defaults.should include( :testconfig )
306
+ Configurability.gather_defaults[:testconfig].should == klass.const_get( :CONFIG_DEFAULTS )
307
+ Configurability.gather_defaults[:testconfig].should_not be( klass.const_get(:CONFIG_DEFAULTS) )
308
+ end
309
+
310
+ it "fetches defaults from a DEFAULT_CONFIG constant if the object defines one" do
311
+ klass = Class.new do
312
+ extend Configurability
313
+ config_key :testconfig
314
+ self::DEFAULT_CONFIG = { :two => 2, :types => {:two => true} }
315
+ end
316
+
317
+ Configurability.gather_defaults.should include( :testconfig )
318
+ Configurability.gather_defaults[:testconfig].should == klass.const_get( :DEFAULT_CONFIG )
319
+ Configurability.gather_defaults[:testconfig].should_not be( klass.const_get(:DEFAULT_CONFIG) )
320
+ end
321
+
322
+ it "fetches defaults from a #defaults method if the object implements one" do
323
+ klass = Class.new do
324
+ extend Configurability
325
+ config_key :otherconfig
326
+ def self::defaults; { :other => true }; end
327
+ end
328
+
329
+ Configurability.gather_defaults.should include( :otherconfig )
330
+ Configurability.gather_defaults[:otherconfig].should == klass.defaults
331
+ Configurability.gather_defaults[:otherconfig].should_not be( klass.defaults )
332
+ end
333
+
334
+ it "can return a Configurability::Config object with defaults, too" do
335
+ klass1 = Class.new do
336
+ extend Configurability
337
+ config_key :testconfig
338
+ self::CONFIG_DEFAULTS = { :one => 1, :types => {:one => true} }
339
+ end
340
+ klass2 = Class.new do
341
+ extend Configurability
342
+ config_key :testconfig
343
+ self::DEFAULT_CONFIG = { :two => 2, :types => {:two => true} }
344
+ end
345
+ klass3 = Class.new do
346
+ extend Configurability
347
+ config_key :otherconfig
348
+ def self::defaults; { :other => true }; end
349
+ end
350
+
351
+ config = Configurability.default_config
352
+
353
+ config.should be_a( Configurability::Config )
354
+ config.testconfig.one.should == 1
355
+ config.testconfig.two.should == 2
356
+ config.testconfig.types.one.should be_true()
357
+ config.testconfig.types.two.should be_true()
358
+ config.otherconfig.other.should be_true()
359
+ end
360
+
361
+ end
362
+
290
363
  end
291
364
 
292
365
  # vim: set nosta noet ts=4 sw=4:
data/spec/lib/helpers.rb CHANGED
@@ -142,6 +142,10 @@ end
142
142
  RSpec.configure do |config|
143
143
  config.mock_with( :rspec )
144
144
  config.include( Configurability::SpecHelpers )
145
+ config.treat_symbols_as_metadata_keys_with_true_values = true
146
+
147
+ config.filter_run_excluding :only_ruby_19 if RUBY_VERSION < '1.9.2'
148
+
145
149
  end
146
150
 
147
151
  # vim: set nosta noet ts=4 sw=4:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: configurability
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -36,22 +36,27 @@ cert_chain:
36
36
  YUhDS0xaZFNLai9SSHVUT3QrZ2JsUmV4OEZBaDhOZUEKY21saFhlNDZwWk5K
37
37
  Z1dLYnhaYWg4NWpJang5NWhSOHZPSStOQU01aUg5a09xSzEzRHJ4YWNUS1Bo
38
38
  cWo1UGp3RgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
39
- date: 2012-03-13 00:00:00.000000000 Z
39
+ date: 2012-04-26 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: hoe-mercurial
43
- requirement: &70327439150940 !ruby/object:Gem::Requirement
43
+ requirement: !ruby/object:Gem::Requirement
44
44
  none: false
45
45
  requirements:
46
46
  - - ~>
47
47
  - !ruby/object:Gem::Version
48
- version: 1.3.1
48
+ version: 1.4.0
49
49
  type: :development
50
50
  prerelease: false
51
- version_requirements: *70327439150940
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 1.4.0
52
57
  - !ruby/object:Gem::Dependency
53
58
  name: hoe-highline
54
- requirement: &70327439150420 !ruby/object:Gem::Requirement
59
+ requirement: !ruby/object:Gem::Requirement
55
60
  none: false
56
61
  requirements:
57
62
  - - ~>
@@ -59,10 +64,31 @@ dependencies:
59
64
  version: 0.0.1
60
65
  type: :development
61
66
  prerelease: false
62
- version_requirements: *70327439150420
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ~>
71
+ - !ruby/object:Gem::Version
72
+ version: 0.0.1
73
+ - !ruby/object:Gem::Dependency
74
+ name: rdoc
75
+ requirement: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ version: '3.10'
81
+ type: :development
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: '3.10'
63
89
  - !ruby/object:Gem::Dependency
64
90
  name: rspec
65
- requirement: &70327439149940 !ruby/object:Gem::Requirement
91
+ requirement: !ruby/object:Gem::Requirement
66
92
  none: false
67
93
  requirements:
68
94
  - - ~>
@@ -70,10 +96,15 @@ dependencies:
70
96
  version: '2.4'
71
97
  type: :development
72
98
  prerelease: false
73
- version_requirements: *70327439149940
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ~>
103
+ - !ruby/object:Gem::Version
104
+ version: '2.4'
74
105
  - !ruby/object:Gem::Dependency
75
106
  name: simplecov
76
- requirement: &70327439149500 !ruby/object:Gem::Requirement
107
+ requirement: !ruby/object:Gem::Requirement
77
108
  none: false
78
109
  requirements:
79
110
  - - ~>
@@ -81,44 +112,45 @@ dependencies:
81
112
  version: '0.3'
82
113
  type: :development
83
114
  prerelease: false
84
- version_requirements: *70327439149500
85
- - !ruby/object:Gem::Dependency
86
- name: rdoc
87
- requirement: &70327439149040 !ruby/object:Gem::Requirement
115
+ version_requirements: !ruby/object:Gem::Requirement
88
116
  none: false
89
117
  requirements:
90
118
  - - ~>
91
119
  - !ruby/object:Gem::Version
92
- version: '3.10'
93
- type: :development
94
- prerelease: false
95
- version_requirements: *70327439149040
120
+ version: '0.3'
96
121
  - !ruby/object:Gem::Dependency
97
122
  name: hoe
98
- requirement: &70327439148620 !ruby/object:Gem::Requirement
123
+ requirement: !ruby/object:Gem::Requirement
99
124
  none: false
100
125
  requirements:
101
126
  - - ~>
102
127
  - !ruby/object:Gem::Version
103
- version: '2.13'
128
+ version: '3.0'
104
129
  type: :development
105
130
  prerelease: false
106
- version_requirements: *70327439148620
107
- description: ! 'Configurability is a mixin that allows you to add configurability
108
- to one or
131
+ version_requirements: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ~>
135
+ - !ruby/object:Gem::Version
136
+ version: '3.0'
137
+ description: ! 'Configurability is a unified, unintrusive, assume-nothing configuration
138
+ system
139
+
140
+ for Ruby. It lets you keep the configuration for multiple objects in a single
109
141
 
110
- more objects or classes. You can assign them each a subsection of the
142
+ config file, load the file when it''s convenient for you, and distribute the
111
143
 
112
- configuration, and then later, when the configuration is loaded, the
144
+ configuration when you''re ready, sending it everywhere it needs to go with a
113
145
 
114
- configuration is split up and sent to the objects that will use it.'
146
+ single action.'
115
147
  email:
116
148
  - ged@FaerieMUD.org
117
149
  executables: []
118
150
  extensions: []
119
151
  extra_rdoc_files:
120
- - Manifest.txt
121
152
  - History.rdoc
153
+ - Manifest.txt
122
154
  - README.rdoc
123
155
  files:
124
156
  - ChangeLog
@@ -133,19 +165,21 @@ files:
133
165
  - lib/configurability/behavior.rb
134
166
  - lib/configurability/config.rb
135
167
  - lib/configurability/deferredconfig.rb
136
- - lib/configurability/logformatter.rb
168
+ - lib/configurability/logging.rb
137
169
  - spec/configurability/config_spec.rb
138
170
  - spec/configurability/deferredconfig_spec.rb
139
171
  - spec/configurability_spec.rb
140
172
  - spec/lib/helpers.rb
141
173
  - .gemtest
142
- homepage: http://bitbucket.org/ged/configurability
174
+ homepage: https://bitbucket.org/ged/configurability
143
175
  licenses:
144
176
  - BSD
145
177
  post_install_message:
146
178
  rdoc_options:
147
- - --main
148
- - README.rdoc
179
+ - -f
180
+ - fivefish
181
+ - -t
182
+ - Configurability Toolkit
149
183
  require_paths:
150
184
  - lib
151
185
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -162,9 +196,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
196
  version: '0'
163
197
  requirements: []
164
198
  rubyforge_project: configurability
165
- rubygems_version: 1.8.16
199
+ rubygems_version: 1.8.21
166
200
  signing_key:
167
201
  specification_version: 3
168
- summary: Configurability is a mixin that allows you to add configurability to one
169
- or more objects or classes
202
+ summary: Configurability is a unified, unintrusive, assume-nothing configuration system
203
+ for Ruby
170
204
  test_files: []
metadata.gz.sig CHANGED
Binary file
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'logger'
4
-
5
- require 'configurability'
6
-
7
- # A custom log-formatter class for
8
- class Configurability::LogFormatter < Logger::Formatter
9
-
10
- # The format to output unless debugging is turned on
11
- DEFAULT_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"
12
-
13
- # The format to output if debugging is turned on
14
- DEFAULT_DEBUG_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"
15
-
16
-
17
- ### Initialize the formatter with a reference to the logger so it can check for log level.
18
- def initialize( logger, format=DEFAULT_FORMAT, debug=DEFAULT_DEBUG_FORMAT ) # :notnew:
19
- @logger = logger
20
- @format = format
21
- @debug_format = debug
22
-
23
- super()
24
- end
25
-
26
- ######
27
- public
28
- ######
29
-
30
- # The Logger object associated with the formatter
31
- attr_accessor :logger
32
-
33
- # The logging format string
34
- attr_accessor :format
35
-
36
- # The logging format string that's used when outputting in debug mode
37
- attr_accessor :debug_format
38
-
39
-
40
- ### Log using either the DEBUG_FORMAT if the associated logger is at ::DEBUG level or
41
- ### using FORMAT if it's anything less verbose.
42
- def call( severity, time, progname, msg )
43
- args = [
44
- time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
45
- time.usec, # %2$d
46
- Process.pid, # %3$d
47
- Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
48
- severity, # %5$s
49
- progname, # %6$s
50
- msg # %7$s
51
- ]
52
-
53
- if @logger.level == Logger::DEBUG
54
- return self.debug_format % args
55
- else
56
- return self.format % args
57
- end
58
- end
59
-
60
- end # class Configurability::LogFormatter