Class: HunkReviewChanges::State

Inherits:
Object
  • Object
show all
Defined in:
lib/hunk_review_changes/state.rb

Overview

Per-piece review state (comment, flag, reviewed), persisted as state.json next to the bundle so a closed tab loses nothing and re-running the same bundle resumes.

State is scoped to a bundle fingerprint: when a directory is reused for a different (or overwritten) bundle, the previous review's comments are discarded rather than replayed against unrelated pieces that happen to share an id.

Status precedence, highest first:

flag        - checked "flag for discussion"
change      - has a non-blank comment
ok          - reviewed and left as-is ("Looks good")
unreviewed  - not yet looked at

Constant Summary collapse

STATUSES =
%w[flag change ok unreviewed].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, bundle_id: nil) ⇒ State

Returns a new instance of State.



30
31
32
33
34
# File 'lib/hunk_review_changes/state.rb', line 30

def initialize(path, bundle_id: nil)
  @path = path
  @bundle_id = bundle_id
  @entries = load_entries
end

Class Method Details

.actionable?(entry) ⇒ Boolean

Status counts a piece needs the agent to act on (everything but ok/unreviewed).

Returns:

  • (Boolean)


69
70
71
72
# File 'lib/hunk_review_changes/state.rb', line 69

def self.actionable?(entry)
  status = status_for(entry)
  %w[flag change].include?(status)
end

.lock_for(path) ⇒ Object



26
27
28
# File 'lib/hunk_review_changes/state.rb', line 26

def self.lock_for(path)
  @locks_guard.synchronize { @locks[path] ||= Mutex.new }
end

.status_for(entry) ⇒ Object



60
61
62
63
64
65
66
# File 'lib/hunk_review_changes/state.rb', line 60

def self.status_for(entry)
  return "flag" if entry && entry["flag"]
  return "change" if entry && entry["comment"].to_s.strip != ""
  return "ok" if entry && entry["reviewed"]

  "unreviewed"
end

Instance Method Details

#[](id) ⇒ Object



36
37
38
# File 'lib/hunk_review_changes/state.rb', line 36

def [](id)
  @entries[id.to_s] || {}
end

#status(id) ⇒ Object



56
57
58
# File 'lib/hunk_review_changes/state.rb', line 56

def status(id)
  self.class.status_for(self[id])
end

#update(id, comment:, flag:, reviewed:) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/hunk_review_changes/state.rb', line 40

def update(id, comment:, flag:, reviewed:)
  entry = {
    "comment" => comment.to_s,
    "flag" => !!flag,
    "reviewed" => !!reviewed
  }
  # Serialize the whole read-modify-write: re-read the current file so a save
  # racing on another thread merges its piece instead of overwriting it.
  self.class.lock_for(@path).synchronize do
    @entries = load_entries
    @entries[id.to_s] = entry
    save
  end
  self.class.status_for(entry)
end