lib/ole/support.rb in ruby-ole-1.2.1 vs lib/ole/support.rb in ruby-ole-1.2.2

- old
+ new

@@ -1,15 +1,29 @@ # # A file with general support functions used by most files in the project. # +# These are the only methods added to other classes. +# require 'logger' +require 'stringio' +require 'enumerator' +class String # :nodoc: + # plural of String#index. returns all offsets of +string+. rename to indices? + # + # note that it doesn't check for overlapping values. + def indexes string + # in some ways i'm surprised that $~ works properly in this case... + to_enum(:scan, /#{Regexp.quote string}/m).map { $~.begin 0 } + end +end + class File # :nodoc: - # for consistency with StringIO and others. makes more sense than forcing - # them to provide a #stat + # for interface consistency with StringIO etc (rather than adding #stat + # to them). used by RangesIO. def size stat.size end end @@ -30,12 +44,22 @@ def sum initial=0 inject(initial) { |a, b| a + b } end end +# move to support? +class IO # :nodoc: + def self.copy src, dst + until src.eof? + buf = src.read(4096) + dst.write buf + end + end +end + class Logger # :nodoc: - # A helper method for creating <tt>Logger</tt>s which produce call stack + # A helper method for creating a +Logger+ which produce call stack # in their output def self.new_with_callstack logdev=STDERR log = Logger.new logdev log.level = WARN log.formatter = proc do |severity, time, progname, msg| @@ -45,7 +69,92 @@ from = callstack.first.sub(/:in `(.*?)'/, ":\\1") "[%s %s]\n%-7s%s\n" % [time.strftime('%H:%M:%S'), from, severity, msg.to_s] end log end +end + +# Include this module into a class that defines #each_child. It should +# maybe use #each instead, but its easier to be more specific, and use +# an alias. +# +# I don't want to force the class to cache children (eg where children +# are loaded on request in pst), because that forces the whole tree to +# be loaded. So, the methods should only call #each_child once, and +# breadth first iteration holds its own copy of the children around. +# +# Main methods are #recursive, and #to_tree +module RecursivelyEnumerable + def each_recursive_depth_first(&block) + each_child do |child| + yield child + if child.respond_to? :each_recursive_depth_first + child.each_recursive_depth_first(&block) + end + end + end + + def each_recursive_breadth_first(&block) + children = [] + each_child do |child| + children << child if child.respond_to? :each_recursive_breadth_first + yield child + end + children.each { |child| child.each_recursive_breadth_first(&block) } + end + + def each_recursive mode=:depth_first, &block + # we always actually yield ourself (the tree root) before recursing + yield self + send "each_recursive_#{mode}", &block + end + + # the idea of this function, is to allow use of regular Enumerable methods + # in a recursive fashion. eg: + # + # # just looks at top level children + # root.find { |child| child.some_condition? } + # # recurse into all children getting non-folders, breadth first + # root.recursive(:breadth_first).select { |child| !child.folder? } + # # just get everything + # items = root.recursive.to_a + # + def recursive mode=:depth_first + to_enum(:each_recursive, mode) + end + + # streams a "tree" form of the recursively enumerable structure to +io+, or + # return a string form instead if +io+ is not specified. + # + # mostly a debugging aid. can specify a different +method+ to call if desired, + # though it should return a single line string. + def to_tree io=nil, method=:inspect + unless io + to_tree io = StringIO.new + return io.string + end + io << "- #{send method}\n" + to_tree_helper io, method, ' ' + end + + def to_tree_helper io, method, prefix + # i need to know when i get to the last child. use delay to know + child = nil + each_child do |next_child| + if child + io << "#{prefix}|- #{child.send method}\n" + if child.respond_to? :to_tree_helper + child.to_tree_helper io, method, prefix + '| ' + end + end + child = next_child + end + return unless child + # child is the last child + io << "#{prefix}\\- #{child.send method}\n" + if child.respond_to? :to_tree_helper + child.to_tree_helper io, method, prefix + ' ' + end + end + protected :to_tree_helper end