Class: Textus::Manifest
- Inherits:
-
Object
- Object
- Textus::Manifest
- Defined in:
- lib/textus/manifest.rb,
lib/textus/manifest/entry.rb,
lib/textus/manifest/rules.rb,
lib/textus/manifest/schema.rb,
lib/textus/manifest/entry/parser.rb,
lib/textus/manifest/entry/validators.rb,
lib/textus/manifest/entry/validators/events.rb,
lib/textus/manifest/entry/validators/inject_intro.rb,
lib/textus/manifest/entry/validators/publish_each.rb,
lib/textus/manifest/entry/validators/format_matrix.rb,
lib/textus/manifest/entry/validators/index_filename.rb
Defined Under Namespace
Modules: Schema Classes: Entry, Rules
Constant Summary collapse
- TEXTUS_2_HINT =
"Install textus 0.11.x to run the migrator, then upgrade to this version. " \ "See https://github.com/patrick204nqh/textus/blob/main/CHANGELOG.md#0110".freeze
Instance Attribute Summary collapse
-
#entries ⇒ Object
readonly
Returns the value of attribute entries.
-
#raw ⇒ Object
readonly
Returns the value of attribute raw.
-
#root ⇒ Object
readonly
Returns the value of attribute root.
Class Method Summary collapse
Instance Method Summary collapse
-
#enumerate(prefix: nil) ⇒ Object
Enumerate all entry files reachable through the manifest.
-
#initialize(root, raw) ⇒ Manifest
constructor
A new instance of Manifest.
- #permission_for(zone_name) ⇒ Object
-
#resolve(key) ⇒ Object
Returns [Manifest::Entry, resolved_path, remaining_segments].
- #rules ⇒ Object
- #rules_for(key) ⇒ Object
-
#suggestions_for(key) ⇒ Object
Returns up to 5 dotted keys from the manifest that look similar to the requested key, ranked by shared-prefix length then Levenshtein distance.
- #validate_key!(key) ⇒ Object
- #zone_readers ⇒ Object
- #zone_writers(zone_name) ⇒ Object
- #zones ⇒ Object
Constructor Details
#initialize(root, raw) ⇒ Manifest
Returns a new instance of Manifest.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/textus/manifest.rb', line 66 def initialize(root, raw) @root = root @raw = raw raise BadFrontmatter.new(File.join(root, "manifest.yaml"), "manifest must declare zones:") if Array(raw["zones"]).empty? Schema.validate!(raw) @entries = Array(raw["entries"]).map do |e| entry = Manifest::Entry::Parser.call(self, e) Manifest::Entry::Validators.run_all(entry) entry end validate_declared_keys! end |
Instance Attribute Details
#entries ⇒ Object (readonly)
Returns the value of attribute entries.
15 16 17 |
# File 'lib/textus/manifest.rb', line 15 def entries @entries end |
#raw ⇒ Object (readonly)
Returns the value of attribute raw.
15 16 17 |
# File 'lib/textus/manifest.rb', line 15 def raw @raw end |
#root ⇒ Object (readonly)
Returns the value of attribute root.
15 16 17 |
# File 'lib/textus/manifest.rb', line 15 def root @root end |
Class Method Details
.load(root) ⇒ Object
46 47 48 49 50 51 52 53 |
# File 'lib/textus/manifest.rb', line 46 def self.load(root) manifest_path = File.join(root, "manifest.yaml") raise IoError.new("manifest not found: #{manifest_path}") unless File.exist?(manifest_path) raw = YAML.safe_load_file(manifest_path, aliases: false) check_version!(raw, manifest_path) new(root, raw) end |
.parse(yaml_text, root: ".") ⇒ Object
40 41 42 43 44 |
# File 'lib/textus/manifest.rb', line 40 def self.parse(yaml_text, root: ".") raw = YAML.safe_load(yaml_text, aliases: false) check_version!(raw, "<string>") new(root, raw) end |
Instance Method Details
#enumerate(prefix: nil) ⇒ Object
Enumerate all entry files reachable through the manifest. Returns
- { key:, path:, manifest_entry: }, …
132 133 134 135 136 |
# File 'lib/textus/manifest.rb', line 132 def enumerate(prefix: nil) out = @entries.flat_map { |entry| entry.nested ? enumerate_nested(entry) : enumerate_leaf(entry) } out.select! { |row| row[:key] == prefix || row[:key].start_with?("#{prefix}.") } if prefix out.sort_by { |row| row[:key] } end |
#permission_for(zone_name) ⇒ Object
32 33 34 35 36 37 38 |
# File 'lib/textus/manifest.rb', line 32 def (zone_name) Textus::Domain::Permission.new( zone: zone_name, write_policy: zone_writers(zone_name), read_policy: zone_readers[zone_name] || :all, ) end |
#resolve(key) ⇒ Object
Returns [Manifest::Entry, resolved_path, remaining_segments]
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/textus/manifest.rb', line 90 def resolve(key) validate_key!(key) segments = key.split(".") # longest-prefix match candidates = @entries .map { |e| [e, e.key.split(".")] } .select { |(_, esegs)| esegs == segments[0, esegs.length] } .sort_by { |(_, esegs)| -esegs.length } raise UnknownKey.new(key, suggestions: suggestions_for(key)) if candidates.empty? entry, esegs = candidates.first remaining = segments[esegs.length..] if remaining.empty? path = resolve_leaf_path(entry) [entry, path, []] else raise UnknownKey.new(key, suggestions: suggestions_for(key)) unless entry.nested path = if entry.index_filename File.join(@root, "zones", entry.path, *remaining, entry.index_filename) else primary_ext = Textus::Entry.for_format(entry.format).extensions.first File.join(@root, "zones", entry.path, *remaining) + primary_ext end [entry, path, remaining] end end |
#rules ⇒ Object
81 82 83 |
# File 'lib/textus/manifest.rb', line 81 def rules @rules ||= Textus::Manifest::Rules.parse(@raw["rules"] || []) end |
#rules_for(key) ⇒ Object
85 86 87 |
# File 'lib/textus/manifest.rb', line 85 def rules_for(key) rules.for(key) end |
#suggestions_for(key) ⇒ Object
Returns up to 5 dotted keys from the manifest that look similar to the requested key, ranked by shared-prefix length then Levenshtein distance.
120 121 122 123 124 125 126 127 128 |
# File 'lib/textus/manifest.rb', line 120 def suggestions_for(key) candidates = enumerate.map { |r| r[:key] } # Include declared (non-nested) entry keys even if file is missing. candidates.concat(@entries.reject(&:nested).map(&:key)) candidates.uniq! Key::Distance.suggest(key, candidates, limit: 5) rescue StandardError [] end |
#validate_key!(key) ⇒ Object
138 139 140 141 142 |
# File 'lib/textus/manifest.rb', line 138 def validate_key!(key) raise UsageError.new("empty key") if key.nil? || key.empty? Key::Grammar.validate!(key) end |
#zone_readers ⇒ Object
21 22 23 24 25 26 |
# File 'lib/textus/manifest.rb', line 21 def zone_readers @zone_readers ||= Array(@raw["zones"]).to_h do |z| rp = z["read_policy"] [z["name"], rp.nil? ? :all : Array(rp)] end end |
#zone_writers(zone_name) ⇒ Object
28 29 30 |
# File 'lib/textus/manifest.rb', line 28 def zone_writers(zone_name) zones[zone_name] or raise UsageError.new("undeclared zone '#{zone_name}'") end |
#zones ⇒ Object
17 18 19 |
# File 'lib/textus/manifest.rb', line 17 def zones @zones ||= Array(@raw["zones"]).to_h { |z| [z["name"], Array(z["write_policy"])] } end |