lib/sup/util.rb in sup-0.3 vs lib/sup/util.rb in sup-0.4

- old
+ new

@@ -1,5 +1,6 @@ +require 'thread' require 'lockfile' require 'mime/types' require 'pathname' ## time for some monkeypatching! @@ -35,20 +36,11 @@ begin size rescue SystemCallError return "?" end - - if s < 1024 - s.to_s + "b" - elsif s < (1024 * 1024) - (s / 1024).to_s + "k" - elsif s < (1024 * 1024 * 1024) - (s / 1024 / 1024).to_s + "m" - else - (s / 1024 / 1024 / 1024).to_s + "g" - end + s.to_human_size end def human_time begin ctime.strftime("%Y-%m-%d %H:%M") @@ -61,38 +53,40 @@ ## more monkeypatching! module RMail class EncodingUnsupportedError < StandardError; end class Message - def add_file_attachment fn + def self.make_file_attachment fn bfn = File.basename fn - a = Message.new t = MIME::Types.type_for(bfn).first || MIME::Types.type_for("exe").first + make_attachment IO.read(fn), t.content_type, t.encoding, bfn.to_s + end - a.header.add "Content-Disposition", "attachment; filename=#{bfn.to_s.inspect}" - a.header.add "Content-Type", "#{t.content_type}; name=#{bfn.to_s.inspect}" - a.header.add "Content-Transfer-Encoding", t.encoding + def charset + if header.field?("content-type") && header.fetch("content-type") =~ /charset="?(.*?)"?(;|$)/i + $1 + end + end + + def self.make_attachment payload, mime_type, encoding, filename + a = Message.new + a.header.add "Content-Disposition", "attachment; filename=#{filename.inspect}" + a.header.add "Content-Type", "#{mime_type}; name=#{filename.inspect}" + a.header.add "Content-Transfer-Encoding", encoding if encoding a.body = - case t.encoding + case encoding when "base64" - [IO.read(fn)].pack "m" + [payload].pack "m" when "quoted-printable" - [IO.read(fn)].pack "M" - when "7bit", "8bit" - IO.read(fn) + [payload].pack "M" + when "7bit", "8bit", nil + payload else - raise EncodingUnsupportedError, t.encoding + raise EncodingUnsupportedError, encoding.inspect end - - add_part a + a end - - def charset - if header.field?("content-type") && header.fetch("content-type") =~ /charset="?(.*?)"?(;|$)/ - $1 - end - end end end class Range ## only valid for integer ranges (unless I guess it's exclusive) @@ -292,18 +286,25 @@ self end end def in? range; range.member? self; end + + def to_human_size + if self < 1024 + to_s + "b" + elsif self < (1024 * 1024) + (self / 1024).to_s + "k" + elsif self < (1024 * 1024 * 1024) + (self / 1024 / 1024).to_s + "m" + else + (self / 1024 / 1024 / 1024).to_s + "g" + end + end end class Fixnum - def num_digits base=10 - return 1 if self == 0 - 1 + (Math.log(self) / Math.log(10)).floor - end - def to_character if self < 128 && self >= 0 chr else "<#{self}>" @@ -570,6 +571,45 @@ def [] k @hash[k] ||= @constructor.call(k) end defer_all_other_method_calls_to :hash +end + +class OrderedHash < Hash + alias_method :store, :[]= + alias_method :each_pair, :each + attr_reader :keys + + def initialize *a + @keys = [] + a.each { |k, v| self[k] = v } + end + + def []= key, val + @keys << key unless member?(key) + super + end + + def values; keys.map { |k| self[k] } end + def index key; @keys.index key end + + def delete key + @keys.delete key + super + end + + def each; @keys.each { |k| yield k, self[k] } end +end + +## easy thread-safe class for determining who's the "winner" in a race (i.e. +## first person to hit the finish line +class FinishLine + def initialize + @m = Mutex.new + @over = false + end + + def winner? + @m.synchronize { !@over && @over = true } + end end