Non-recursive, container-agnostic message threading.
Usage is typically:
use ::new to create a new object
use Msgthr#add! for every message you have
use #thread! to perform threading and (optionally) sort
use #walk_thread to iterate through the threaded tree
See 80x24.org/msgthr/README for more info You may email us publically at msgthr-public@80x24.org Archives are at 80x24.org/msgthr-public/
raised when methods are called in an unsupported order
an Array of root (parent-less) messages, only populated after calling #thread!
new () source
Initialize a Msgthr object
add (mid, refs, msg) { |parent, child| ... } source
Adds a message to prepare a Msgthr object for threading.
mid
is a unique identifier for the message in a given thread.
It is typically a String or Integer, but may be anything usable as a Hash
key in Ruby.
refs
should be an Array of unique identifiers belonging to
ancestors of the current message. For mail and news messages, this is
usually the parsed result of the "References:" header. Order should be
oldest to newest in terms of ancestry, with the last element being the
immediate parent of the given message.
This is nil
for messages with no parent (root messages).
msg
is an opaque object which typically contains a Mail or
Tmail object for handling mail.
If mid
is a String, it is recommended to freeze the string
before calling this method to avoid wasting memory on hash keys. Likewise
is true for any String objects in refs
.
Adding a message could link 2 messages in Msgthr, by making one message a child of the other. It's possible to have a callback called when a child is added by passing a block to this method. This block can access the child and parent messages. E.g.
msgthr.add(0, nil, '0') msgthr.add(1, [0], '1') do |parent, child| puts "#{parent.mid} -> #{child.mid}" end
clear () source
Clear internal data structures to save memory and prepare for reuse
order! () { |rootset| ... } source
Calling this method is unnecessary since msgthr 1.1.0. In previous releases, the thread! did not support a block parameter for ordering. This method remains for compatibility.
thread! () { |ary| ... } source
Performs threading on the messages and returns the rootset (set of message containers without parents).
Call this only after all add operations are complete.
If given an optional block, it will perform an in-place sort using the block parameter.
To thread and sort by unique mid
identifiers for each
container:
msgthr.thread! { |ary| ary.sort_by!(&:mid) }
If your opaque message pointer contains a time
accessor which
gives a Time object:
msgthr.thread! do |ary| ary.sort_by! do |cont| # Msgthr::Container cur = cont.topmost cur ? cur.msg.time : Time.at(0) end end
Note, using Msgthr::Container#topmost
is NOT necessary when accessing Msgthr::Container#mid, as
any known missing messages (ghosts) will still have a mid
.
However, Msgthr::Container#topmost
is necessary if accessing Msgthr::Container#msg.
walk_thread () { |level, cont, idx| ... } source
non-recursively walk a set of messages after thread! (and optionally, order!).
If you do not care about ordering, you may call this immediately after all add operations are complete starting with msgthr 1.1.0
This takes a block and yields 3 elements to it: +|level, container, index|+ for each message container.
level
is the current depth within the walk (non-negative
Integer)
container
is the Msgthr::Container object
index
is the offset of the container within its level
(starting at 0)
To display the subject of each message with indentation, assuming your
msg
pointer has a subject
field:
msgthr.walk_thread do |level, container, index| msg = container.msg subject = msg ? msg.subject : "[missing: <#{container.mid}>]" indent = ' ' * level printf("#{indent} % 3d. %s\n", index, subject) end
mail archives: https://80x24.org/msgthr-public/ public: msgthr-public@80x24.org