Msgthr Container


::new #add #clear #order! #thread! #walk_thread

class Msgthr

Non-recursive, container-agnostic message threading.

Usage is typically:

See for more info You may email us publically at Archives are at



raised when methods are called in an unsupported order


rootset [R]

an Array of root (parent-less) messages, only populated after calling #thread!

Public Class Methods

new () source

Initialize a Msgthr object

Public Instance Methods

add (mid, refs, msg) { |parent, child| ... } source

Adds a message to prepare a Msgthr object for threading.

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}"
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 :

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.

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)

Pages Classes Methods
mail archives: