diff options
Diffstat (limited to 'vendor/ruby-ole/lib/ole/support.rb')
-rw-r--r-- | vendor/ruby-ole/lib/ole/support.rb | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/vendor/ruby-ole/lib/ole/support.rb b/vendor/ruby-ole/lib/ole/support.rb new file mode 100644 index 000000000..bbb0bbe68 --- /dev/null +++ b/vendor/ruby-ole/lib/ole/support.rb @@ -0,0 +1,256 @@ +# +# 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 + + def each_chunk size + (length / size.to_f).ceil.times { |i| yield self[i * size, size] } + end +end + +class File # :nodoc: + # for interface consistency with StringIO etc (rather than adding #stat + # to them). used by RangesIO. + def size + stat.size + end +end + +class Symbol # :nodoc: + unless :x.respond_to? :to_proc + def to_proc + proc { |a| a.send self } + end + end +end + +module Enumerable # :nodoc: + unless [].respond_to? :group_by + # 1.9 backport + def group_by + hash = Hash.new { |h, key| h[key] = [] } + each { |item| hash[yield(item)] << item } + hash + end + end + + unless [].respond_to? :sum + def sum initial=0 + inject(initial) { |a, b| a + b } + end + end +end + +# move to support? +class IO # :nodoc: + # Copy data from IO-like object +src+, to +dst+ + 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 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| + # find where we were called from, in our code + callstack = caller.dup + callstack.shift while callstack.first =~ /\/logger\.rb:\d+:in/ + 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 # :nodoc: + 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 + + # don't think this is actually a proper breadth first recursion. only first + # level is breadth first. + 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 block which will be called + # to provide the string form for each node. + def to_tree io='', &inspect + inspect ||= :inspect.to_proc + io << "- #{inspect[self]}\n" + recurse = proc do |node, prefix| + child = nil + node.each_child do |next_child| + if child + io << "#{prefix}|- #{inspect[child]}\n" + recurse.call child, prefix + '| ' + end + child = next_child + end if node.respond_to?(:each_child) + if child + io << "#{prefix}\\- #{inspect[child]}\n" + recurse.call child, prefix + ' ' + end + end + recurse.call self, ' ' + io + end +end + +# can include File::Constants +class IO + # this is for jruby + include File::Constants unless defined?(RDONLY) + + # nabbed from rubinius, and modified + def self.parse_mode mode + ret = 0 + + case mode[0, 1] + when 'r'; ret |= RDONLY + when 'w'; ret |= WRONLY | CREAT | TRUNC + when 'a'; ret |= WRONLY | CREAT | APPEND + else raise ArgumentError, "illegal access mode #{mode}" + end + + (1...mode.length).each do |i| + case mode[i, 1] + when '+'; ret = (ret & ~(RDONLY | WRONLY)) | RDWR + when 'b'; ret |= Mode::BINARY + else raise ArgumentError, "illegal access mode #{mode}" + end + end + + ret + end + + class Mode + # ruby 1.9 defines binary as 0, which isn't very helpful. + # its 4 in rubinius. no longer using + # + # BINARY = 0x4 unless defined?(BINARY) + # + # for that reason, have my own constants module here + module Constants + include File::Constants + BINARY = 0x4 + end + + include Constants + NAMES = %w[rdonly wronly rdwr creat trunc append binary] + + attr_reader :flags + def initialize flags + flags = IO.parse_mode flags.to_str if flags.respond_to? :to_str + raise ArgumentError, "invalid flags - #{flags.inspect}" unless Fixnum === flags + @flags = flags + end + + def writeable? + #(@flags & RDONLY) == 0 + (@flags & 0x3) != RDONLY + end + + def readable? + (@flags & WRONLY) == 0 + end + + def truncate? + (@flags & TRUNC) != 0 + end + + def append? + (@flags & APPEND) != 0 + end + + def create? + (@flags & CREAT) != 0 + end + + def binary? + (@flags & BINARY) != 0 + end + +=begin + # revisit this + def apply io + if truncate? + io.truncate 0 + elsif append? + io.seek IO::SEEK_END, 0 + end + end +=end + + def inspect + names = NAMES.map { |name| name if (flags & Mode.const_get(name.upcase)) != 0 } + names.unshift 'rdonly' if (flags & 0x3) == 0 + "#<#{self.class} #{names.compact * '|'}>" + end + end +end + |