for 0.0.9
---------
+_ add arbitrary labels to sources
_ detect other sup instances and do something intelligent (because ferret crashes violently with more than one index writer open)
_ bugfix: need a way to force an address to a particular name, for things like evite addresses
_ bugfix: read before thread-index has finished loading then hides the thread?!? wtf. (on jamie)
end
end
+class Module
+ def yaml_properties *props
+ props = props.map { |p| p.to_s }
+ vars = props.map { |p| "@#{p}" }
+ klass = self
+ path = klass.name.gsub(/::/, "/")
+
+ klass.instance_eval do
+ define_method(:to_yaml_properties) { vars }
+ define_method(:to_yaml_type) { "!#{Redwood::YAML_DOMAIN},#{Redwood::YAML_DATE}/#{path}" }
+ end
+
+ YAML.add_domain_type("#{Redwood::YAML_DOMAIN},#{Redwood::YAML_DATE}", path) do |type, val|
+ klass.new(*props.map { |p| val[p] })
+ end
+ end
+end
+
module Redwood
VERSION = "0.0.8"
module_function :reporting_thread
## one-stop shop for yamliciousness
- def register_yaml klass, props
- vars = props.map { |p| "@#{p}" }
- path = klass.name.gsub(/::/, "/")
-
- klass.instance_eval do
- define_method(:to_yaml_properties) { vars }
- define_method(:to_yaml_type) { "!#{YAML_DOMAIN},#{YAML_DATE}/#{path}" }
- end
-
- YAML.add_domain_type("#{YAML_DOMAIN},#{YAML_DATE}", path) do |type, val|
- klass.new(*props.map { |p| val[p] })
- end
- end
-
def save_yaml_obj object, fn, compress=false
if compress
Zlib::GzipWriter.open(fn) { |f| f.puts object.to_yaml }
end
end
- module_function :register_yaml, :save_yaml_obj, :load_yaml_obj, :start, :finish, :report_broken_sources
+ module_function :save_yaml_obj, :load_yaml_obj, :start, :finish, :report_broken_sources
end
## set up default configuration file
class DraftLoader < Source
attr_accessor :dir
+ yaml_properties :cur_offset
def initialize cur_offset=0
dir = Redwood::DRAFT_DIR
end
end
-Redwood::register_yaml(DraftLoader, %w(cur_offset))
-
end
## of the spec actually happens in practice. you'll request flags for
## one message, and get it interspersed with a random bunch of flags
## for some other messages, including a different set of flags for the
-## same message! totally ok by the imap spec. totally retarded.
+## same message! totally ok by the imap spec. totally retarded by any
+## other metric.
##
## fuck you, imap committee. you managed to design something nearly as
## shitty as mbox but goddamn THIRTY YEARS LATER.
RECOVERABLE_ERRORS = [ Errno::EPIPE, Errno::ETIMEDOUT, OpenSSL::SSL::SSLError ]
attr_accessor :username, :password
+ yaml_properties :uri, :username, :password, :cur_offset, :usual,
+ :archived, :id
def initialize uri, username, password, last_idate=nil, usual=true, archived=false, id=nil
raise ArgumentError, "username and password must be specified" unless username && password
end
-Redwood::register_yaml(IMAP, %w(uri username password cur_offset usual archived id))
-
end
File.chmod 0600, fn
FileUtils.mv fn, bakfn, :force => true unless File.exists?(bakfn) && File.size(bakfn) > File.size(fn)
end
- Redwood::save_yaml_obj @sources.values, fn
+ Redwood::save_yaml_obj @sources.values.sort_by { |s| s.id.to_i }, fn
File.chmod 0600, fn
end
@sources_dirty = false
class Maildir < Source
SCAN_INTERVAL = 30 # seconds
+ yaml_properties :uri, :cur_offset, :usual, :archived, :id
def initialize uri, last_date=nil, usual=true, archived=false, id=nil
super
uri = URI(uri)
end
end
-Redwood::register_yaml(Maildir, %w(uri cur_offset usual archived id))
-
end
module MBox
class Loader < Source
+ yaml_properties :uri, :cur_offset, :usual, :archived, :id
def initialize uri_or_fp, start_offset=nil, usual=true, archived=false, id=nil
super
end
end
-Redwood::register_yaml(Loader, %w(uri cur_offset usual archived id))
-
end
end
class SSHLoader < Source
attr_accessor :username, :password
+ yaml_properties :uri, :username, :password, :cur_offset, :usual,
+ :archived, :id
+
def initialize uri, username=nil, password=nil, start_offset=nil, usual=true, archived=false, id=nil
raise ArgumentError, "not an mbox+ssh uri: #{uri.inspect}" unless uri =~ %r!^mbox\+ssh://!
end
end
-Redwood::register_yaml(SSHLoader, %w(uri username password cur_offset usual archived id))
-
end
end
end
class SentLoader < MBox::Loader
+ yaml_properties :cur_offset
+
def initialize cur_offset=0
filename = Redwood::SENT_FN
File.open(filename, "w") { } unless File.exists? filename
def labels; [:sent, :inbox]; end
end
-Redwood::register_yaml(SentLoader, %w(cur_offset))
-
end
class FatalSourceError < SourceError; end
class Source
- ## Implementing a new source is typically quite easy, because Sup
- ## only needs to be able to:
+ ## Implementing a new source should be easy, because Sup only needs
+ ## to be able to:
## 1. See how many messages it contains
## 2. Get an arbitrary message
## 3. (optional) see whether the source has marked it read or not
##
## In particular, Sup doesn't need to move messages, mark them as
- ## read, delete them, or anything else. (Well, at some point it will
- ## need to delete them, but that will be an optional capability.)
+ ## read, delete them, or anything else. (Well, it's nice to be able
+ ## to delete them, but that is optional.)
##
## On the other hand, Sup assumes that you can assign each message a
## unique integer id, such that newer messages have higher ids than
## - raw_header offset
## - raw_full_message offset
## - check
- ## - next (or each, if you prefer)
+ ## - next (or each, if you prefer): should return a message and an
+ ## array of labels.
##
## ... where "offset" really means unique id. (You can tell I
## started with mbox.)
## else (e.g. the imap server is down or the maildir is missing.)
##
## Finally, be sure the source is thread-safe, since it WILL be
- ## pummeled from multiple threads at once.
+ ## pummelled from multiple threads at once.
##
## Examples for you to look at: mbox/loader.rb, imap.rb, and
## maildir.rb.
end
end
-Redwood::register_yaml(Source, %w(uri cur_offset usual archived id))
-
end
## h2[:a].val # => 0
## h2[:a].val = 1
## h2[:a].val # => 1
+##
+## important note: you REALLY want to use #member? to test existence,
+## because just checking h[anything] will always evaluate to true
+## (except for degenerate constructor blocks that return nil or false)
class SavingHash
def initialize &b
@constructor = b