configurability 3.2.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
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