Class: Redwood::ThreadSet
Overview
A set of threads (so a forest). Builds thread structures by reading messages from an index.
If ‘thread_by_subj’ is true, puts messages with the same subject in one thread, even if they don’t reference each other. This is helpful for crappy MUAs that don’t set In-reply-to: or References: headers, but means that messages may be threaded unnecessarily.
Instance Attribute Summary collapse
-
#num_messages ⇒ Object
readonly
Returns the value of attribute num_messages.
Instance Method Summary collapse
-
#add_message(message) ⇒ Object
the heart of the threading code.
-
#add_thread(t) ⇒ Object
merges in a pre-loaded thread.
- #contains_id?(id) ⇒ Boolean
-
#dump(f) ⇒ Object
unused.
-
#initialize(index, thread_by_subj = true) ⇒ ThreadSet
constructor
A new instance of ThreadSet.
- #is_relevant?(m) ⇒ Boolean
-
#load_n_threads(num, opts = {}) ⇒ Object
load in (at most) num number of threads from the index.
-
#load_thread_for_message(m, opts = {}) ⇒ Object
loads in all messages needed to thread m may do nothing if m’s thread is killed.
- #remove(mid) ⇒ Object
- #size ⇒ Object
- #thread_for(m) ⇒ Object
- #threads ⇒ Object
Constructor Details
#initialize(index, thread_by_subj = true) ⇒ ThreadSet
Returns a new instance of ThreadSet.
245 246 247 248 249 250 251 252 253 |
# File 'lib/sup/thread.rb', line 245 def initialize index, thread_by_subj=true @index = index = 0 ## map from message ids to container objects = SavingHash.new { |id| Container.new id } ## map from subject strings or (or root message ids) to thread objects @threads = SavingHash.new { Thread.new } @thread_by_subj = thread_by_subj end |
Instance Attribute Details
#num_messages ⇒ Object (readonly)
Returns the value of attribute num_messages.
242 243 244 |
# File 'lib/sup/thread.rb', line 242 def end |
Instance Method Details
#add_message(message) ⇒ Object
the heart of the threading code
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/sup/thread.rb', line 339 def el = [.id] return if el. # we've seen it before el. = oldroot = el.root ## link via references: prev = nil .refs.each do |ref_id| ref = [ref_id] link prev, ref if prev prev = ref end link prev, el, true if prev ## link via in-reply-to: .replytos.each do |ref_id| ref = [ref_id] link ref, el, true break # only do the first one end root = el.root ## new root. need to drop old one and put this one in its place if root != oldroot && oldroot.thread oldroot.thread.drop oldroot oldroot.thread = nil end key = if thread_by_subj? Message.normalize_subj root.subj else root.id end ## check to see if the subject is still the same (in the case ## that we first added a child message with a different ## subject) if root.thread unless @threads[key] == root.thread if @threads[key] root.thread.empty! @threads[key] << root root.thread = @threads[key] else @threads[key] = root.thread end end else thread = @threads[key] thread << root root.thread = thread end ## last bit += 1 end |
#add_thread(t) ⇒ Object
merges in a pre-loaded thread
329 330 331 332 |
# File 'lib/sup/thread.rb', line 329 def add_thread t raise "duplicate" if @threads.values.member? t t.each { |m, *o| m } end |
#contains_id?(id) ⇒ Boolean
255 |
# File 'lib/sup/thread.rb', line 255 def contains_id? id; .member?(id) && ![id].empty?; end |
#dump(f) ⇒ Object
unused
269 270 271 272 273 274 275 276 |
# File 'lib/sup/thread.rb', line 269 def dump f @threads.each do |s, t| f.puts "**********************" f.puts "** for subject #{s} **" f.puts "**********************" t.dump f end end |
#is_relevant?(m) ⇒ Boolean
334 335 336 |
# File 'lib/sup/thread.rb', line 334 def is_relevant? m m.refs.any? { |ref_id| .member? ref_id } end |
#load_n_threads(num, opts = {}) ⇒ Object
load in (at most) num number of threads from the index
307 308 309 310 311 312 313 314 315 316 |
# File 'lib/sup/thread.rb', line 307 def load_n_threads num, opts={} @index.each_id_by_date opts do |mid, builder| break if size >= num next if contains_id? mid m = builder.call m, :skip_killed => opts[:skip_killed], :load_deleted => opts[:load_deleted], :load_spam => opts[:load_spam] yield size if block_given? end end |
#load_thread_for_message(m, opts = {}) ⇒ Object
loads in all messages needed to thread m may do nothing if m’s thread is killed
320 321 322 323 324 325 326 |
# File 'lib/sup/thread.rb', line 320 def m, opts={} good = @index. m, opts do |mid, builder| next if contains_id? mid builder.call end m if good end |
#remove(mid) ⇒ Object
296 297 298 299 300 301 302 303 304 |
# File 'lib/sup/thread.rb', line 296 def remove mid return unless(c = [mid]) c.parent.children.delete c if c.parent if c.thread c.thread.drop c c.thread = nil end end |
#size ⇒ Object
266 |
# File 'lib/sup/thread.rb', line 266 def size; delete_cruft; @threads.size; end |
#thread_for(m) ⇒ Object
256 257 258 |
# File 'lib/sup/thread.rb', line 256 def thread_for m (c = [m.id]) && c.root.thread end |
#threads ⇒ Object
265 |
# File 'lib/sup/thread.rb', line 265 def threads; delete_cruft; @threads.values; end |