lib/sup/util.rb in sup-0.2 vs lib/sup/util.rb in sup-0.3
- old
+ new
@@ -134,20 +134,47 @@
## "k combinator"
def returning x; yield x; x; end
## clone of java-style whole-method synchronization
## assumes a @mutex variable
+ ## TODO: clean up, try harder to avoid namespace collisions
def synchronized *meth
meth.each do
class_eval <<-EOF
alias unsynchronized_#{meth} #{meth}
def #{meth}(*a, &b)
@mutex.synchronize { unsynchronized_#{meth}(*a, &b) }
end
EOF
end
end
+
+ def ignore_concurrent_calls *meth
+ meth.each do
+ mutex = "@__concurrent_protector_#{meth}"
+ flag = "@__concurrent_flag_#{meth}"
+ oldmeth = "__unprotected_#{meth}"
+ class_eval <<-EOF
+ alias #{oldmeth} #{meth}
+ def #{meth}(*a, &b)
+ #{mutex} = Mutex.new unless defined? #{mutex}
+ #{flag} = true unless defined? #{flag}
+ run = #{mutex}.synchronize do
+ if #{flag}
+ #{flag} = false
+ true
+ end
+ end
+ if run
+ ret = #{oldmeth}(*a, &b)
+ #{mutex}.synchronize { #{flag} = true }
+ ret
+ end
+ end
+ EOF
+ end
+ end
end
class String
def camel_to_hyphy
self.gsub(/([a-z])([A-Z0-9])/, '\1-\2').downcase
@@ -163,20 +190,79 @@
start = pos + 1
end
ret
end
+ ## one of the few things i miss from perl
def ucfirst
self[0 .. 0].upcase + self[1 .. -1]
end
## a very complicated regex found on teh internets to split on
## commas, unless they occurr within double quotes.
def split_on_commas
split(/,\s*(?=(?:[^"]*"[^"]*")*(?![^"]*"))/)
end
+ ## ok, here we do it the hard way. got to have a remainder for purposes of
+ ## tab-completing full email addresses
+ def split_on_commas_with_remainder
+ ret = []
+ state = :outstring
+ pos = 0
+ region_start = 0
+ while pos <= length
+ newpos = case state
+ when :escaped_instring, :escaped_outstring: pos
+ else index(/[,"\\]/, pos)
+ end
+
+ if newpos
+ char = self[newpos]
+ else
+ char = nil
+ newpos = length
+ end
+
+ case char
+ when ?"
+ state = case state
+ when :outstring: :instring
+ when :instring: :outstring
+ when :escaped_instring: :instring
+ when :escaped_outstring: :outstring
+ end
+ when ?,, nil
+ state = case state
+ when :outstring, :escaped_outstring:
+ ret << self[region_start ... newpos].gsub(/^\s+|\s+$/, "")
+ region_start = newpos + 1
+ :outstring
+ when :instring: :instring
+ when :escaped_instring: :instring
+ end
+ when ?\\
+ state = case state
+ when :instring: :escaped_instring
+ when :outstring: :escaped_outstring
+ when :escaped_instring: :instring
+ when :escaped_outstring: :outstring
+ end
+ end
+ pos = newpos + 1
+ end
+
+ remainder = case state
+ when :instring
+ self[region_start .. -1].gsub(/^\s+/, "")
+ else
+ nil
+ end
+
+ [ret, remainder]
+ end
+
def wrap len
ret = []
s = self
while s.length > len
cut = s[0 ... len].rindex(/\s/)
@@ -221,10 +307,24 @@
chr
else
"<#{self}>"
end
end
+
+ ## hacking the english language
+ def pluralize s
+ to_s + " " +
+ if self == 1
+ s
+ else
+ if s =~ /(.*)y$/
+ $1 + "ies"
+ else
+ s + "s"
+ end
+ end
+ end
end
class Hash
def - o
Hash[*self.map { |k, v| [k, v] unless o.include? k }.compact.flatten_one_level]
@@ -297,10 +397,11 @@
def rest; self[1..-1]; end
def to_boolean_h; Hash[*map { |x| [x, true] }.flatten]; end
def last= e; self[-1] = e end
+ def nonempty?; !empty? end
end
class Time
def to_indexable_s
sprintf "%012d", self
@@ -403,23 +504,24 @@
def self.included klass
klass.extend ClassMethods
end
end
-## wraps an object. if it throws an exception, keeps a copy, and
-## rethrows it for any further method calls.
+## wraps an object. if it throws an exception, keeps a copy.
class Recoverable
def initialize o
@o = o
- @e = nil
+ @error = nil
+ @mutex = Mutex.new
end
- def clear_error!; @e = nil; end
- def has_errors?; !@e.nil?; end
- def error; @e; end
+ attr_accessor :error
- def method_missing m, *a, &b; __pass m, *a, &b; end
+ def clear_error!; @error = nil; end
+ def has_errors?; !@error.nil?; end
+
+ def method_missing m, *a, &b; __pass m, *a, &b end
def id; __pass :id; end
def to_s; __pass :to_s; end
def to_yaml x; __pass :to_yaml, x; end
def is_a? c; @o.is_a? c; end
@@ -428,11 +530,11 @@
def __pass m, *a, &b
begin
@o.send(m, *a, &b)
rescue Exception => e
- @e = e
- raise e
+ @error ||= e
+ raise
end
end
end
## acts like a hash with an initialization block, but saves any