# #-- # Copyright (c) 2005-2007, John Mettraux, OpenWFE.org # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # . Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # . Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # . Neither the name of the "OpenWFE" nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #++ # # $Id: utils.rb 3454 2006-10-08 16:51:00Z jmettraux $ # # # "hecho en Costa Rica" and "made in Japan" # # john.mettraux@openwfe.org # require 'rexml/document' require 'tmpdir' require 'open-uri' module OpenWFE # # Returns the first subelt of xmlElt that matches the given xpath. # If xpath is null, the first elt will be returned. # def OpenWFE.first_element (xmlElt, elementName=nil) return nil if not xmlElt return xmlElt.elements[1] if not elementName #xmlElt.elements.each do |elt| # return elt if elt.name == elementName #end #return nil xmlElt.elements.detect { |elt| elt.name == elementName } end # # Used in tests, is equivalent to Perl's die() method. # def OpenWFE.die (text) puts text exit 1 end # # Attempts a deep cloning of the object # def OpenWFE.copy (object) return nil if object == nil if object.kind_of?(Array) result = [] object.each do |i| result << copy(i) end return result end if object.kind_of?(Hash) result = {} object.each do |k, v| result[copy(k)] = copy(v) end return result end return object.dup end # # see # http://wiki.rubygarden.org/Ruby/page/show/Make_A_Deep_Copy_Of_An_Object # def OpenWFE.deep_clone (object) Marshal::load(Marshal.dump(object)) end # # an automatic dup implementation attempt # def OpenWFE.fulldup (object) return nil if object == nil return object if object.kind_of?(Float) return object if object.kind_of?(Fixnum) return object if object.kind_of?(TrueClass) return object if object.kind_of?(FalseClass) return object.dup if object.kind_of?(String) #return deep_clone(object) if object.kind_of? REXML::Document #return REXML::Document.new(object.to_s) \ # if object.kind_of? REXML::Document if object.kind_of?(REXML::Element) d = REXML::Document.new object.to_s return d if object.kind_of?(REXML::Document) return d.root end o = object.class.new # # some kind of collection ? if object.kind_of?(Array) object.each do |i| o << fulldup(i) end elsif object.kind_of?(Hash) object.each do |k, v| o[copy(k)] = fulldup(v) end end # # duplicate the attributes of the object object.instance_variables.each do |v| #puts "v is #{v}" value = object.instance_variable_get(v) #puts "value is '#{value}'" value = fulldup(value) begin o.instance_variable_set(v, value) rescue # ignore, must be readonly end end o end def OpenWFE.to_underscore (string) string.gsub("-", "_") end def OpenWFE.to_dash (string) string.gsub("_", "-") end def OpenWFE.symbol_to_name (symbol) to_dash(symbol.to_s) end def OpenWFE.name_to_symbol (name) return name if name.is_a?(Symbol) return to_underscore(name).intern end # # Turns all the spaces in string into underscores. # Returns the new String. # def OpenWFE.stu (s) s.gsub("\s", "_") end # # Returns an URI if the string is one, else returns nil. # No exception is thrown by this method. # def OpenWFE.parse_uri (string) begin return URI::parse(string) rescue Exception => e end nil end # # Returns true if the given string starts with the 'start' string. # def OpenWFE.starts_with (string, start) # # my favourite way of doing that would be by adding this # method to the String class, but that could be intrusive # (as OpenWFE is meant at first as an embeddable workflow engine). # return false unless string return false if string.length < start.length string[0, start.length] == start end # # Returns true if the given string ends with the '_end' string. # def OpenWFE.ends_with (string, _end) return false unless string return false if string.length < _end.length string[-_end.length..-1] == _end end # # Attempts at displaying a nice stack trace # def OpenWFE.exception_to_s (exception) s = "" s << "#{exception}\n" s << exception.backtrace.join("\n") return s end # # Pretty printing a caller() array # def OpenWFE.caller_to_s (start_index, max_lines=nil) s = "" caller(start_index + 1).each_with_index do |line, index| break if max_lines and index >= max_lines s << " #{line}\n" end return s end # # Some code for writing thinks like : # # if async # OpenWFE::call_in_thread "launch()", self do # raw_expression.apply(wi) # end # else # raw_expression.apply(wi) # end # # Returns the new thread instance. # def OpenWFE.call_in_thread (caller_name, caller_object=nil, &block) return unless block Thread.new do begin #$SAFE = safe_level # # (note) # doesn't work : the block inherits the safety level # of its surroundings, it's a closure, ne ? block.call rescue Exception => e msg = "#{caller_name} caught an exception\n" + exception_to_s(e) if caller_object and caller_object.respond_to? :lwarn caller_object.lwarn { msg } else puts msg end end end # returns the thread end # # A small Timer class for debug purposes. # # t = Time.new # # # ... do something # # puts "that something took #{t.duration} ms" # class Timer attr_reader :start def initialize @start = Time.now.to_f end # # Returns the number of milliseconds since this Timer was # instantiated. # def duration return (Time.now.to_f - @start) * 1000 end end # # A simple Hash that accepts String or Symbol as lookup keys [] # class SymbolHash < Hash def [] (key) super(key.to_s) end end # # Returns a version of s that is usable as or within a filename # (removes for examples things like '/' or '\'...) # def OpenWFE.ensure_for_filename (s) s = s.gsub(" ", "_") s = s.gsub("/", "_") s = s.gsub(":", "_") s = s.gsub(";", "_") s = s.gsub("\*", "_") s = s.gsub("\\", "_") s = s.gsub("\+", "_") s = s.gsub("\?", "_") return s end # # "my//path" -> "my/path" # def OpenWFE.clean_path (s) s.gsub(/\/+/, "/") end # # This method is used within the InFlowWorkItem and the CsvTable classes. # def OpenWFE.lookup_attribute (container, key) key, rest = pop_key(key) value = container[key] return value unless rest return nil unless value return lookup_attribute(value, rest) end # # This method is used within the InFlowWorkItem and the CsvTable classes. # def OpenWFE.has_attribute? (container, key) key, rest = pop_key(key) if not rest return container.has_key?(key) \ if container.respond_to?(:has_key?) return false end return has_attribute?(rest, key) end # # Returns a list of lines matching the pattern in the given file. # # This is also possible : # # OpenWFE::grep "^..) ", "path/to/file.txt" do |line| # puts " - '#{line.downcase}'" # end # def OpenWFE.grep (pattern, filepath, &block) result = [] r = Regexp.new pattern File.open filepath do |file| file.readlines.each do |l| if r.match l if block block.call l else result << l end end end end result unless block end # # This method is used within the InFlowWorkItem and the CsvTable classes. # def OpenWFE.set_attribute (container, key, value) i = key.rindex(".") if not i container[key] = value return end container = lookup_attribute(container, key[0..i-1]) container[key[i+1..-1]] = value end protected def pop_key (key) i = key.index(".") return narrow(key), nil unless i return narrow(key[0..i-1]), key[i+1..-1] end def narrow (key) return 0 if key == "0" i = key.to_i return i if i != 0 return key end end