Class: Configurability::Config::Struct

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
DataUtilities, Enumerable
Defined in:
lib/configurability/config.rb

Overview

Hash-wrapper that allows struct-like accessor calls on nested hashes.

Instance Method Summary collapse

Methods included from DataUtilities

#stringify_keys, #symbolify_keys

Constructor Details

#initialize(hash = nil) ⇒ Struct

Create a new ConfigStruct using the values from the given hash if specified.



353
354
355
356
357
# File 'lib/configurability/config.rb', line 353

def initialize( hash=nil )
  hash ||= {}
  @hash = symbolify_keys( hash )
  @dirty = false
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args) ⇒ Object (protected)

Handle calls to key-methods



505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
# File 'lib/configurability/config.rb', line 505

def method_missing( sym, *args )
  key = sym.to_s.sub( /(=|\?)$/, '' ).to_sym

  # Create new methods for this key
  reader    = self.create_member_reader( key )
  writer    = self.create_member_writer( key )
  predicate = self.create_member_predicate( key )

  # ...and install them
  self.class.send( :define_method, key, &reader )
  self.class.send( :define_method, "#{key}=", &writer )
  self.class.send( :define_method, "#{key}?", &predicate )

  # Now jump to the requested method in a way that won't come back through
  # the proxy method if something didn't get defined
  self.method( sym ).call( *args )
end

Instance Method Details

#[](key) ⇒ Object

Return the value associated with the specified key, or another Configurability::Config::ConfigStruct if key is a section name.



374
375
376
377
378
379
380
381
# File 'lib/configurability/config.rb', line 374

def []( key )
  key = key.to_sym if key.respond_to?( :to_sym )

  # Convert Hashes to Struct on the fly for subsections
  @hash[ key ] = self.class.new( @hash[key] ) if @hash[ key ].is_a?( Hash )

  return @hash[ key ]
end

#[]=(key, value) ⇒ Object

Set the value associated with the specified key to value.



385
386
387
388
389
# File 'lib/configurability/config.rb', line 385

def []=( key, value )
  key = key.to_sym
  self.mark_dirty if @hash[ key ] != value
  @hash[ key ] = value
end

#dirty?Boolean

Returns true if the ConfigStruct or any of its sub-structs have changed since it was created.

Returns:

  • (Boolean)


400
401
402
403
404
405
# File 'lib/configurability/config.rb', line 400

def dirty?
  return true if @dirty
  return true if @hash.values.find do |obj|
    obj.respond_to?( :dirty? ) && obj.dirty?
  end
end

#inspectObject

Return a human-readable representation of the Struct suitable for debugging.



491
492
493
494
495
496
497
# File 'lib/configurability/config.rb', line 491

def inspect
  return "#<%s:%0x16 %p>" % [
    self.class.name,
    self.object_id * 2,
    @hash,
  ]
end

#mark_dirtyObject

Mark the struct has having been modified since its creation.



393
394
395
# File 'lib/configurability/config.rb', line 393

def mark_dirty
  @dirty = true
end

#member?(name) ⇒ Boolean Also known as: has_member?

Returns true if the given name is the name of a member of the receiver.

Returns:

  • (Boolean)


447
448
449
450
# File 'lib/configurability/config.rb', line 447

def member?( name )
  name = name.to_sym if name.respond_to?( :to_sym )
  return @hash.key?( name )
end

#membersObject

Returns an Array of Symbols, one for each of the struct’s members.



440
441
442
# File 'lib/configurability/config.rb', line 440

def members
  return @hash.keys
end

#merge(other) ⇒ Object

Return a new Configurability::Config::Struct which is the result of merging the receiver with the given other object (a Hash or another Configurability::Config::Struct).



485
486
487
# File 'lib/configurability/config.rb', line 485

def merge( other )
  self.dup.merge!( other )
end

#merge!(other) ⇒ Object

Merge the specified other object with this config struct. The other object can be either a Hash, another Configurability::Config::Struct, or an Configurability::Config.



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
# File 'lib/configurability/config.rb', line 457

def merge!( other )
  mergefunc = Configurability::Config.method( :merge_complex_hashes )

  case other
  when Hash
    @hash = self.to_h.merge( other, &mergefunc )

  when Configurability::Config::Struct
    @hash = self.to_h.merge( other.to_h, &mergefunc )

  when Configurability::Config
    @hash = self.to_h.merge( other.struct.to_h, &mergefunc )

  else
    raise TypeError,
      "Don't know how to merge with a %p" % other.class
  end

  # :TODO: Actually check to see if anything has changed?
  @dirty = true

  return self
end

#respond_to?(sym, priv = false) ⇒ Boolean

Return true if the receiver responds to the given method. Overridden to grok autoloaded methods.

Returns:

  • (Boolean)


432
433
434
435
436
# File 'lib/configurability/config.rb', line 432

def respond_to?( sym, priv=false )
  key = sym.to_s.sub( /(=|\?)$/, '' ).to_sym
  return true if @hash.key?( key )
  super
end

#to_hashObject Also known as: to_h

Return the receiver’s values as a (possibly multi-dimensional) Hash with String keys.



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/configurability/config.rb', line 410

def to_hash
  rhash = {}
  @hash.each {|k,v|
    case v
    when Configurability::Config::Struct
      rhash[k] = v.to_h
    when NilClass, FalseClass, TrueClass, Numeric
      # No-op (can't dup)
      rhash[k] = v
    when Symbol
      rhash[k] = v.to_s
    else
      rhash[k] = v.dup
    end
  }
  return rhash
end