configurability 3.2.0 → 4.2.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/History.md CHANGED
@@ -1,3 +1,68 @@
1
+ # Release History for configurability
2
+
3
+ ---
4
+
5
+ ## v4.2.0 [2020-12-28] Michael Granger <ged@faeriemud.org>
6
+
7
+ Improvements:
8
+
9
+ - Updates for Ruby 3
10
+
11
+
12
+ ## v4.1.0 [2020-02-19] Michael Granger <ged@faeriemud.org>
13
+
14
+ Improvements:
15
+
16
+ - Add support for two-argument #respond_to? to Configurability::Config
17
+
18
+
19
+ ## v4.0.0 [2020-01-08] Michael Granger <ged@faeriemud.org>
20
+
21
+ Breaking changes:
22
+
23
+ - Remove tainting, which is deprecated in 2.7 and beyond.
24
+
25
+ Enhancements:
26
+
27
+ - Enable SafeYAML if it's loaded
28
+
29
+
30
+ ## v3.4.1 [2019-09-03] Michael Granger <ged@FaerieMUD.org>
31
+
32
+ Bugfixes:
33
+
34
+ - Bump minimal Ruby version to 2.5.
35
+
36
+ Documentation:
37
+
38
+ - Change URLs to Sourcehut/ability.guide
39
+ - Fix license years, README title
40
+
41
+
42
+ ## v3.4.0 [2019-09-01] Michael Granger <ged@FaerieMUD.org>
43
+
44
+ (Yanked due to inaccurate minimum Ruby version)
45
+
46
+ Bugfixes:
47
+
48
+ - Remove old command that depended on Trollop
49
+
50
+ Enhancements:
51
+
52
+ - Add a predicate setting option
53
+ - Add a test for declaring helper methods inside a settings block
54
+ - Add after-configure hooks to execute a block after the configuration
55
+ has been loaded
56
+
57
+
58
+ ## v3.3.0 [2018-09-12] Michael Granger <ged@FaerieMUD.org>
59
+
60
+ Enhancements:
61
+
62
+ - Declare the class/class-instance variable when declaring a setting
63
+ - Add a 'defaults' subcommand to the configurability executable
64
+
65
+
1
66
  ## v3.2.0 [2017-04-17] Michael Granger <ged@FaerieMUD.org>
2
67
 
3
68
  Enhancements:
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2016 Michael Granger and Mahlon E. Smith
1
+ Copyright (c) 2010-2019 Michael Granger and Mahlon E. Smith
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
@@ -4,7 +4,6 @@ LICENSE
4
4
  Manifest.txt
5
5
  README.md
6
6
  Rakefile
7
- bin/configurability
8
7
  examples/basicconfig.rb
9
8
  examples/config.yml
10
9
  examples/readme.rb
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Configurability
2
2
 
3
3
  home
4
- : https://bitbucket.org/ged/configurability
4
+ : https://configur.ability.guide/
5
5
 
6
6
  code
7
- : https://bitbucket.org/ged/configurability
7
+ : https://hg.sr.ht/~ged/Configurability
8
8
 
9
9
  docs
10
10
  : http://deveiate.org/code/configurability
@@ -117,6 +117,42 @@ After this happens you can access the configuration values like this:
117
117
  Database.password
118
118
  # => "pXVvVY,YjWNRRi[yPWx4"
119
119
 
120
+ You can add helper methods inside the `configurability` block to eliminate
121
+ repeated code in your setting blocks:
122
+
123
+ configurability( :server ) do
124
+ def self::make_path( value )
125
+ return nil unless value
126
+ pn = Pathname( value )
127
+ raise "Can't read from %s!" % [ pn ] unless pn.readable?
128
+ return pn
129
+ end
130
+
131
+ setting :template_path do |value|
132
+ make_path( value )
133
+ end
134
+
135
+ setting :plugin_path do |*values|
136
+ make_path( value )
137
+ end
138
+ end
139
+
140
+ If a setting is a boolean, you can also have a predicate method created for it
141
+ alongside its getter and setter:
142
+
143
+ class Mailer
144
+ extend Configurability
145
+ configurability( :db ) do
146
+ setting :use_whitelist, default: false, predicate: true
147
+ end
148
+ end
149
+
150
+ Mailer.use_whitelist?
151
+ # => false
152
+ Mailer.use_whitelist = true
153
+ Mailer.use_whitelist?
154
+ # => true
155
+
120
156
 
121
157
  ### More Details
122
158
 
@@ -387,9 +423,9 @@ default_config
387
423
 
388
424
  You can submit bug reports, suggestions, clone it with Mercurial, and
389
425
  read more about future plans at
390
- {the project page}[http://bitbucket.org/ged/configurability]. If you
426
+ [the project page](http://hg.sr.ht/ged/configurability). If you
391
427
  prefer Git, there is also a
392
- {Github mirror}[https://github.com/ged/configurability].
428
+ [Github mirror](https://github.com/ged/configurability).
393
429
 
394
430
  After checking out the source, run:
395
431
 
@@ -399,9 +435,15 @@ This task will install any missing dependencies, run the tests/specs,
399
435
  and generate the API documentation.
400
436
 
401
437
 
438
+ ## Authors
439
+
440
+ - Michael Granger <ged@faeriemud.org>
441
+ - Mahlon E. Smith <mahlon@martini.nu>
442
+
443
+
402
444
  ## License
403
445
 
404
- Copyright (c) 2010-2017 Michael Granger and Mahlon E. Smith
446
+ Copyright (c) 2010-2020 Michael Granger and Mahlon E. Smith
405
447
  All rights reserved.
406
448
 
407
449
  Redistribution and use in source and binary forms, with or without
data/Rakefile CHANGED
@@ -1,89 +1,9 @@
1
- #!/usr/bin/env rake
1
+ #!/usr/bin/env ruby -S rake
2
2
 
3
- begin
4
- require 'hoe'
5
- rescue LoadError
6
- abort "This Rakefile requires 'hoe' (gem install hoe)"
7
- end
8
-
9
- GEMSPEC = 'configurability.gemspec'
10
-
11
- Hoe.plugin :mercurial
12
- Hoe.plugin :signing
13
- Hoe.plugin :deveiate
14
-
15
- Hoe.plugins.delete :rubyforge
16
-
17
- Encoding.default_internal = Encoding::UTF_8
18
-
19
- hoespec = Hoe.spec 'configurability' do |spec|
20
- spec.readme_file = 'README.md'
21
- spec.history_file = 'History.md'
22
- spec.extra_rdoc_files = FileList[ '*.rdoc', '*.md' ]
23
- spec.license 'BSD-3-Clause'
24
- spec.urls = {
25
- home: 'http://deveiate.org/projects/configurability',
26
- code: 'http://bitbucket.org/ged/configurability',
27
- docs: 'http://deveiate.org/code/configurability',
28
- github: 'http://github.com/ged/configurability',
29
- }
3
+ require 'rake/deveiate'
30
4
 
31
- spec.developer 'Michael Granger', 'ged@FaerieMUD.org'
32
- spec.developer 'Mahlon E. Smith', 'mahlon@martini.nu'
33
-
34
- spec.dependency 'loggability', '~> 0.12'
35
-
36
- spec.dependency 'hoe-deveiate', '~> 0.8', :developer
37
- spec.dependency 'simplecov', '~> 0.12', :developer
38
- spec.dependency 'rspec', '~> 3.5', :developer
39
-
40
- spec.require_ruby_version( '>= 2.2.0' )
41
-
42
- spec.hg_sign_tags = true if spec.respond_to?( :hg_sign_tags= )
43
- spec.rdoc_locations << "deveiate:/usr/local/www/public/code/#{remote_rdoc_dir}"
5
+ Rake::DevEiate.setup( 'configurability' ) do |project|
6
+ project.required_ruby_version = '>= 2.5'
7
+ project.publish_to = 'deveiate:/usr/local/www/public/code'
44
8
  end
45
9
 
46
- ENV['VERSION'] ||= hoespec.spec.version.to_s
47
-
48
- # Ensure the specs pass before checking in
49
- task 'hg:precheckin' => [ :check_history, :check_manifest, :gemspec, :spec ]
50
-
51
-
52
- desc "Build a coverage report"
53
- task :coverage do
54
- ENV["COVERAGE"] = 'yes'
55
- Rake::Task[:spec].invoke
56
- end
57
-
58
-
59
- # Use the fivefish formatter for docs generated from development checkout
60
- if File.directory?( '.hg' )
61
- require 'rdoc/task'
62
-
63
- Rake::Task[ 'docs' ].clear
64
- RDoc::Task.new( 'docs' ) do |rdoc|
65
- rdoc.main = "README.md"
66
- rdoc.rdoc_files.include( "*.rdoc", "*.md", "ChangeLog", "lib/**/*.rb" )
67
- rdoc.generator = :fivefish
68
- rdoc.title = 'Configurability'
69
- rdoc.rdoc_dir = 'doc'
70
- end
71
- end
72
-
73
-
74
- task :gemspec => [ 'ChangeLog', GEMSPEC ]
75
- file GEMSPEC => __FILE__ do |task|
76
- spec = $hoespec.spec
77
- spec.files.delete( '.gemtest' )
78
- spec.files.delete( 'LICENSE' )
79
- spec.signing_key = nil
80
- spec.version = "#{spec.version.bump}.0.pre#{Time.now.strftime("%Y%m%d%H%M%S")}"
81
- spec.cert_chain = [ 'certs/ged.pem' ]
82
- File.open( task.name, 'w' ) do |fh|
83
- fh.write( spec.to_ruby )
84
- end
85
- end
86
- CLOBBER.include( GEMSPEC )
87
-
88
- task :default => :gemspec
89
-
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'set'
3
4
  require 'loggability'
4
5
  require 'yaml'
5
6
 
@@ -13,10 +14,10 @@ module Configurability
13
14
 
14
15
 
15
16
  # Library version constant
16
- VERSION = '3.2.0'
17
+ VERSION = '4.2.0'
17
18
 
18
19
  # Version-control revision constant
19
- REVISION = %q$Revision: c1a8ffc3266f $
20
+ REVISION = %q$Revision$
20
21
 
21
22
  require 'configurability/deferred_config'
22
23
 
@@ -25,20 +26,58 @@ module Configurability
25
26
 
26
27
 
27
28
  ### The objects that have had Configurability added to them
29
+ ##
30
+ # the Array of objects that have had Configurability added to them
31
+ singleton_class.attr_accessor :configurable_objects
28
32
  @configurable_objects = []
29
33
 
30
- ### The loaded config (if there is one)
34
+ ##
35
+ # the loaded configuration (after ::configure_objects has been called at least once)
36
+ singleton_class.attr_accessor :loaded_config
31
37
  @loaded_config = nil
32
38
 
39
+ ##
40
+ # An Array of callbacks to be run after the config is loaded
41
+ @after_configure_hooks = Set.new
42
+ singleton_class.attr_reader :after_configure_hooks
33
43
 
34
- class << self
35
44
 
36
- # the Array of objects that have had Configurability added to them
37
- attr_accessor :configurable_objects
45
+ @after_configure_hooks_run = false
38
46
 
39
- # the loaded configuration (after ::configure_objects has been called at least once)
40
- attr_accessor :loaded_config
47
+ ### Returns +true+ if the after-configuration hooks have run at least once.
48
+ def self::after_configure_hooks_run?
49
+ return @after_configure_hooks_run ? true : false
50
+ end
51
+
52
+
53
+ ### Set the flag that indicates that the after-configure hooks have run at least
54
+ ### once.
55
+ def self::after_configure_hooks_run=( new_value )
56
+ @after_configure_hooks_run = new_value ? true : false
57
+ end
58
+
59
+
60
+ ### Register a callback to be run after the config is loaded.
61
+ def self::after_configure( &block )
62
+ raise LocalJumpError, "no block given" unless block
63
+ self.after_configure_hooks << block
41
64
 
65
+ # Call the block immediately if the hooks have already been called or are in
66
+ # the process of being called.
67
+ block.call if self.after_configure_hooks_run?
68
+ end
69
+ singleton_class.alias_method :after_configuration, :after_configure
70
+
71
+
72
+ ### Call the post-configuration callbacks.
73
+ def self::call_after_configure_hooks
74
+ self.log.debug " calling %d post-config hooks" % [ self.after_configure_hooks.length ]
75
+ @after_configure_hooks_run = true
76
+
77
+ self.after_configure_hooks.to_a.each do |hook|
78
+ # self.log.debug " %s line %s..." % hook.source_location
79
+ hook.call
80
+ end
42
81
  end
43
82
 
44
83
 
@@ -103,12 +142,15 @@ module Configurability
103
142
  self.configurable_objects.each do |obj|
104
143
  self.install_config( config, obj )
105
144
  end
145
+
146
+ self.call_after_configure_hooks
106
147
  end
107
148
 
108
149
 
109
150
  ### If a configuration has been loaded (via {#configure_objects}), clear it.
110
151
  def self::reset
111
152
  self.loaded_config = nil
153
+ self.after_configure_hooks_run = false
112
154
  end
113
155
 
114
156
 
@@ -259,8 +301,7 @@ module Configurability
259
301
  @config.each_pair do |key, value|
260
302
  Configurability.log.debug "Looking for %p config attribute" % [ key ]
261
303
  next unless self.respond_to?( "#{key}=" )
262
- Configurability.log.debug " setting %p to %p via attr_writer" %
263
- [ key, value ]
304
+ Configurability.log.debug " setting %p to %p" % [ key, value ]
264
305
  self.public_send( "#{key}=", value )
265
306
  end
266
307
  else
@@ -43,6 +43,10 @@ class Configurability::Config
43
43
  log_to :configurability
44
44
 
45
45
 
46
+ # Make safe loading the default if SafeYAML is loaded
47
+ SafeYAML::OPTIONS[:default_mode] = :safe if defined?( SafeYAML )
48
+
49
+
46
50
  #############################################################
47
51
  ### C L A S S M E T H O D S
48
52
  #############################################################
@@ -84,7 +88,7 @@ class Configurability::Config
84
88
 
85
89
  # Make a deep copy of the defaults before loading so we don't modify
86
90
  # the argument
87
- @defaults = Marshal.load( Marshal.dump(defaults) ) if defaults
91
+ @defaults = defaults ? Marshal.load( Marshal.dump(defaults) ) : nil
88
92
  @time_created = Time.now
89
93
  @path = path
90
94
 
@@ -162,7 +166,7 @@ class Configurability::Config
162
166
 
163
167
 
164
168
  ### Returns +true+ for methods which can be autoloaded
165
- def respond_to?( sym )
169
+ def respond_to?( sym, include_all=false )
166
170
  return true if @struct.member?( sym.to_s.sub(/(=|\?)$/, '').to_sym )
167
171
  super
168
172
  end
@@ -256,7 +260,7 @@ class Configurability::Config
256
260
  end
257
261
  end
258
262
 
259
- ihash = symbolify_keys( untaint_hash(hash) )
263
+ ihash = symbolify_keys( hash )
260
264
  idefaults = symbolify_keys( defaults )
261
265
  mergedhash = idefaults.merge( ihash, &mergefunc )
262
266
 
@@ -285,41 +289,9 @@ class Configurability::Config
285
289
 
286
290
 
287
291
  # A collection of data-structure-manipulation functions.
292
+ # :TODO: Replace with #transform_keys after 2.4's EOL
288
293
  module DataUtilities
289
294
 
290
- ### Return a copy of the specified +hash+ with all of its values
291
- ### untainted.
292
- def untaint_hash( hash )
293
- newhash = {}
294
- hash.each_key do |key|
295
- newhash[ key ] = untaint_value( hash[key] )
296
- end
297
- return newhash
298
- end
299
-
300
-
301
- ### Return an untainted copy of the specified +val+.
302
- def untaint_value( val )
303
- case val
304
- when Hash
305
- return untaint_hash( val )
306
-
307
- when Array
308
- return val.collect {|v| untaint_value(v) }
309
-
310
- when NilClass, TrueClass, FalseClass, Numeric, Symbol, Encoding
311
- return val
312
-
313
- else
314
- if val.respond_to?( :dup ) && val.respond_to?( :untaint )
315
- return val.dup.untaint
316
- else
317
- return val
318
- end
319
- end
320
- end
321
-
322
-
323
295
  ### Return a duplicate of the given +hash+ with its identifier-like keys
324
296
  ### transformed into symbols from whatever they were before.
325
297
  def symbolify_keys( hash )
@@ -400,7 +372,7 @@ class Configurability::Config
400
372
  # Return the value associated with the specified +key+, or another
401
373
  # Configurability::Config::ConfigStruct if +key+ is a section name.
402
374
  def []( key )
403
- key = key.untaint.to_sym if key.respond_to?( :to_sym )
375
+ key = key.to_sym if key.respond_to?( :to_sym )
404
376
 
405
377
  # Convert Hashes to Struct on the fly for subsections
406
378
  @hash[ key ] = self.class.new( @hash[key] ) if @hash[ key ].is_a?( Hash )
@@ -411,7 +383,7 @@ class Configurability::Config
411
383
 
412
384
  ### Set the value associated with the specified +key+ to +value+.
413
385
  def []=( key, value )
414
- key = key.untaint.to_sym
386
+ key = key.to_sym
415
387
  self.mark_dirty if @hash[ key ] != value
416
388
  @hash[ key ] = value
417
389
  end