Class: Textus::Store

Inherits:
Object
  • Object
show all
Defined in:
lib/textus/store.rb,
lib/textus/store/view.rb,
lib/textus/store/mover.rb,
lib/textus/store/reader.rb,
lib/textus/store/writer.rb,
lib/textus/store/audit_log.rb,
lib/textus/store/staleness.rb,
lib/textus/store/validator.rb

Defined Under Namespace

Classes: AuditLog, Mover, Reader, Staleness, Validator, View, Writer

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root) ⇒ Store

Returns a new instance of Store.



39
40
41
42
43
44
45
46
47
48
# File 'lib/textus/store.rb', line 39

def initialize(root)
  @root = File.expand_path(root)
  @manifest = Manifest.load(@root)
  @bus = Hooks::Dispatcher.new(audit_log: audit_log)
  @registry = Hooks::Registry.new(dispatcher: @bus)
  @schemas = {}
  load_extensions
  @reader = Reader.new(self)
  @writer = Writer.new(self)
end

Instance Attribute Details

#busObject (readonly)

Returns the value of attribute bus.



6
7
8
# File 'lib/textus/store.rb', line 6

def bus
  @bus
end

#manifestObject (readonly)

Returns the value of attribute manifest.



6
7
8
# File 'lib/textus/store.rb', line 6

def manifest
  @manifest
end

#readerObject (readonly)

Returns the value of attribute reader.



6
7
8
# File 'lib/textus/store.rb', line 6

def reader
  @reader
end

#registryObject (readonly)

Returns the value of attribute registry.



6
7
8
# File 'lib/textus/store.rb', line 6

def registry
  @registry
end

#rootObject (readonly)

Returns the value of attribute root.



6
7
8
# File 'lib/textus/store.rb', line 6

def root
  @root
end

#writerObject (readonly)

Returns the value of attribute writer.



6
7
8
# File 'lib/textus/store.rb', line 6

def writer
  @writer
end

Class Method Details

.discover(start_dir = Dir.pwd, root: nil) ⇒ Object

Raises:



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/textus/store.rb', line 15

def self.discover(start_dir = Dir.pwd, root: nil)
  explicit = root || ENV.fetch("TEXTUS_ROOT", nil)
  return discover_explicit(explicit) if explicit

  dir = File.expand_path(start_dir)
  loop do
    candidate = File.join(dir, ".textus")
    return new(candidate) if File.directory?(candidate) && File.exist?(File.join(candidate, "manifest.yaml"))

    parent = File.dirname(dir)
    break if parent == dir

    dir = parent
  end
  raise IoError.new("no .textus directory found from #{start_dir}")
end

.mint_uidObject

A Textus UID: 16 lowercase hex chars (SecureRandom.hex(8)). Not a UUID —short on purpose. Random enough for collision-never-in-practice within a single store.



11
12
13
# File 'lib/textus/store.rb', line 11

def self.mint_uid
  SecureRandom.hex(8)
end

Instance Method Details

#acceptObject



94
# File 'lib/textus/store.rb', line 94

def accept(...) = @writer.accept(...)

#audit_logObject



112
113
114
# File 'lib/textus/store.rb', line 112

def audit_log
  @audit_log ||= Store::AuditLog.new(@root)
end

#deleteObject



87
# File 'lib/textus/store.rb', line 87

def delete(...) = @writer.delete(...)

#deps(key) ⇒ Object



96
# File 'lib/textus/store.rb', line 96

def deps(key)    = @reader.deps(key)

#fire_event(event) ⇒ Object



89
90
91
92
# File 'lib/textus/store.rb', line 89

def fire_event(event, **)
  view = Store::View.new(self)
  @bus.publish(event, store: view, **)
end

#get(key) ⇒ Object



77
78
79
# File 'lib/textus/store.rb', line 77

def get(key)
  @reader.get(key)
end

#listObject



82
# File 'lib/textus/store.rb', line 82

def list(**) = @reader.list(**)

#load_extensionsObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/textus/store.rb', line 50

def load_extensions
  Textus.with_registry(@registry) do
    Hooks::Builtin.register_all
    dir = File.join(@root, "hooks")
    return unless File.directory?(dir)

    Dir.glob(File.join(dir, "*.rb")).sort.each do |f| # rubocop:disable Lint/RedundantDirGlobSort
      begin
        load(f)
      rescue StandardError, ScriptError => e
        raise UsageError.new("failed loading extension #{File.basename(f)}: #{e.class}: #{e.message}")
      end
    end
  end
end

#mv(old_key, new_key, as: Role::DEFAULT, dry_run: false) ⇒ Object

Move an entry from old_key to new_key within the same zone. Preserves uid (minting one first if absent), validates both keys against the manifest, refuses to clobber, and writes one mv audit row.



107
108
109
110
# File 'lib/textus/store.rb', line 107

def mv(old_key, new_key, as: Role::DEFAULT, dry_run: false)
  Mover.new(reader: @reader, writer: @writer, manifest: @manifest, audit_log: audit_log)
       .call(old_key, new_key, as: as, dry_run: dry_run)
end

#publishedObject



98
# File 'lib/textus/store.rb', line 98

def published    = @reader.published

#putObject



85
# File 'lib/textus/store.rb', line 85

def put(...) = @writer.put(...)

#rdeps(key) ⇒ Object



97
# File 'lib/textus/store.rb', line 97

def rdeps(key)   = @reader.rdeps(key)

#schema_envelope(key) ⇒ Object



83
# File 'lib/textus/store.rb', line 83

def schema_envelope(key) = @reader.schema_envelope(key)

#schema_for(name) ⇒ Object



66
67
68
69
70
71
72
73
74
75
# File 'lib/textus/store.rb', line 66

def schema_for(name)
  return nil if name.nil?

  @schemas[name] ||= begin
    sp = File.join(@root, "schemas", "#{name}.yaml")
    raise IoError.new("schema not found: #{sp}") unless File.exist?(sp)

    Schema.load(sp)
  end
end

#staleObject



99
# File 'lib/textus/store.rb', line 99

def stale(**)    = @reader.stale(**)

#uid(key) ⇒ Object



102
# File 'lib/textus/store.rb', line 102

def uid(key) = @reader.uid(key)

#validate_allObject



100
# File 'lib/textus/store.rb', line 100

def validate_all = @reader.validate_all

#where(key) ⇒ Object



81
# File 'lib/textus/store.rb', line 81

def where(key) = @reader.where(key)