Class: Ace::Support::Items::Molecules::FieldUpdater

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/support/items/molecules/field_updater.rb

Overview

Orchestrates –set/–add/–remove field updates on frontmatter files. Handles nested dot-key paths for –set operations. Writes atomically using temp file + rename.

Class Method Summary collapse

Class Method Details

.apply_add(frontmatter, add) ⇒ Object

Apply –add operations (append to arrays). If the existing value is a scalar, coerces it to an array first.

Parameters:

  • frontmatter (Hash)

    Frontmatter hash (mutated in place)

  • add (Hash)

    Key-value pairs to add



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ace/support/items/molecules/field_updater.rb', line 63

def self.apply_add(frontmatter, add)
  return if add.nil? || add.empty?

  add.each do |key, value|
    key_str = key.to_s
    current = frontmatter[key_str]
    values_to_add = Array(value)

    frontmatter[key_str] = (Array(current) + values_to_add).uniq
  end
end

.apply_remove(frontmatter, remove) ⇒ Object

Apply –remove operations (remove from arrays).

Parameters:

  • frontmatter (Hash)

    Frontmatter hash (mutated in place)

  • remove (Hash)

    Key-value pairs to remove

Raises:

  • (ArgumentError)

    If target field is not an array



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/ace/support/items/molecules/field_updater.rb', line 79

def self.apply_remove(frontmatter, remove)
  return if remove.nil? || remove.empty?

  remove.each do |key, value|
    key_str = key.to_s
    current = frontmatter[key_str]
    next if current.nil?

    unless current.is_a?(Array)
      raise ArgumentError, "Cannot remove from non-array field '#{key_str}' (is #{current.class})"
    end

    values_to_remove = Array(value)
    frontmatter[key_str] = current - values_to_remove
  end
end

.apply_set(frontmatter, set) ⇒ Object

Apply –set operations (supports nested dot-key paths).

Parameters:

  • frontmatter (Hash)

    Frontmatter hash (mutated in place)

  • set (Hash)

    Key-value pairs to set



46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ace/support/items/molecules/field_updater.rb', line 46

def self.apply_set(frontmatter, set)
  return if set.nil? || set.empty?

  set.each do |key, value|
    key_str = key.to_s
    if key_str.include?(".")
      apply_nested_set(frontmatter, key_str, value)
    else
      frontmatter[key_str] = value
    end
  end
end

.update(file_path, set: {}, add: {}, remove: {}) ⇒ Hash

Update frontmatter fields in a spec file.

Parameters:

  • file_path (String)

    Path to the spec file

  • set (Hash) (defaults to: {})

    Fields to set (key => value). Supports dot-notation for nested keys.

  • add (Hash) (defaults to: {})

    Fields to append to arrays (key => value or array of values).

  • remove (Hash) (defaults to: {})

    Fields to remove from arrays (key => value or array of values).

Returns:

  • (Hash)

    Updated frontmatter hash



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/ace/support/items/molecules/field_updater.rb', line 22

def self.update(file_path, set: {}, add: {}, remove: {})
  File.open(file_path, File::RDWR) do |file|
    file.flock(File::LOCK_EX)

    file.rewind
    content = file.read
    frontmatter, body = Atoms::FrontmatterParser.parse(content)
    # Strip leading newline from body so rebuild doesn't double-space
    body = body.sub(/\A\n/, "")

    apply_set(frontmatter, set)
    apply_add(frontmatter, add)
    apply_remove(frontmatter, remove)

    new_content = Atoms::FrontmatterSerializer.rebuild(frontmatter, body)
    rewrite_locked_file(file, new_content)

    frontmatter
  end
end