Add bin and edit workflow
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s

This commit is contained in:
2026-09-16 13:11:16 -06:00
parent c8ac4fcae5
commit 4cee170d66
17576 changed files with 895740 additions and 2 deletions
@@ -0,0 +1,33 @@
#
def temporary_directory
@temporary_directory ||= 'tmp'
end
When /Given a directory '(.*?)' containing/ do |dir, text|
@temporary_directory = File.join(@temporary_directory, dir)
text.lines.each do |file|
next if file =~ /^\s*$/
file = File.join(@temporary_directory, file.strip)
dir = File.dirname(file)
FileUtils.mkdir_p(dir)
File.open(file, 'w'){ |f| f << "SPINICH" }
end
end
Before :all do
if File.exist?(temporary_directory)
FileUtils.rm_r(temporary_directory)
end
FileUtils.mkdir_p(temporary_directory)
end
# Used for File extensions
When "had a file '(((.*?)))'" do |name|
name = name.sub(/^tmp\//, '') # b/c QED now runs from tmp/qed
File.open(name, 'w'){|f| f << "Hello World"}
end
When "had a binary file '(((.*?)))'" do |name|
name = name.sub(/^tmp\//, '') # b/c QED now runs from tmp/qed
File.open(name, 'wb'){|f| f << "Hello\nWorld\n"}
end
@@ -0,0 +1,49 @@
require_relative 'array/after.rb'
#require_relative 'array/arrange.rb' # too new
require_relative 'array/average.rb'
require_relative 'array/before.rb'
require_relative 'array/collapse.rb'
require_relative 'array/collisions.rb'
require_relative 'array/commonality.rb'
require_relative 'array/conjoin.rb'
require_relative 'array/contains.rb'
require_relative 'array/delete.rb'
require_relative 'array/delete_unless.rb'
require_relative 'array/delete_values.rb'
require_relative 'array/divide.rb'
require_relative 'array/duplicates.rb'
require_relative 'array/each_pair.rb'
require_relative 'array/each_value.rb'
require_relative 'array/entropy.rb'
require_relative 'array/extract_options.rb'
require_relative 'array/from.rb'
require_relative 'array/indexable.rb'
#require_relative 'array/intersection.rb' # too new
#require_relative 'array/median.rb' # uncommon
require_relative 'array/merge.rb'
#require_relative 'array/missing.rb' # too new
require_relative 'array/mode.rb'
require_relative 'array/nonuniq.rb'
require_relative 'array/not_empty.rb'
require_relative 'array/only.rb'
require_relative 'array/pad.rb'
require_relative 'array/peek.rb'
#require_relative 'array/percentile.rb' # uncommon
require_relative 'array/unique_permutation.rb'
require_relative 'array/poke.rb'
require_relative 'array/probability.rb'
require_relative 'array/pull.rb'
require_relative 'array/occurrence.rb'
#require_relative 'array/op_pow.rb' # uncommon
require_relative 'array/recurse.rb'
require_relative 'array/recursively.rb'
require_relative 'array/reject_values.rb'
require_relative 'array/splice.rb'
require_relative 'array/split.rb'
require_relative 'array/squeeze.rb'
require_relative 'array/store.rb'
require_relative 'array/thru.rb'
require_relative 'array/to_h.rb'
require_relative 'array/traverse.rb'
require_relative 'array/uniq_by.rb'
@@ -0,0 +1 @@
require 'facets/array/before'
@@ -0,0 +1,42 @@
class Array
# The `arrange` method produces appropriate ranges from the objects in the array.
#
# Examples
#
# [1,2,3,6,7,8].arrange #=> [1..3, 6..8]
#
# [10..15, 16..20, 21, 22].arrange #=> [10..22]
#
# Assumes inclusive ranges (ie. 1..4) and range.first <= range.last.
#
# Works with integers, dates and strings. However, all the objects in the array must
# be of the same class.
#
# CREDIT: monocle
def arrange
array = uniq.sort_by { |e| Range === e ? e.first : e }
array.inject([]) do |c, value|
unless c.empty?
last = c.last
last_value = (Range === last ? last.last : last)
current_value = (Range === value ? value.first : value)
if (last_value.succ <=> current_value) == -1
c << value
else
first = (Range === last ? last.first : last)
second = [Range === last ? last.last : last, Range === value ? value.last : value].max
c[-1] = [first..second]
c.flatten!
end
else
c << value
end
end
end
alias rangify arrange
end
@@ -0,0 +1,16 @@
class Array
# Calculate the average of an array of numbers
#
# Examples
#
# [].average #=> nil
# [1, 2, 3].average #=> 2
# [3, 12, 57, 85, 15, 89, 33, 7, 22, 54].average #=> 37.7
# [1,[2,nil,[3]],nil,4].collapse #=> [1,2,3,4]
#
def average
return nil if empty?
self.reduce(:+)/length.to_f
end
end
@@ -0,0 +1,41 @@
class Array
# Returns the value previous to the given value. The value previous
# to the first is the last. Returns nil if the given value is not
# in the array.
#
# Examples
#
# sequence = ['a', 'b', 'c']
# sequence.before('a') #=> 'c'
# sequence.before('b') #=> 'a'
# sequence.before('c') #=> 'b'
# sequence.before('d') #=> nil
#
# CREDIT: Tyler Rick
def before(value)
return nil unless include? value
self[(index(value).to_i - 1) % length]
end
# Returns the value after the given value. The value before the last
# is the first. Returns nil if the given value is not in the array.
#
# Examples
#
# sequence = ['a', 'b', 'c']
# sequence.after('a') #=> 'b'
# sequence.after('b') #=> 'c'
# sequence.after('c') #=> 'a'
# sequence.after('d') #=> nil
#
# CREDIT: Tyler Rick
def after(value)
return nil unless include? value
self[(index(value).to_i + 1) % length]
end
end
@@ -0,0 +1,18 @@
class Array
# Simplify an array by flattening it then compacting it.
#
# Examples
#
# [1,[2,nil,[3]],nil,4].collapse #=> [1,2,3,4]
#
def collapse
flatten.compact
end
def collapse!
flatten!.compact!
end
end
@@ -0,0 +1 @@
require 'facets/array/commonality'
@@ -0,0 +1,49 @@
class Array
# Get a list of all items that have something in common in terms of the
# supplied block. If no block is given objects are considered to be in
# common if they return the same value for Object#hash and if obj1 == obj2.
#
# This can be useful, for instance, in determining all persons that share
# their last name with another person.
#
# persons.commonality { |person| person.last_name }
#
# The method is similar to #group_by which is a standard Ruby method as of 1.9.
# To get effectively the same results with #group_by use `select{ |k,v| v.size > 1 }`.
#
# [1, 2, 2, 3, 4, 4].group_by{ |e| e }.select{ |k,v| v.size > 1 }
# #=> { 2 => [2, 2], 4 => [4, 4] }
#
# Examples
#
# [1, 2, 2, 3, 4, 4].commonality #=> { 2 => [2, 2], 4 => [4, 4] }
#
# ["foo", "bar", "baz"].commonality { |str| str[0] }
# #=> { 'b' => ["bar", "baz"] }
#
# Returns [Hash] mapping common attribute to those elements.
#
# CREDIT: Florian Gross
def commonality(&block)
block ||= lambda { |item| item }
result = Hash.new { |hash, key| hash[key] = Array.new }
each do |item|
key = block.call(item)
result[key] << item
end
result.reject! do |key, values|
values.size <= 1
end
return result
end
# Deprecated: Alias for #commonality.
alias collisions commonality
end
@@ -0,0 +1,89 @@
class Array
# This is more advanced form of #join. It allows for fine control
# of separators.
#
# NOTE: The old version used to default its separator to ", " and
# default the terminating separator to " and ". This is no longer
# the case. You must specifically provide these parameters.
#
# If no paramters are given, it acts like #join but will a space
# separator.
#
# [1,2,3].conjoin
# #=> "1 2 3"
#
# Use comma+space and 'and' on tail.
#
# [1,2,3].conjoin(', ', ' and ')
# #=> "1, 2 and 3"
#
# Use comma+space and 'or' on tail using :last option.
#
# [1,2,3].conjoin(', ', :last => ' or ')
# #=> "1, 2 or 3"
#
# Use semicolon+space and ampersand on tail using index.
#
# [1,2,3].conjoin('; ', -1 => ' & ')
# #=> "1; 2 & 3"
#
# Can take a block to determine separator.
#
# [1,2,3,4].conjoin{ |i, a, b| i % 2 == 0 ? '.' : '-' }
# #=> "1.2-3.4"
#
# This makes very esoteric transformation possible.
#
# [1,1,2,2].conjoin{ |i, a, b| a == b ? '=' : ' != ' }
# #=> "1=1 != 2=2"
#
# [1,2,3,4].conjoin{ |i, x, y| "<#{i} #{x} #{y}>" }
# #=> "1<0 1 2>2<1 2 3>3<2 3 4>4"
#
# There are also spacing options. Providing the :space option
# pads the separators.
#
# [1,2,3].conjoin(',', '&', :space=>2)
# #=> "1 , 2 & 3"
#
# And the :spacer option can set an alternate spacing string.
#
# [1,2,3].conjoin('|', '>', :space=>2, :spacer=>'-')
# #=> "1--|--2-->--3"
#
# CREDIT: Trans
def conjoin(*args, &block)
return first.to_s if size < 2
options = (Hash===args.last) ? args.pop : {}
spacing = options.delete(:space) || 0
spacer = options.delete(:spacer) || " "
space = spacer * spacing.to_i
sep = []
if block_given?
(size - 1).times do |i|
sep << space + yield(i, *slice(i,2)) + space
end
else
separator = args.shift || " "
options[-1] = args.shift if args.first
options[0] = options.delete(:first) if options.key?(:first)
options[-1] = options.delete(:last) if options.key?(:last)
separator = space + separator + space
sep = [separator] * (size - 1)
options.each{|i, s| sep[i] = space + s + space}
end
zip(sep).join
end
end
@@ -0,0 +1,7 @@
class Array
# Alias for #include?.
alias_method :contains?, :include?
end
@@ -0,0 +1,4 @@
# Here for backward compatability. To be deprecated.
require 'facets/array/delete_unless'
require 'facets/array/delete_values'
@@ -0,0 +1,15 @@
class Array
# Inverse of #delete_if.
#
# [1,2,3].delete_unless{ |x| x < 2 }
# #=> [1]
#
# CREDIT: Daniel Schierbeck
def delete_unless(&block)
delete_if { |element| not block.call(element) }
end
end
@@ -0,0 +1,50 @@
class Array
# Delete multiple values from array.
#
# a = [1,2,3,4]
# a.delete_values(1,2) #=> [1,2]
# a #=> [3,4]
#
# CREDIT: Trans
def delete_values(*values)
d = []
values.each{ |v| d << delete(v) }
d
end
# Delete multiple values from array given
# indexes or index range.
#
# a = [1,2,3,4]
# a.delete_values_at(1,2) #=> [2,3]
# a #=> [1,4]
# a = [1,2,3,4]
# a.delete_values_at(0..2) #=> [1,2,3]
# a #=> [4]
#
# NOTE: It would be nice to see #delete_at incorporate this
# funcitonaility.
#
# CREDIT: Trans
def delete_values_at(*selectors)
idx = []
selectors.each{ |i|
case i
when Range
idx.concat( i.to_a )
else
idx << i.to_i
end
}
idx.uniq!
dvals = values_at(*idx)
idx = (0...size).to_a - idx
self.replace( values_at(*idx) )
return dvals
end
end
@@ -0,0 +1 @@
require 'facets/array/delete_values'
@@ -0,0 +1,27 @@
class Array
# Divide on matching pattern.
#
# ['a1','b1','a2','b2'].divide(/^a/)
# #=> [['a1','b1'],['a2','b2']]
#
# ['a1','b1','a2','b2'].divide(/^b/)
# #=> [['a1',['b1','a2'],[]'b2']]
#
# ['a1','b1','a2','b2'].divide(/^c/)
# #=> [['a1','b1','a2','b2']]
#
# CREDIT: Trans
def divide(pattern)
memo = []
memo.push [] unless pattern === first
each do |obj|
memo.push [] if pattern === obj
memo.last << obj
end
memo
end
end
@@ -0,0 +1,24 @@
class Array
# Return list of duplicate elements.
#
# min - The minimum number of duplication necessary for inclusion. [Integer]
#
# Examples:
#
# [1,1,2,3].duplicates #=> [1]
#
# [1,1,2,3,2,4,5,4,2].duplicates(3) #=> [2]
#
# CREDIT: Rebort Dober (current implementation)
# CREDIT: Thibaut Barrère
def duplicates(min=2)
h = Hash.new( 0 )
each {|i|
h[i] += 1
}
h.delete_if{|_,v| v < min}.keys
end
end
@@ -0,0 +1,25 @@
class Array
# Iterate over each slice where the last n values of a preceding slice
# overlap with the first n values of the following slice. The value of n
# is specified by the second `overlap` argument.
#
# a, r = [1,2,3,4,5], []
# a.each_overlap(2,1) { |x,y| r << [x,y] }
# r # => [[1,2],[2,3],[3,4],[4,5]]
#
# Returns nothing.
def each_overlap(slice_size, overlap)
if block_given?
i = 0
while i + slice_size <= length
yield slice(i...i+slice_size)
i += (slice_size - overlap)
end
else
to_enum(:each_overlap, slice_size, overlap)
end
end
end
@@ -0,0 +1,11 @@
class Array
# Iterate over index and value. The intention of this
# method is to provide polymorphism with Hash.
#
def each_pair #:yield:
each_with_index {|e, i| yield(i,e) }
end
end
@@ -0,0 +1,6 @@
class Array
# Alias for #each. The intention of this method
# is to provide polymorphism with Hash.
alias :each_value :each
end
@@ -0,0 +1,39 @@
require 'facets/array/probability'
class Array
# Shannon's entropy for an array - returns the average
# bits per symbol required to encode the array.
# Lower values mean less "entropy" - i.e. less unique
# information in the array.
#
# e = %w{ a b c d e e e }.entropy
#
# ("%.3f" % e) #=> "2.128"
#
# CREDIT: Derek
def entropy
arr = self
probHash = arr.probability
# -- h is the Shannon entropy of the array
h = -1.to_f * probHash.keys.inject(0.to_f) do |sum, i|
sum + (probHash[i] * (Math.log(probHash[i])/Math.log(2.to_f)))
end
h
end
# Returns the maximum possible Shannon entropy of the array
# with given size assuming that it is an "order-0" source
# (each element is selected independently of the next).
#
# CREDIT: Derek
def ideal_entropy
arr = self
unitProb = 1.0.to_f / arr.size.to_f
(-1.to_f * arr.size.to_f * unitProb * Math.log(unitProb)/Math.log(2.to_f))
end
end
@@ -0,0 +1,31 @@
class Hash
# By default, only instances of Hash itself are extractable.
# Subclasses of Hash may implement this method and return
# true to declare themselves as extractable. If a Hash
# is extractable, Array#extract_options! pops it from
# the Array when it is the last element of the Array.
def extractable_options?
instance_of?(Hash)
end
end
class Array
# Extracts options from a set of arguments. Removes and returns the last
# element in the array if it's a hash, otherwise returns a blank hash.
#
# def options(*args)
# args.extract_options!
# end
#
# options(1, 2) # => {}
# options(1, 2, :a => :b) # => {:a=>:b}
#
def extract_options!
if Hash === last && last.extractable_options?
pop
else
{}
end
end
end
@@ -0,0 +1 @@
require 'facets/array/indexable'
@@ -0,0 +1,28 @@
class Array
# Returns elements from `index` until the end.
#
# %w{W o r l d}.from(3) #=> ["l", "d"]
# %w{W o r l d}.from(9) #=> []
#
def from(index)
return [] if index >= size
self[index..-1]
end unless method_defined?(:from)
# Fetch values from a start index thru an end index.
#
# [1,2,3,4,5].thru(2) #=> [1,2,3]
# [1,2,3,4,5].thru(4) #=> [1,2,3,4,5]
#
# [1,2,3,4,5].thru(0,2) #=> [1,2,3]
# [1,2,3,4,5].thru(2,4) #=> [3,4,5]
#
def thru(from, to=nil)
from, to = 0, from unless to
return [] if from >= size
self[from..to]
end unless method_defined?(:thru)
end
@@ -0,0 +1,31 @@
require 'facets/indexable'
require 'facets/array/splice'
class Array
include Indexable
# Alias for shift, which removes and returns
# the first element in an array.
#
# a = ["a","y","z"]
# a.first! #=> "a"
# a #=> ["y","z"]
#
# CREDIT: Trans
alias_method :first!, :shift
# Alias for pop, which removes and returns
# the last element in an array.
#
# a = [1,2,3]
# a.last! #=> 3
# a #=> [1,2]
#
# CREDIT: Trans
alias_method :last!, :pop
end
@@ -0,0 +1,25 @@
class Array
# Returns the values in common for an array set (nil, single value/object, or range).
#
# CREDIT: monocle
def intersection
array = uniq.sort_by { |e| Range === e ? e.first : e }
array.inject() do |c, e|
f = (Range === c ? c.last : c)
v = (Range === e ? e.first : e)
case f <=> v
when -1 then return nil
when 0 then f
else
if Range === e
v..([f, e.last].min)
else
v
end
end
end
end
end
@@ -0,0 +1 @@
require 'facets/array/indexable'
@@ -0,0 +1,32 @@
class Array
# Determines the _sorted_ middle element.
#
# a = %w{a a b b c c c}
# a.median #=> "b"
#
# When there are an even number of elements, the greater
# of the two middle elements is given.
#
# a = %w{a a b b c c c d}
# a.median #=> "c"
#
# An offset can be supplied to get an element relative
# to the middle.
#
# a = %w{a a b b c c c d}
# a.median(-1) #=> "b"
#
# The the array is empty, +nil+ is returned.
#
# @return [Object] sorted middle element
def median(offset=0)
return nil if self.size == 0
tmp = self.sort
mid = (tmp.size / 2).to_i + offset
tmp[mid]
end
end
@@ -0,0 +1,22 @@
class Array
# In place #merge.
#
# a = [1,2]
# a.merge! [2,3]
# a #=> [1,2,3]
#
# CREDIT: Trans
def merge!( other )
self.replace(self.merge(other))
end
# Alias for <tt>|</tt>.
#
# [1,2].merge([2,3]) #=> [1,2,3]
#
alias_method :merge, :|
end
@@ -0,0 +1,29 @@
require 'facets/array/arrange'
class Array
# Determine the "holes" in the values of an array.
#
# TODO: Better name?
#
# Returns the missing elements in an array set.
#
# CREDIT: monocle
def missing
missing, array = [], arrange
i, length = 0, array.size - 1
while i < length
x0 = array[i]
x1 = array[i+1]
c = (Range === x0 ? x0.last : x0)
n = (Range === x1 ? x1.first : x1)
missing << (
c.succ.succ == n ? c.succ : ((c.succ)..(n.pred))
)
i += 1
end
return missing
end
end
@@ -0,0 +1,22 @@
class Array
# In Statistics. mode is the value that occurs most frequently
# in a given set of data. This method returns an array in case
# there is a tie.
#
# [:a, :b, :c, :b, :d].mode #=> [:b]
# [:a, :b, :c, :b, :a].mode #=> [:a, :b]
#
# Returns an Array of most common elements.
#
# @author Robert Klemme
def mode
max = 0
c = Hash.new 0
each {|x| cc = c[x] += 1; max = cc if cc > max}
c.select {|k,v| v == max}.map {|k,v| k}
end
end
@@ -0,0 +1,28 @@
class Array
# Returns a list of non-unique elements.
#
# Examples
#
# [1,1,2,2,3,4,5].nonuniq #=> [1,2]
#
# CREDIT: Martin DeMello
def nonuniq
h1 = {}
h2 = {}
each {|i|
h2[i] = true if h1[i]
h1[i] = true
}
h2.keys
end
# Same as `#nonuniq` but acts in place.
def nonuniq!
self.replace(self.nonuniq)
end
end
@@ -0,0 +1,13 @@
class Array
# Not empty?
#
# [].not_empty? #=> false
# [1,2].not_empty? #=> true
def not_empty?
!empty?
end
end
@@ -0,0 +1,38 @@
class Array
# Returns a list of elements that occur +n+ times.
#
# If +n+ is a Range then returns elements that occur a number
# of time within the range.
#
# Examples
#
# [0,1,1,1,3,0,1,2,4].occur(3) #=> [1]
#
# [0,1,1,1,3,0,1,2,4].occur(2..4) #=> [0,1]
#
# Returns [Array] of reoccurring elements.
#
# CREDIT: Robert Dober
def occur(n=nil) #:yield:
h = Hash.new(0)
each do |i|
h[i] += 1
end
case n
when nil
h.delete_if{ |_,v| ! yield(v) }.keys
when Range
h.delete_if{ |_,v| ! n.include?(v) }.keys
else
h.delete_if{|_,v| v != n}.keys
end
end
# Plural alias of #occur.
alias :occurs :occur
end
@@ -0,0 +1,29 @@
class Array
# Create a hash of each uniq element of the array
# and how many time each appears.
#
# Examples
#
# [:a,:a,:b,:c,:c,:c].occurrence
# #=> { :a => 2, :b => 1, :c => 3 }
#
# [2,2,3,4,4,4].occurrence{|i| i % 2}
# #=> { 0 => 5, 1 => 1 }
#
def occurrence
h = Hash.new(0)
if block_given?
each do |e|
h[yield(e)] += 1
end
else
each do |e|
h[e] += 1
end
end
h
end
end
@@ -0,0 +1,37 @@
class Array
# Returns the _only_ element in the array. Raises an IndexError if
# the array's size is not 1.
#
# [5].only # => 5
#
# expect IndexError do
# [1,2,3].only
# end
#
# expect IndexError do
# [].only
# end
#
# CREDIT: Gavin Sinclair, Noah Gibbs
def only
unless size == 1
raise IndexError, "not the only element of array"
end
first
end
# Does this Array have only one element?
#
# TODO: While clearly this goes along with the regular #only method,
# the name doesn't seem quite right. Perhaps rename to #lonely.
#
# CREDIT: Lavir the Whiolet
#
def only?
size == 1
end
end
@@ -0,0 +1,12 @@
class Array
# Array#** is an alias for Array#product.
#
# NOTE: This method is not a common core extension and is not
# loaded automatically when using <code>require 'facets'</code>.
#
# @uncommon
# require 'facets/array/op_pow'
#
alias_method :**, :product
end
@@ -0,0 +1,41 @@
class Array
# Pad an array with a given <tt>value</tt> up to a given <tt>length</tt>.
#
# [0,1,2].pad(6,"a") #=> [0,1,2,"a","a","a"]
#
# If <tt>length</tt> is a negative number padding will be added
# to the beginning of the array.
#
# [0,1,2].pad(-6,"a") #=> ["a","a","a",0,1,2]
#
# CREDIT: Richard Laugesen
def pad(len, val=nil)
return dup if self.size >= len.abs
if len < 0
Array.new((len+size).abs,val) + self
else
self + Array.new(len-size,val)
end
end
# Like #pad but changes the array in place.
#
# a = [0,1,2]
# a.pad!(6,"x")
# a #=> [0,1,2,"x","x","x"]
#
# CREDIT: Richard Laugesen
def pad!(len, val=nil)
return self if self.size >= len.abs
if len < 0
replace Array.new((len+size).abs,val) + self
else
concat Array.new(len-size,val)
end
end
end
@@ -0,0 +1 @@
require 'facets/array/pull'
@@ -0,0 +1 @@
require 'facets/array/pull'
@@ -0,0 +1,39 @@
class Array
# Generates a hash mapping each unique element in the array to the
# relative frequency, i.e. the probability, of it appearance.
#
# [:a, :b, :c, :c].probability #=> {:a=> 0.25, :b=>0.25, :c=>0.5}
#
# CREDIT: Brian Schröder
def probability
probs = Hash.new(0.0)
size = 0.0
each do |e|
probs[e] += 1.0
size += 1.0
end
probs.keys.each{ |e| probs[e] /= size }
probs
end
#--
# Old Definition ...
#
# def probability
# arr = self.to_a
# probHash = Hash.new
# size = arr.size.to_f
# arr.uniq.each do |i|
# ct = arr.inject(0) do |mem,obj|
# obj.eql?(i) ? (mem+1) : mem
# end
# probHash[i] = ct.to_f/size
# end
# probHash
# end
#++
end
@@ -0,0 +1,30 @@
class Array
# Alias for shift which removes an object off first slot of an array.
# This is the opposite of pop.
alias_method :pull, :shift
# Peek at the top of the stack (the end of the array).
#
# a = [1, 2, 3]
# a.peek #=> 3
# a #=> [1, 2, 3]
#
# Or provide an index to inspect the array from back to front.
def peek(i=0)
i = -(i + 1)
fetch(i)
end
# Put an object on the bottom of the stack (front of the array).
#
# a = [2, 3]
# a.poke(1)
# a #=> [1, 2, 3]
#
# Or supply an index and #poke works like #insert.
def poke(x, i=0)
insert(i,x)
end
end
@@ -0,0 +1,29 @@
class Array
# Apply a block to array, and recursively apply that block
# to each sub-array or +types+.
#
# arr = ["a", ["b", "c", nil], nil]
# arr.recurse{ |a| a.compact! }
# #=> ["a", ["b", "c"]]
#
def recurse(*types, &block)
types = [self.class] if types.empty?
a = inject([]) do |array, value|
case value
when *types
array << value.recurse(*types, &block)
else
array << value
end
array
end
yield a
end
# In place form of #recurse.
def recurse!(&block)
replace(recurse(&block))
end
end
@@ -0,0 +1,53 @@
require 'facets/functor'
require 'facets/enumerable/recursively'
class Array
# Apply a method to array, and recursively apply that method
# to each sub-array or given +types+.
#
# By default the sub-types are passed through unaffected. Passing
# a block to #recursively can be used to change this.
#
# types - List of class types to recurse. [Array<Class>]
# block - Optional filter procedure to apply on each recursion.
#
# Examples
#
# arr = ["a", ["b", "c"]]
# arr.recursively.map{ |v| v.to_sym }
# #=> [:a, [:b, :c]]
#
# arr = ["a", ["b", "c"]]
# arr.recursively{ |a| a.reverse }.map{ |v| v.to_sym }
# #=> [:a, [:c, :b]]
#
# Returns [Recursor].
def recursively(*types, &block)
Recursor.new(self, *types, &block)
end
## TODO: When no longer needing to support 1.8.6 we could get rid of
## the Recursor class and use:
##
## def recursively(*types, &block)
## types = types.empty? ? [self.class] : types
## Functor.new do |op, &yld|
## rec = block || lambda{ |a| a }
## yld = yld || lambda{ |v| v } # ? to_enum
## __send__(op) do |v|
## case v
## when String # b/c of 1.8
## yld.call(v)
## when *types
## res = v.recursively(*types, &block).__send__(op,&yld)
## rec.call(res)
## else
## yld.call(v)
## end
## end
## end
## end
end
@@ -0,0 +1,21 @@
class Array
# Non-destructive form of `Array#delete_values`. Unlike `delete_values`
# this method returns a new array.
#
# values - List of array elements to reject.
#
# Examples
#
# [1,2,3,4,5].reject_values(2,4) # => [1,3,5]
#
# Returns [Array]
#
# CREDIT: Sean Mackesey
def reject_values(*values)
reject { |x| values.include?(x) }
end
end
@@ -0,0 +1,31 @@
require 'facets/array/store'
class Array
# Splice acts as a combination of #slice! and #store.
# If two arguments are given it calls #store.
# If a single argument is given it calls slice!.
#
# Examples
#
# a = [1,2,3]
# a.splice(1) #=> 2
# a #=> [1,3]
#
# a = [1,2,3]
# a.splice(1,4) #=> 4
# a #=> [1,4,3]
#
# Returns [Array].
#
# CREDIT: Trans
def splice(*args)
if args.size == 1
slice!(*args)
else
store(*args)
end
end
end
@@ -0,0 +1,30 @@
class Array
# Split on matching pattern. Unlike #divide this does not include matching
# elements.
#
# Examples
#
# ['a1','a2','b1','a3','b2','a4'].split(/^b/)
# #=> [['a1','a2'],['a3'],['a4']]
#
# Returns list of split-up arrays. [Array<Array>]
def split(pattern)
memo = []
sect = []
each do |obj|
if pattern === obj
memo << sect
sect = []
else
sect << obj
end
end
memo << sect
memo.pop while memo.last == []
memo
end
end
@@ -0,0 +1,23 @@
require 'facets/enumerable/squeeze'
class Array
# Destructive version of Enumerable#squeeze.
#
# a = [1,2,2,3,3,2,1]
# a.squeeze!
# a #=> [1,2,3,2,1]
#
# a = [1,2,2,3,3,2,1]
# a.squeeze!(*[3])
# a #=> [1,2,2,3,2,1]
#
# Returns the receiver. [Array]
#
# CREDIT: T. Yamada
def squeeze!(*limited_to)
replace(squeeze(*limited_to))
end
end
@@ -0,0 +1,23 @@
require 'facets/array/variance'
class Array
# Calculate the standard_deviation of an array of numbers
#
# Examples
#
# [].standard_deviation #=> nil
# [1, 2, 3].standard_deviation #=> 0.816496580927726
# [96, 35, 72, 30, 75, 33, 68, 13, 49, 71].standard_deviation #=> 24.69331893448104
# [36, -67, -17, 85, -46, -64, -23, -13, 89, -47].standard_deviation #=> 54.67183918618432
# [60.7829, 31.2622, 20.626, 78.8907, 61.5328].standard_deviation #=> 21.428815505053002
#
def standard_deviation
return nil if empty?
Math.sqrt(variance)
end
alias sd standard_deviation
end
@@ -0,0 +1,31 @@
class Array
# Iterate over every nth element of an array.
#
# r = []
# [:a, :b, :c, :d].step(2) { |x| r << x }
# r #=> [:b, :d]
#
# Without a block it returns an Enumerator.
#
# [:a, :b, :c, :d].step(1).to_a #=> [:a, :b, :c, :d]
# [:a, :b, :c, :d].step(2).to_a #=> [:b, :d]
# [:a, :b, :c, :d].step(3).to_a #=> [:c]
# [:a, :b, :c, :d].step(5).to_a #=> []
#
# CREDIT: Ryan Duryea
def step(n) #:yield:
if block_given?
((n - 1)...size).step(n).each do |i|
yield(fetch(i))
end
else
Enumerator.new(size / n) do |y|
((n - 1)...self.size).step(n).each { |i| y << fetch(i) }
end
end
end
end
@@ -0,0 +1,16 @@
class Array
# Store a value at a given index. Store is an alias for #[]=.
#
# Example:
#
# a = []
# a.store(1, "A")
# a[1] #=> "A"
#
# Returns the stored object.
alias_method :store, :[]=
end
@@ -0,0 +1 @@
require 'facets/array/from'
@@ -0,0 +1,19 @@
class Array
# Convert an associative array to a Hash.
#
# Examples
#
# [[:a, 1], [:b, 2]].to_h
# #=> {:a=>1, :b=>2}
#
# Returns [Hash].
#
def to_h
h = {}
each{ |(k,v)| h[k] = v }
h
end unless method_defined?(:to_h)
end
@@ -0,0 +1,50 @@
class Array
# Construct a new array created by traversing the array and its
# sub-arrays, executing the given block on the elements.
#
# Examples
#
# h = ["A", "B", ["X", "Y"]]
# g = h.traverse{ |e| e.downcase }
# g #=> ["a", "b", ["x", "y"]]
#
# This is the same as <code>recursive.map</code> and will
# likely be deprecated in the future because of it.
#
# Returns new array. [Array]
#
# CREDIT: Trans
def traverse(&block)
if block_given?
map do |e|
if e.respond_to?(:to_ary)
e.to_ary.traverse(&block)
else
block.call(e)
end
end
else
to_enum(:traverse)
end
end
# Like #recursive_map, but will change the array in place.
#
# Examples:
#
# h = ["A", "B", ["X", "Y"]]
# h.traverse!{ |e| e.downcase }
# h #=> ["a", "b", ["x", "y"]]
#
# Returns self. [Array]
#
# CREDIT: Trans
def traverse!(&block)
replace(traverse(&block))
end
end
@@ -0,0 +1,24 @@
class Array
# Like #uniq, but determines uniqueness based on a given block.
# As can be seen in the following examples, order is significant.
#
# Examples
#
# a = (-5..5).to_a
# a.uniq_by!{ |i| i*i }
# a #=> [-5, -4, -3, -2, -1, 0]
#
# a = (-5..5).to_a.reverse
# a.uniq_by!{ |i| i*i }
# a #=> [5, 4, 3, 2, 1, 0]
#
# Returns [Array] of unique elements.
#
def uniq_by! #:yield:
h = {}
replace( inject([]){|a,x| h[yield(x)] ||= a << x} )
end
end
@@ -0,0 +1,29 @@
class Array
# Enumerates permutation of Array.
# Unlike Array#permutation, there are no duplicates in generated permutations.
# Instead, elements must be comparable.
#
# [1,1,2,2,3].unique_permutation(2).to_a
# #=> [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2]]
# # Note: [1,1,2,2,3].permutation(2).to_a
# #=> [[1, 1], [1, 2], [1, 2], [1, 3], [1, 1], [1, 2], [1, 2], [1, 3], [2, 1], [2, 1], [2, 2], [2, 3], [2, 1], [2, 1], [2, 2], [2, 3], [3, 1], [3, 1], [3, 2], [3, 2]]
#
# CREDIT: T. Yamada
def unique_permutation(n=self.size)
return to_enum(:unique_permutation,n) unless block_given?
return if n<0||self.size<n
a=self.sort # sort is O(nlogn), so I believe this is not so costly. (Also sort is not destructive)
yield a[0,n]
loop{
a=a[0,n]+a[n..-1].reverse
k=(a.size-2).downto(0).find{|i|a[i]<a[i+1]}
break if !k
l=(a.size-1).downto(k+1).find{|i|a[k]<a[i]}
a[k],a[l]=a[l],a[k]
a=a[0,k+1]+a[k+1..-1].reverse
yield a[0,n]
}
end
end
@@ -0,0 +1,20 @@
require 'facets/array/average'
class Array
# Calculate the variance of an array of numbers
#
# Examples
#
# [].variance #=> nil
# [1, 2, 3].variance #=> 0.6666666666666666
# [96, 35, 72, 30, 75, 33, 68, 13, 49, 71].variance #=> 609.76
# [36, -67, -17, 85, -46, -64, -23, -13, 89, -47].variance #=> 2989.0099999999993
# [60.7829, 31.2622, 20.626, 78.8907, 61.5328].variance #=> 459.1941339495999
#
def variance
avg = average
map {|n| (n - avg) ** 2 }.average
end
end
@@ -0,0 +1,21 @@
class Array
# Class level rendition of Array#zip.
#
# arrays - List of arrays to zip. [Array<Array>]
#
# Example:
#
# Array.zip([1,2],[3,4]]
# #=> [[1,3],[2,4]]
#
# Returns arranged array of arrays. [Array<Array>]
#
# Returns an empty array if no arguments are given. [Array]
def self.zip(*arrays)
return [] if arrays.empty?
return arrays[0].zip(*arrays[1..-1])
end
end
@@ -0,0 +1,12 @@
require_relative 'binding/caller.rb'
require_relative 'binding/callstack.rb'
require_relative 'binding/call_stack.rb'
require_relative 'binding/defined.rb'
require_relative 'binding/op.rb'
require_relative 'binding/op_get.rb'
require_relative 'binding/op_set.rb'
require_relative 'binding/self.rb'
require_relative 'binding/with.rb'
require_relative 'binding/__callee__.rb'
require_relative 'binding/__method__.rb'
@@ -0,0 +1 @@
require 'facets/binding/caller'
@@ -0,0 +1 @@
require 'facets/binding/caller'
@@ -0,0 +1 @@
require 'facets/kernel/callstack'
@@ -0,0 +1,42 @@
require 'facets/binding/callstack'
class Binding
# Returns the call stack, same format as Kernel#caller()
#
def caller( skip=0 )
eval("caller(#{skip})")
end
# Return the line number on which the binding was created.
#
def __LINE__
Kernel.eval("__LINE__", self)
end
# Returns file name in which the binding was created.
#
def __FILE__
Kernel.eval("__FILE__", self)
end
# Return the directory of the file in which the binding was created.
#
def __DIR__
File.dirname(self.__FILE__)
end
# Retreive the current running method.
#
def __method__
Kernel.eval("__method__", self)
end
# Retreive the current running method.
#
def __callee__
Kernel.eval("__callee__", self)
end
end
@@ -0,0 +1 @@
require 'facets/kernel/callstack'
@@ -0,0 +1,10 @@
class Binding
# Returns the nature of something within the context of the binding.
# Returns nil if that thing is not defined.
def defined?(x)
eval("defined? #{x}")
end
end
@@ -0,0 +1,4 @@
# This file is here for backward compatibility only.
# It can be deprecated eventually.
require 'facets/binding/op_get'
@@ -0,0 +1,25 @@
class Binding
# Returns the value of some variable.
#
# a = 2
# binding["a"] #=> 2
#
def []( x )
eval( x.to_s )
end
# Set the value of a local variable.
#
# binding["a"] = 4
# a #=> 4
#
# @deprecated No longer wortks in Ruby 1.9+.
#
# @see Binding#with for an alternative.
def []=( l, v )
eval( "lambda {|v| #{l} = v}").call( v )
end
end
@@ -0,0 +1 @@
require 'facets/binding/op_get'
@@ -0,0 +1,15 @@
class Binding
# This is already defined by Rubinius:
# Kernel.eval('Rubinius::VariableScope.current.self', self)
unless method_defined?(:self)
# Returns self of the binding's context.
def self
eval('self')
end
end
end
@@ -0,0 +1,12 @@
class Binding
# Returns a new binding with local varaibles set.
#
# CREDIT: Trans
def with(_local_variables, &_yields)
eval("lambda{ |#{_local_variables.keys.join(',')},&yields| binding }").call(*_local_variables.values, &_yields)
end
end
@@ -0,0 +1,121 @@
require 'facets/kernel/true'
require 'facets/kernel/false'
module Kernel
# Boolean conversion for not being nil or false.
# Other classes may redefine this to suite the
# particular need.
#
# "yes".to_b #=> true
# "abc".to_b #=> false
#
# true.to_b #=> true
# false.to_b #=> false
# nil.to_b #=> false
#
# CREDIT: Ara T. Howard, Trans
def to_b
self ? true : false
end
# All objects except false and nil are "true".
def to_bool
true
end
# Returns true is an object is class TrueClass
# or FalseClass, otherwise false.
#
# true.bool? #=> true
# false.bool? #=> true
# nil.bool? #=> false
#
def bool?
(true == self or false == self)
end
end
class TrueClass
def to_bool
self
end
end
class FalseClass
def to_bool
self
end
end
class NilClass
def to_bool
false
end
end
class Numeric
# Provides a boolean interpretation of self.
# If self == 0 then false else true.
#
# 0.to_b #=> false
# 1.to_b #=> true
# 2.3.to_b #=> true
#
def to_b
self == 0 ? false : true
end
end
class String
# Interpret common affirmative string meanings as true,
# otherwise nil or false. Blank space and case are ignored.
# The following strings that will return true ...
#
# true
# yes
# on
# t
# 1
# y
# ==
#
# The following strings will return nil ...
#
# nil
# null
#
# All other strings return false.
#
# Here are some exmamples.
#
# "true".to_b #=> true
# "yes".to_b #=> true
# "no".to_b #=> false
# "123".to_b #=> false
#
def to_b
case self.downcase.strip
when 'true', 'yes', 'on', 't', '1', 'y', '=='
return true
when 'nil', 'null'
return nil
else
return false
end
end
end
class Array
# Boolean conversion for not empty?
def to_b
! self.empty?
end
end
class Hash
# Boolean conversion for not empty?
def to_b
! self.empty?
end
end
@@ -0,0 +1 @@
require 'facets/class/cattr'
@@ -0,0 +1,9 @@
require_relative 'class/descendants.rb'
#require_relative 'class/hierarchically' # uncommon
require_relative 'class/methodize.rb'
require_relative 'class/pathize.rb'
#require_relative 'class/preallocate.rb' # uncommon
#require_relative 'class/singleton.rb' # uncommon
require_relative 'class/subclasses.rb'
require_relative 'class/to_proc.rb'
@@ -0,0 +1 @@
require 'facets/module/cattr'
@@ -0,0 +1,36 @@
require 'facets/class/subclasses'
class Class
# List all descedents of this class.
#
# class A ; end
# class B < A; end
# class C < A; end
# A.descendants #=> [B,C]
#
# You may also limit the generational distance the subclass may be from
# the parent class.
#
# class X ; end
# class Y < X; end
# class Z < Y; end
# X.descendants #=> [Y,Z]
# X.descendants(1) #=> [Y]
#
# NOTE: This is a intensive operation. Do not expect it to be very fast.
#
# @author Roger Pack
def descendants(generations=-1)
descendants = []
subclasses.each do |k|
descendants << k
if generations != 1
descendants.concat(k.descendants(generations - 1))
end
end
descendants
end
end
@@ -0,0 +1,12 @@
module Kernel
# Hierarchically apply a block, passing each ancestor to the block
# starting at the root ancestor and working toward the current object.
#
def hierarchically(&block)
ancestors.reverse_each do |m|
block.call(m)
end
end
end
@@ -0,0 +1,19 @@
require 'facets/string/methodize'
class Class
# Translate a class name to a suitable method name.
#
# module ::Example
# class MethodizeExample
# end
# end
#
# Example::MethodizeExample.methodize #=> "example__methodize_example"
#
def methodize
name.methodize
end
end
@@ -0,0 +1,19 @@
require 'facets/string/pathize'
class Class
# Converts a class name to a unix path.
#
# module ::Example
# class PathizeExample
# end
# end
#
# Example::PathizeExample.pathize #=> "example/pathize_example"
#
def pathize
name.pathize
end
end
@@ -0,0 +1,55 @@
class Class
# Designate aspect modules to be added to a object at instantiation.
#
# class Firetruck
# def put_out_fire(option)
# "Put out #{option}"
# end
# end
#
# module FastFiretruck
# def put_out_fire(option)
# super("very #{option}!")
# end
# end
#
# Firetruck.preallocate(FastFiretruck)
#
# ft = Firetruck.new
# ft.put_out_fire('fast') #=> "Put out very fast!"
#
# This method is very similar to the idea of #prepend, but it has some
# limitations in that it works by overriding #new and #allocate and extends
# an object with the aspect modules on instantiation. A true #prepend
# implementation would not have to do this --but would be a natural part
# of the class heirarchy instead. For this reason, this method has been
# named #preallocate, rather than #prepend.
#
# NOTE: This method is not a common core extension and is not
# loaded automatically when using <code>require 'facets'</code>.
#
# CREDIT: Trans
#
# @uncommon
# require 'facets/class/preallocate'
#
def preallocate(aspect)
_new = method(:new)
_allocate = method(:allocate)
(class << self; self; end).class_eval do
define_method(:new) do |*args|
o = _new.call(*args)
o.extend aspect
o
end
define_method(:allocate) do |*args|
o = _allocate.call(*args)
o.extend aspect
o
end
end
end
end
@@ -0,0 +1 @@
require 'facets/class/singleton_class'
@@ -0,0 +1,16 @@
class Class
# Return true if a class is the singleton class of
# an object.
#
# @uncommon
# require 'facets/class/singleton_class'
#
def singleton_class?
! ancestors.include?( self ) rescue false
end
# @deprecated
alias :singleton? :singleton_class?
end
@@ -0,0 +1,28 @@
class Class
if defined?(Class.__subclasses__) # Rubinius
# Returns an array with the direct children of +self+.
#
# Integer.subclasses # => [Fixnum, Bignum]
#
alias_method :subclasses, :__subclasses__
else
# Returns an array with the direct children of +self+.
#
# Integer.subclasses # => [Fixnum, Bignum]
#
def subclasses
list = []
ObjectSpace.each_object(Class) do |c|
list.unshift c if c.superclass == self
end
list.uniq
end
end
end
@@ -0,0 +1,25 @@
class Class
# Convert instatiation of a class into a Proc.
#
# class Person
# def initialize(name)
# @name = name
# end
#
# def inspect
# @name.to_str
# end
# end
#
# persons = %w(john bob jane hans).map(&Person)
#
# persons.map{ |p| p.inspect } #=> ['john', 'bob', 'jane', 'hans']
#
# CREDIT: Daniel Schierbeck
def to_proc
proc{|*args| new(*args)}
end
end
@@ -0,0 +1,8 @@
require_relative 'comparable/at_least.rb'
require_relative 'comparable/at_most.rb'
require_relative 'comparable/bound.rb'
require_relative 'comparable/cap.rb'
require_relative 'comparable/clip.rb'
require_relative 'comparable/cmp.rb'
require_relative 'comparable/op_get.rb'
@@ -0,0 +1 @@
require 'facets/comparable/cap'
@@ -0,0 +1 @@
require 'facets/comparable/cap'
@@ -0,0 +1 @@
require 'facets/comparable/clip'
@@ -0,0 +1,34 @@
module Comparable
# Returns the lower of self or x.
#
# 4.at_least(5) #=> 5
# 6.at_least(5) #=> 6
#
# CREDIT: Florian Gross
def at_least(lower)
(self >= lower) ? self : lower
end
# Returns the greater of self or x.
#
# 4.at_most(5) #=> 4
# 6.at_most(5) #=> 5
#
# CREDIT: Florian Gross
def at_most(upper)
(self <= upper) ? self : upper
end
# Returns the greater of self or x.
#
# 4.cap(5) #=> 4
# 6.cap(5) #=> 5
#
# CREDIT: Trans
alias_method :cap, :at_most
end
@@ -0,0 +1,38 @@
module Comparable
# Returns self if above the given lower bound, or
# within the given lower and upper bounds,
# otherwise returns the the bound of which the
# value falls outside.
#
# 4.clip(3) #=> 4
# 4.clip(5) #=> 5
# 4.clip(2,7) #=> 4
# 9.clip(2,7) #=> 7
# 1.clip(2,7) #=> 2
#
# CREDIT Florian Gross, Trans
def clip(lower, upper=nil)
return lower if self < lower
return self unless upper
return upper if self > upper
return self
end
# Returns self if above the given lower bound, or
# within the given lower and upper bounds,
# otherwise returns the the bound of which the
# value falls outside.
#
# 4.bound(3) #=> 4
# 4.bound(5) #=> 5
# 4.bound(2,7) #=> 4
# 9.bound(2,7) #=> 7
# 1.bound(2,7) #=> 2
#
# CREDIT: Florian Gross
alias_method :bound, :clip
end
@@ -0,0 +1,41 @@
module Comparable
# Alternate name for comparison operator #<=>.
#
# 3.cmp(1) #=> 1
# 3.cmp(3) #=> 0
# 3.cmp(10) #=> -1
#
# This fundamental compare method is used to keep
# comparison compatible with <tt>#succ</tt>.
#
# CREDIT: Peter Vanbroekhoven
def cmp(o)
self<=>o
end
end
class String
# Compare method that takes length into account.
# Unlike #<=>, this is compatible with #succ.
#
# "abc".cmp("abc") #=> 0
# "abcd".cmp("abc") #=> 1
# "abc".cmp("abcd") #=> -1
# "xyz".cmp("abc") #=> 1
#
# CREDIT: Peter Vanbroekhoven
#
# TODO: Move String#cmp to string/ directory.
def cmp(other)
return -1 if length < other.length
return 1 if length > other.length
self <=> other # alphabetic compare
end
end
@@ -0,0 +1,45 @@
module Comparable
# Automatically generate comparitive definitions based on
# attribute fields.
#
# include Comparable[:a, :b]
#
# is equivalent to including a module containing:
#
# def <=>(other)
# cmp = self.a <=> other.a; return cmp unless cmp == 0
# cmp = self.b <=> other.b; return cmp unless cmp == 0
# 0
# end
#
def self.[](*accessors)
Module.new do
include Comparable
define_method(:comparability){ accessors }
define_method(:<=>) do |other|
comparability.each do |a|
cmp = (send(a) <=> other.send(a))
break cmp unless cmp == 0
end
end
end
end
end
# Would it be nice if we could define comparability for all objects?
# Then Comparable[] method would not be needed. Just:
#
# module Comparable
#
# def <=>(other)
# comparability.each do |field|
# cmp = send(field) <=> other.send(field); return cmp unless cmp == 0
# end
# end
#
# end
#
# But I fear it might break other code.
@@ -0,0 +1,77 @@
require 'facets/enumerator'
#require 'facets/enumerable/take'
# Classes which include Denumerable will get versions of map,
# select, and so on, which return a Denumerator, so that they
# work horizontally without creating intermediate arrays.
#
# @author Brian Candler
# @author Trans
module Denumerable
#
def map
Denumerator.new do |output|
each do |*input|
output.yield yield(*input)
end
end
end
alias :collect :map
#
def select
Denumerator.new do |output|
each do |*input|
output.yield(*input) if yield(*input)
end
end
end
alias :find_all :select
#
def reject
Denumerator.new do |output|
each do |*input|
output.yield(*input) unless yield(*input)
end
end
end
# Limit to the first n items in the list
def take(n)
Denumerator.new do |output|
count = 0
each do |*input|
break if count >= n
output.yield(*input)
count += 1
end
end
end
# Skip the first n items in the list
def skip(n)
Denumerator.new do |output|
count = 0
each do |*input|
output.yield(*input) if count >= n
count += 1
end
end
end
# TODO: add more methods, e.g. grep, take_while etc.
end
# = Denumerator
#
# A class like Enumerator, but which has 'lazy' versions of map, select etc.
#
class Denumerator < Enumerator
include Denumerable
end
@@ -0,0 +1,7 @@
require_relative 'dir/ascend.rb'
require_relative 'dir/descend.rb'
require_relative 'dir/each_child.rb'
require_relative 'dir/multiglob.rb'
require_relative 'dir/parent.rb'
require_relative 'dir/recurse.rb'
@@ -0,0 +1,56 @@
class Dir
# TODO: Make instance method versions ?
# Ascend a directory path.
#
# a = []
#
# Dir.ascend("/var/log") do |path|
# a << path
# end
#
# a #=> ['/var/log', '/var', '/']
#
# CREDIT: Daniel Berger, Jeffrey Schwab
#
# TODO: Make it work with windows too
# use FileTest.root?
def self.ascend(dir, inclusive=true, &blk)
dir = dir.dup
blk.call(dir) if inclusive
ri = dir.rindex('/')
while ri
dir = dir.slice(0...ri)
if dir == ""
blk.call('/') ; break
end
blk.call( dir )
ri = dir.rindex('/')
end
end
# Descend a directory path.
#
# d = []
#
# Dir.descend("/var/log") do |path|
# d << path
# end
#
# d #=> ['/', '/var', '/var/log']
#
# CREDIT: Daniel Berger, Jeffrey Schwab
def self.descend(path) #:yield:
paths = path.split('/')
paths.size.times do |n|
pth = File.join(*paths[0..n])
pth = "/" if pth == ""
yield(pth)
end
end
end
@@ -0,0 +1 @@
require 'facets/dir/ascend'
@@ -0,0 +1,16 @@
class Dir
# Like #each, except the "." and ".." special files are ignored.
# You can use +ignore+ to override '.' and '..' and ignore
# other entries via a exact match or regular expression.
#
# CREDIT: Tyler Rick
def each_child(*ignore)
ignore = ['.', '..'] if ignore.empty?
each do |file|
yield file unless ignore.any?{ |i| i === file }
end
end
end
@@ -0,0 +1,20 @@
class Dir
# Lookup directory tree for a path.
#
# TODO: Make a non class method version of this?
#
# Returns full path or `nil` if not found. [String,nil]
def self.lookup(rel_path, parent_path='.')
while true
path = File.expand_path(rel_path, parent_path)
return path if File.exists?(path)
return nil if path == '/'
parent_path = File.expand_path('..', parent_path)
end
end
end
@@ -0,0 +1,78 @@
class Dir
# Like +glob+ but can take multiple patterns.
#
# Dir.multiglob('tmp/*.rb', 'tmp/*.py')
#
# Rather then constants for options multiglob accepts a trailing options
# hash of symbol keys...
#
# :noescape File::FNM_NOESCAPE
# :casefold File::FNM_CASEFOLD
# :pathname File::FNM_PATHNAME
# :dotmatch File::FNM_DOTMATCH
# :strict File::FNM_PATHNAME && File::FNM_DOTMATCH
#
# It also has an option for recurse...
#
# :recurse Recurively include contents of directories.
#
# For example
#
# Dir.multiglob('tmp/*', :recurse => true)
#
# would have the same result as
#
# Dir.multiglob('tmp/**/*')
#
def self.multiglob(*patterns)
options = (Hash === patterns.last ? patterns.pop : {})
if options.delete(:recurse)
##patterns += patterns.collect{ |f| File.join(f, '**', '**') }
multiglob_r(*patterns)
end
bitflags = 0
bitflags |= File::FNM_NOESCAPE if options[:noescape]
bitflags |= File::FNM_CASEFOLD if options[:casefold]
bitflags |= File::FNM_PATHNAME if options[:pathname] or options[:strict]
bitflags |= File::FNM_DOTMATCH if options[:dotmatch] or options[:strict]
patterns = [patterns].flatten.compact
if options[:recurse]
patterns += patterns.collect{ |f| File.join(f, '**', '**') }
end
files = []
files += patterns.collect{ |pattern| Dir.glob(pattern, bitflags) }.flatten.uniq
return files
end
# The same as +multiglob+, but recusively includes directories.
#
# Dir.multiglob_r('tmp')
#
# is equivalent to
#
# Dir.multiglob('tmp', :recurse=>true)
#
# The effect of which is
#
# Dir.multiglob('tmp', 'tmp/**/**')
#
def self.multiglob_r(*patterns)
options = Hash === patterns.last ? patterns.pop : {}
matches = multiglob(*patterns)
directories = matches.select{ |m| File.directory?(m) }
matches += directories.map{ |d| multiglob_r(File.join(d, '**'), options) }.flatten
matches.uniq
##options = (Hash === patterns.last ? patterns.pop : {})
##options[:recurse] = true
##patterns << options
##multiglob(*patterns)
end
end
@@ -0,0 +1,16 @@
class Dir
# Is a path parental to another?
#
# Dir.parent?('parent', 'parent/child') #=> true
#
# TODO: Needs improvement.
#
# TODO: Instance version?
def self.parent?(parent_path, child_path)
%r|^#{Regexp.escape(parent_path)}| =~ child_path ? true : false
end
end
@@ -0,0 +1,35 @@
class Dir
# Recursively scan a directory and pass each file to the given block.
#
# Dir.recurse('.') do |path|
# # ...
# end
#
# CREDIT: George Moschovitis
#
# TODO: If fully compatible, reimplement as alias of Find.find,
# or just copy and paste Find.find code here if it looks more robust.
#
def self.recurse(path='.', &block)
list = []
stoplist = ['.', '..']
Dir.foreach(path) do |f|
next if stoplist.include?(f)
filename = (path == '.' ? f : path + '/' + f)
list << filename
block.call(filename) if block
if FileTest.directory?(filename) and not FileTest.symlink?(filename)
list.concat(Dir.recurse(filename, &block))
end
end
list
end
# Same as Dir#recurse.
def self.ls_r(path='.', &block)
recurse(path, &block)
end
end

Some files were not shown because too many files have changed in this diff Show More