Class: Mailmate::IndexReader

Inherits:
Object
  • Object
show all
Defined in:
lib/mailmate/index_reader.rb

Constant Summary collapse

RECORD_SIZE =
12

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ IndexReader

Returns a new instance of IndexReader.

Raises:

  • (ArgumentError)


63
64
65
66
67
68
69
70
71
72
# File 'lib/mailmate/index_reader.rb', line 63

def initialize(name)
  @name = name
  base = "#{Mailmate.config.db_headers}/#{name}"
  raise ArgumentError, "Index not found: #{name} (looked at #{base}.{cache,offsets})" \
    unless File.exist?("#{base}.cache") && File.exist?("#{base}.offsets")

  @cache_bytes   = File.binread("#{base}.cache")
  @offsets_bytes = File.binread("#{base}.offsets")
  build_index!
end

Instance Attribute Details

#nameObject (readonly)



61
62
63
# File 'lib/mailmate/index_reader.rb', line 61

def name
  @name
end

Class Method Details

.for(name) ⇒ Object

Per-process cache of readers keyed by [name, db_headers]. Including db_headers means a Mailmate.config swap (e.g. a test pointing at a different tmpdir) doesn’t return stale readers built from the old path.



36
37
38
39
# File 'lib/mailmate/index_reader.rb', line 36

def for(name)
  @cache ||= {}
  @cache[cache_key(name)] ||= new(name)
end

.reset!(name = nil) ⇒ Object

Invalidate cached readers. With no argument, drops the entire cache (useful for tests or when MailMate’s database swaps out). With a name, invalidates only entries for that name across all db_headers — the common case (cache-bust after a write) doesn’t need to thread config through.



46
47
48
49
50
51
52
# File 'lib/mailmate/index_reader.rb', line 46

def reset!(name = nil)
  if name.nil?
    @cache = nil
  elsif @cache
    @cache.delete_if { |(n, _dir), _reader| n == name }
  end
end

Instance Method Details

#each_eml_id(&block) ⇒ Object

Iterate every recorded eml-id. Yields just the id; callers that also want the value should pair this with ‘value_for`. Exists so other gem modules don’t have to reach into ‘@index` directly.



98
99
100
101
# File 'lib/mailmate/index_reader.rb', line 98

def each_eml_id(&block)
  return enum_for(:each_eml_id) unless block
  @index.each_key(&block)
end

#each_recordObject

Iterate every (eml_id, raw_value) pair. The value comes back as the bare cache substring; callers that need parsed form (e.g. flag tokens) should massage it themselves.



106
107
108
109
110
111
# File 'lib/mailmate/index_reader.rb', line 106

def each_record
  return enum_for(:each_record) unless block_given?
  @index.each_key do |eml_id|
    yield eml_id, value_for(eml_id)
  end
end

#flags_for(eml_id) ⇒ Object

‘#flags.flag` semantics: the cache stores a space-separated list of IMAP keywords. Split into individual flag tokens.



84
85
86
87
88
# File 'lib/mailmate/index_reader.rb', line 84

def flags_for(eml_id)
  v = value_for(eml_id)
  return [] if v.nil? || v.empty?
  v.split(/\s+/).reject(&:empty?)
end

#sizeObject

Number of records (mostly for diagnostics).



91
92
93
# File 'lib/mailmate/index_reader.rb', line 91

def size
  @index.size
end

#value_for(eml_id) ⇒ Object

Returns the raw cached value for a given .eml body-part ID, or nil if the message isn’t in this index.



76
77
78
79
80
# File 'lib/mailmate/index_reader.rb', line 76

def value_for(eml_id)
  pair = @index[eml_id.to_i]
  return nil unless pair
  @cache_bytes[pair[0]...pair[1]]
end