Class: Rbcli::Config

Inherits:
Hash
  • Object
show all
Defined in:
lib/rbcli/components/config/config.rb

Direct Known Subclasses

ConfigOfDeath

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Hash

#deep_stringify, #deep_stringify!, #deep_symbolize, #deep_symbolize!

Constructor Details

#initialize(location: nil, type: nil, schema_file: nil, schema_hash: nil, create_if_not_exists: false, suppress_errors: false, banner: nil, defaults: {}, skeleton: nil) ⇒ Config

Returns a new instance of Config.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rbcli/components/config/config.rb', line 11

def initialize location: nil, type: nil, schema_file: nil, schema_hash: nil, create_if_not_exists: false, suppress_errors: false, banner: nil, defaults: {}, skeleton: nil
  location = [location] unless location.is_a?(Array)
  locations = location.map { |path| [path, Rbcli::UserConf::Backend.create(path, type: type)] }.reject { |path, storage| !(path.nil? || path == :null) && storage.type == 'NULL' }
  existing_location = locations.select { |_path, storage| storage.exist? }.first
  savable_location = locations.select { |_path, storage| storage.savable? }.first
  if !existing_location.nil?
    @location, @storage = existing_location
    Rbcli.log.debug @location.nil? ? "Instantiated null config; data will not be stored" : "Found config of type '#{@storage.type}' at '#{@location}'", "CONF"
  elsif !savable_location.nil? && create_if_not_exists
    @location, @storage = savable_location
    @should_create = true
    Rbcli.log.debug "Ready to create new config of type '#{@storage.type}' at '#{@location}'", "CONF"
  elsif suppress_errors
    @location, @storage = :null, Rbcli::UserConf::Backend.create(:null)
    Rbcli.log.debug "Location(s) could not be found and/or are not writeable. Instantiating null config and failing silently.", "CONF"
  else
    Rbcli.log.fatal "Config file could not be loaded. Please verify that it exists at one of the following locations: #{location.join(", ")}", "CONF"
    Rbcli::exit 2
  end
  @suppress_errors = suppress_errors
  @original_hash = {}
  @defaults = defaults
  @skeleton = skeleton
  @banner = banner
  if schema_hash
    @schema = self.class.new
    schema_hash.each_key { |key| @schema[key] = schema_hash[key] }
    @schema.is_schema = true
  elsif schema_file
    @schema = self.class.new(location: schema_file)
    @schema.is_schema = true
  else
    @schema = nil
  end
end

Instance Attribute Details

Returns the value of attribute banner.



48
49
50
# File 'lib/rbcli/components/config/config.rb', line 48

def banner
  @banner
end

#defaultsObject

Returns the value of attribute defaults.



47
48
49
# File 'lib/rbcli/components/config/config.rb', line 47

def defaults
  @defaults
end

#is_schemaObject

Returns the value of attribute is_schema.



47
48
49
# File 'lib/rbcli/components/config/config.rb', line 47

def is_schema
  @is_schema
end

#locationObject (readonly)

Returns the value of attribute location.



48
49
50
# File 'lib/rbcli/components/config/config.rb', line 48

def location
  @location
end

#schemaObject (readonly)

Returns the value of attribute schema.



48
49
50
# File 'lib/rbcli/components/config/config.rb', line 48

def schema
  @schema
end

#skeletonObject (readonly)

Returns the value of attribute skeleton.



48
49
50
# File 'lib/rbcli/components/config/config.rb', line 48

def skeleton
  @skeleton
end

#suppress_errorsObject (readonly)

Returns the value of attribute suppress_errors.



48
49
50
# File 'lib/rbcli/components/config/config.rb', line 48

def suppress_errors
  @suppress_errors
end

Instance Method Details

#add_default(slug, default = nil) ⇒ Object



50
51
52
# File 'lib/rbcli/components/config/config.rb', line 50

def add_default slug, default = nil
  @defaults[slug] = default
end

#annotate!Object



129
130
131
# File 'lib/rbcli/components/config/config.rb', line 129

def annotate!
  @storage.annotate! @banner
end

#create!(path: nil, force: false) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/rbcli/components/config/config.rb', line 113

def create! path: nil, force: false
  return false unless @location.is_a?(String)
  if File.exist?(path || @location) && !force
    Rbcli.log.add (@suppress_errors ? :debug : :error), "Config file already exists; can not overwrite.", "CONF"
    Rbcli::exit 4 unless @suppress_errors
    return false
  end
  if @skeleton
    (path.nil? ? @storage : Rbcli::UserConf::Backend.create(path, type: self.type)).save_raw @skeleton
  else
    self.deep_merge!(@storage.respond_to?(:parse_defaults) ? @storage.parse_defaults(@defaults) : @defaults)
    self.save!
  end
  @storage.annotate!(@banner) if @banner
end

#load!Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rbcli/components/config/config.rb', line 58

def load!
  if @should_create
    Rbcli.log.add (@suppress_errors ? :debug : :info), "Config file #{@location} does not exist. Creating with default values.", "CONF"
    return self.create!(force: true)
  end
  Rbcli.log.debug "Loading #{@is_schema ? 'schema' : 'config'} file", "CONF"
  begin
    @original_hash = @storage.load(@defaults)
  rescue Rbcli::ParseError => e
    Rbcli.log.add (@suppress_errors ? :debug : :fatal), e.message, "CONF"
    Rbcli.exit 3 unless @suppress_errors
    @original_hash = {}
  end
  unless @storage.loaded?
    Rbcli.log.add (@suppress_errors ? :debug : :warn), "Could not load #{@is_schema ? 'schema' : 'config'} file", "CONF"
    Rbcli.log.add (@suppress_errors ? :debug : :warn), "Using defaults", "CONF" unless @defaults.empty?
  end
  self.clear
  self.deep_merge!(@storage.respond_to?(:parse_defaults) ? @storage.parse_defaults(@defaults) : @defaults)
  self.deep_merge!(@original_hash.deep_symbolize!) if @original_hash.is_a?(Hash)
end

#save!Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/rbcli/components/config/config.rb', line 96

def save!
  unless @storage.savable?
    Rbcli.log.add (@suppress_errors ? :debug : :warn), "Config file not savable. Data not stored.", "CONF"
    return false
  end
  hash_to_save = Marshal.load(Marshal.dump(self)).to_h # This removes all custom instance variables and types from the data
  if hash_to_save == @original_hash && !@should_create
    Rbcli.log.debug "No changes detected in the config. Skipping save.", "CONF"
  else
    Rbcli.log.debug "Changes detected in the config. Saving updated config.", "CONF"
    @storage.save(hash_to_save.deep_stringify!)
    @original_hash = hash_to_save.deep_symbolize!
    @should_create = false
  end
  self
end

#typeObject



54
55
56
# File 'lib/rbcli/components/config/config.rb', line 54

def type
  @storage.type.downcase.to_sym
end

#validate!Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rbcli/components/config/config.rb', line 80

def validate!
  return true if @schema.nil?
  Rbcli.log.debug "Validating config against schema", "CONF"
  @schema.load! unless @schema.location.nil?
  begin
    JSON::Validator.validate!(@schema, self)
  rescue JSON::Schema::ValidationError => _e
    Rbcli.log.send (@suppress_errors ? :debug : :error), "There are errors in the config. Please fix these errors and try again."
    Rbcli.log.send (@suppress_errors ? :debug : :error), JSON::Validator.fully_validate(@schema, self).join("\n")
    Rbcli::exit 4 unless @suppress_errors
    return false
  end
  Rbcli.log.debug "Validated config against schema successfully", "CONF"
  true
end