Class: Coat::Ledger
- Inherits:
-
Object
- Object
- Coat::Ledger
- Defined in:
- lib/coat/ledger.rb
Overview
Append-only record of collected pieces, one JSON object per line. Each
entry carries the hash of the entry before it, so editing, reordering, or
deleting history breaks the chain and first_break says where.
A coat is evidence of what agents did. Its provenance has to be at least as hard to quietly rewrite as the work it describes.
Constant Summary collapse
- GENESIS =
"0" * 64
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Instance Method Summary collapse
-
#append(fields) ⇒ Object
Holds an exclusive lock across both the read of the tail and the write, so two agents adding pieces at once cannot fork the chain.
- #entries ⇒ Object
-
#first_break ⇒ Object
The sequence number of the first entry whose link does not hold, or nil when the chain is intact end to end.
-
#initialize(path) ⇒ Ledger
constructor
A new instance of Ledger.
Constructor Details
#initialize(path) ⇒ Ledger
Returns a new instance of Ledger.
19 20 21 22 |
# File 'lib/coat/ledger.rb', line 19 def initialize(path) @path = path FileUtils.mkdir_p(File.dirname(path)) end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
17 18 19 |
# File 'lib/coat/ledger.rb', line 17 def path @path end |
Instance Method Details
#append(fields) ⇒ Object
Holds an exclusive lock across both the read of the tail and the write, so two agents adding pieces at once cannot fork the chain.
26 27 28 29 30 31 32 33 |
# File 'lib/coat/ledger.rb', line 26 def append(fields) File.open(@path, File::RDWR | File::CREAT, 0o644) do |file| file.flock(File::LOCK_EX) entry = seal(fields, parse(file.read).last) file.write("#{JSON.generate(entry)}\n") entry end end |
#entries ⇒ Object
35 36 37 38 39 |
# File 'lib/coat/ledger.rb', line 35 def entries return [] unless File.exist?(@path) parse(File.read(@path)) end |
#first_break ⇒ Object
The sequence number of the first entry whose link does not hold, or nil when the chain is intact end to end.
43 44 45 46 47 48 49 50 51 |
# File 'lib/coat/ledger.rb', line 43 def first_break previous = nil entries.each do |entry| return entry["seq"] unless intact?(entry, previous) previous = entry end nil end |