Class: MPS::Store

Inherits:
Object
  • Object
show all
Defined in:
lib/mps/store.rb

Instance Method Summary collapse

Constructor Details

#initialize(storage_dir) ⇒ Store

Returns a new instance of Store.



5
6
7
8
9
10
11
12
13
# File 'lib/mps/store.rb', line 5

def initialize(storage_dir)
  @storage_dir        = storage_dir
  @element_classes    = Elements.constants
    .map    { |k| Elements.const_get(k) }
    .select { |x| x.class == Class }
  @interpolator_classes = Interpolators.constants
    .map    { |k| Interpolators.const_get(k) }
    .select { |x| x.class == Class }
end

Instance Method Details

#all_filesObject

All .mps files in storage, sorted by filename (chronological).



57
58
59
60
61
# File 'lib/mps/store.rb', line 57

def all_files
  Dir[File.join(@storage_dir, "*.#{Constants::MPS_EXT}")]
    .select { |f| File.basename(f) =~ Constants::MPS_FILE_NAME_REGEXP }
    .sort
end

#append(type:, body:, tags: [], attrs: {}, date: Date.today) ⇒ Object

Appends a new element to today’s (or date‘s) file. Returns the file path.



48
49
50
51
52
53
54
# File 'lib/mps/store.rb', line 48

def append(type:, body:, tags: [], attrs: {}, date: Date.today)
  args_parts = attrs.map { |k, v| "#{k}: #{v}" } + Array(tags)
  args_str   = args_parts.join(", ")
  path       = find_or_create_path(date)
  File.open(path, "a") { |f| f.write("\n@#{type}[#{args_str}]{\n  #{body}\n}\n") }
  path
end

#files_since(since_date) ⇒ Object

Files whose date-stamp is >= since_date.



64
65
66
67
# File 'lib/mps/store.rb', line 64

def files_since(since_date)
  since_str = since_date.strftime("%Y%m%d")
  all_files.select { |f| File.basename(f).slice(0, 8) >= since_str }
end

#find_file(date) ⇒ Object

First .mps file found for date, or nil.



16
17
18
# File 'lib/mps/store.rb', line 16

def find_file(date)
  find_files(date).first
end

#find_files(date) ⇒ Object

All .mps files matching date (handles multiple files per day).



21
22
23
24
25
26
# File 'lib/mps/store.rb', line 21

def find_files(date)
  date_str = date.strftime("%Y%m%d")
  Dir[File.join(@storage_dir, "#{date_str}*.#{Constants::MPS_EXT}")]
    .select { |f| File.basename(f) =~ Constants::MPS_FILE_NAME_REGEXP }
    .sort
end

#find_or_create_path(date) ⇒ Object

Existing file for date, or a generated new path (file not yet created).



29
30
31
# File 'lib/mps/store.rb', line 29

def find_or_create_path(date)
  find_file(date) || File.join(@storage_dir, Constants::MPS_NEW_FILE_NAME_GEN.call(date))
end

#parse_date(date) ⇒ Object

Parsed elements hash for date. Returns {} when no file exists.



34
35
36
37
38
39
40
# File 'lib/mps/store.rb', line 34

def parse_date(date)
  path = find_file(date)
  return {} unless path
  Engines::Parser.parse_mps_file_to_elements_hash(
    path, @element_classes, interpolator_classes: @interpolator_classes
  )
end

#resolver_for(date) ⇒ Object

Returns a RefResolver built from the parsed elements for date.



43
44
45
# File 'lib/mps/store.rb', line 43

def resolver_for(date)
  RefResolver.new(parse_date(date))
end

#rewrite_element(ref_str, new_attrs, date: Date.today) ⇒ Object

Rewrites an element’s args bracket in-place and saves atomically.

ref_str may be an epoch ref (“20260428.1”) or a human ref (“task-1”). Human refs are resolved against date (defaults to today). new_attrs is a hash of attribute_name => new_value (symbol keys). Returns true on success, false if element not found or file unchanged.



92
93
94
95
96
97
98
99
100
101
102
# File 'lib/mps/store.rb', line 92

def rewrite_element(ref_str, new_attrs, date: Date.today)
  epoch_ref, path = _resolve_ref_to_path(ref_str, date)
  return false unless epoch_ref && path

  elements = Engines::Parser.parse_mps_file_to_elements_hash(path, @element_classes)
  el = elements[epoch_ref]
  return false unless el
  return false if el.is_a?(Engines::Parser::Unknown)

  _rewrite_element_in_file(path, el, new_attrs)
end

#search(query, type_filter: nil, tag_filter: nil, since_date: nil) ⇒ Object

Full-text search across files. Returns [file:, date_str:].



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/mps/store.rb', line 70

def search(query, type_filter: nil, tag_filter: nil, since_date: nil)
  files = since_date ? files_since(since_date) : all_files
  files.flat_map do |file|
    date_str = File.basename(file).slice(0, 8)
    Engines::Parser.parse_mps_file_to_elements_hash(
      file, @element_classes, interpolator_classes: @interpolator_classes
    )
      .values
      .reject { |e| e.is_a?(Elements::MPS) || e.is_a?(Engines::Parser::Unknown) }
      .select { |e| type_filter.nil? || e.class::SIGNATURE_STAMP == type_filter }
      .select { |e| tag_filter.nil?  || e.tags.include?(tag_filter) }
      .select { |e| query.nil?       || e.body_str.downcase.include?(query.downcase) }
      .map    { |e| { element: e, file: file, date_str: date_str } }
  end
end