Class: Canopus::Settings
- Inherits:
-
Object
- Object
- Canopus::Settings
- Defined in:
- lib/canopus/settings.rb,
lib/canopus/settings/schema.rb,
sig/canopus.rbs
Defined Under Namespace
Modules: Schema
Constant Summary collapse
- DEFAULT_AUTO_PAIRS =
Schema::DEFAULT_AUTO_PAIRS
- DEFAULTS =
Schema::DEFAULTS
- SCHEMA =
Schema::JSON_SCHEMA
- SCHEMA_MODEL =
Schema::KOCHAB_SCHEMA
- SCHEMA_METADATA =
SCHEMA_MODEL
Instance Attribute Summary collapse
-
#errors ⇒ Array[String]
readonly
Returns the value of attribute errors.
-
#layers ⇒ Array[String | values]
readonly
Returns the value of attribute layers.
-
#values ⇒ values
readonly
Returns the value of attribute values.
Class Method Summary collapse
- .file_diagnostics(path) ⇒ [Kochab::Document, Array[Kochab::Error | Kochab::Diagnostic]]?
- .schema ⇒ values
- .schema_metadata ⇒ Kochab::Schema
- .schema_model ⇒ Kochab::Schema
- .user_path ⇒ String
Instance Method Summary collapse
- #[](key) ⇒ json
- #for_language(language) ⇒ instance
-
#initialize(*layers) ⇒ Settings
constructor
A new instance of Settings.
- #merge!(layer) ⇒ instance
- #paths ⇒ Array[String]
- #reload ⇒ instance
- #set_file(path, key, value) ⇒ instance
Constructor Details
#initialize(*layers) ⇒ Settings
Returns a new instance of Settings.
37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/canopus/settings.rb', line 37 def initialize(*layers) fallback = layers.pop.values if layers.last.is_a?(ReloadFallback) @values, @errors = DEFAULTS.dup, [] @layers = layers.compact @reload_fallback = fallback @initializing = true layers.compact.each { |layer| merge!(layer.is_a?(String) ? parse_file(layer) : layer) } @initializing = false @reload_fallback = nil validate! end |
Instance Attribute Details
#errors ⇒ Array[String] (readonly)
Returns the value of attribute errors.
18 19 20 |
# File 'lib/canopus/settings.rb', line 18 def errors @errors end |
#layers ⇒ Array[String | values] (readonly)
Returns the value of attribute layers.
18 19 20 |
# File 'lib/canopus/settings.rb', line 18 def layers @layers end |
#values ⇒ values (readonly)
Returns the value of attribute values.
18 19 20 |
# File 'lib/canopus/settings.rb', line 18 def values @values end |
Class Method Details
.file_diagnostics(path) ⇒ [Kochab::Document, Array[Kochab::Error | Kochab::Diagnostic]]?
22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/canopus/settings.rb', line 22 def self.file_diagnostics(path) return nil unless File.file?(path) document = Kochab.parse(File.read(path)) diagnostics = document.errors.dup if document.valid? diagnostics.concat(SCHEMA_MODEL.validate(document).reject { |diagnostic| diagnostic. == "Required value is missing" }) end [document, diagnostics.freeze].freeze rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR nil end |
.schema_metadata ⇒ Kochab::Schema
21 |
# File 'lib/canopus/settings.rb', line 21 def self. = SCHEMA_MODEL |
.schema_model ⇒ Kochab::Schema
20 |
# File 'lib/canopus/settings.rb', line 20 def self.schema_model = SCHEMA_MODEL |
.user_path ⇒ String
34 35 36 |
# File 'lib/canopus/settings.rb', line 34 def self.user_path File.join(ENV["XDG_CONFIG_HOME"] || File.("~/.config"), "canopus", "settings.jsonc") end |
Instance Method Details
#[](key) ⇒ json
48 |
# File 'lib/canopus/settings.rb', line 48 def [](key) = @values[key.to_s] |
#for_language(language) ⇒ instance
51 |
# File 'lib/canopus/settings.rb', line 51 def for_language(language) = Settings.new(@values, @values.fetch("languages", {}).fetch(language, {})) |
#merge!(layer) ⇒ instance
52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/canopus/settings.rb', line 52 def merge!(layer) document = layer.is_a?(Kochab::Document) raise Error, "settings must be an object" unless document || layer.is_a?(Hash) previous = @values @values = document ? merge_document(@values, layer) : merge_hash(@values, layer) validate! @layers << snapshot_layer(layer) unless @initializing self rescue StandardError @values = previous if previous raise end |
#paths ⇒ Array[String]
49 |
# File 'lib/canopus/settings.rb', line 49 def paths = @layers.grep(String) |
#reload ⇒ instance
50 |
# File 'lib/canopus/settings.rb', line 50 def reload = self.class.new(*@layers, ReloadFallback.new(values: @values)) |
#set_file(path, key, value) ⇒ instance
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/canopus/settings.rb', line 64 def set_file(path, key, value) source = File.file?(path) ? File.read(path) : "{}\n" doc = Kochab.parse(source) raise Error, "cannot edit invalid settings" unless doc.valid? key_path = key.is_a?(Array) ? key : [key] raise Error, "settings key path must contain strings" unless key_path.all? { |part| part.is_a?(String) && !part.empty? } editable_source = source (1...key_path.length).each do |length| current = Kochab.parse(editable_source) parent = key_path[0...length] next if current.range_of(parent) editable_source = Kochab.apply(editable_source, current.set(parent, {})) end doc = Kochab.parse(editable_source) replacement = Kochab.apply(editable_source, doc.set(key_path, value)) candidate = Kochab.parse(replacement) schema_errors = SCHEMA_MODEL.validate(candidate).reject { |diagnostic| diagnostic. == "Required value is missing" } raise Error, "invalid setting #{key_path.join(".")}: #{schema_errors.first.}" unless schema_errors.empty? Settings.new(candidate) FileUtils.mkdir_p(File.dirname(path)) Tempfile.create([".settings-", ".json"], File.dirname(path)) do |file| file.write(replacement) file.flush file.fsync file.close raise SaveConflict, "settings changed during save" if File.file?(path) && File.read(path) != source File.rename(file.path, path) end end |