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