Class: Mistri::Workspace::Single
- Inherits:
-
Object
- Object
- Mistri::Workspace::Single
- Defined in:
- lib/mistri/workspace/single.rb
Overview
One document living wherever the host says: a column on a record, a cache key, anything readable and writable. This is the shape of an agent that edits one page:
workspace = Mistri::Workspace::Single.new(
path: "page.html",
read: -> { page.reload.draft_html },
write: ->(html) { page.update!(draft_html: html) },
synchronize: lambda do |&operation|
raise "outer transaction" if page.class.connection.transaction_open?
page.with_lock(&operation)
end
)
The document tools then read and edit that column like any document. synchronize: is optional; without it, the legacy read/write port cannot protect an edit from another process writing between those two calls.
Instance Method Summary collapse
- #atomic_writes? ⇒ Boolean
- #compare_and_write(path, content, expected_revision:) ⇒ Object
- #delete(path) ⇒ Object
-
#initialize(read:, write:, path: "document", synchronize: nil) ⇒ Single
constructor
A new instance of Single.
- #list(prefix = nil) ⇒ Object
- #read(path) ⇒ Object
- #snapshot(path) ⇒ Object
- #write(path, content) ⇒ Object
Constructor Details
#initialize(read:, write:, path: "document", synchronize: nil) ⇒ Single
Returns a new instance of Single.
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/mistri/workspace/single.rb', line 25 def initialize(read:, write:, path: "document", synchronize: nil) unless synchronize.nil? || synchronize.respond_to?(:call) raise ArgumentError, "synchronize must be callable" end @path = String.new(path.to_s).freeze @read = read @write = write @synchronize = synchronize end |
Instance Method Details
#atomic_writes? ⇒ Boolean
47 |
# File 'lib/mistri/workspace/single.rb', line 47 def atomic_writes? = !@synchronize.nil? |
#compare_and_write(path, content, expected_revision:) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/mistri/workspace/single.rb', line 56 def compare_and_write(path, content, expected_revision:) verify_path!(path) unless atomic_writes? raise ConfigurationError, "Single needs synchronize: for atomic writes" end synchronize do current = @read.call actual = current.nil? ? nil : Snapshot.for(current.to_s).revision unless actual == expected_revision raise WorkspaceConflictError.new( @path, expected_revision:, actual_revision: actual ) end @write.call(content.to_s) committed = @read.call raise SchemaError, "#{@path.inspect} disappeared after write" if committed.nil? Snapshot.for(committed.to_s) end end |
#delete(path) ⇒ Object
79 80 81 82 83 84 85 86 |
# File 'lib/mistri/workspace/single.rb', line 79 def delete(path) if path.to_s == @path raise SchemaError, "#{@path.inspect} cannot be deleted, only rewritten" end nil end |
#list(prefix = nil) ⇒ Object
88 89 90 |
# File 'lib/mistri/workspace/single.rb', line 88 def list(prefix = nil) prefix.nil? || @path.start_with?(prefix.to_s) ? [@path] : [] end |
#read(path) ⇒ Object
36 37 38 |
# File 'lib/mistri/workspace/single.rb', line 36 def read(path) path.to_s == @path ? @read.call : nil end |
#snapshot(path) ⇒ Object
49 50 51 52 53 54 |
# File 'lib/mistri/workspace/single.rb', line 49 def snapshot(path) return nil unless path.to_s == @path content = @read.call content.nil? ? nil : Snapshot.for(content.to_s) end |
#write(path, content) ⇒ Object
40 41 42 43 44 45 |
# File 'lib/mistri/workspace/single.rb', line 40 def write(path, content) verify_path!(path) synchronize { @write.call(content.to_s) } nil end |