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
+40
View File
@@ -0,0 +1,40 @@
require 'facets/version.rb'
require 'facets/array.rb'
require 'facets/binding.rb'
require 'facets/boolean.rb'
require 'facets/class.rb'
require 'facets/comparable.rb'
require 'facets/denumerable.rb'
require 'facets/dir.rb'
require 'facets/enumerable.rb'
require 'facets/enumerator.rb'
require 'facets/exception.rb'
require 'facets/file.rb'
require 'facets/filetest.rb'
require 'facets/float.rb'
require 'facets/functor.rb'
require 'facets/hash.rb'
require 'facets/indexable.rb'
require 'facets/integer.rb'
require 'facets/kernel.rb'
require 'facets/lazy.rb'
require 'facets/matchdata.rb'
require 'facets/method.rb'
require 'facets/module.rb'
require 'facets/na.rb'
require 'facets/nilclass.rb'
require 'facets/numeric.rb'
require 'facets/object.rb'
require 'facets/objectspace.rb'
require 'facets/proc.rb'
require 'facets/process.rb'
require 'facets/range.rb'
require 'facets/regexp.rb'
require 'facets/string.rb'
require 'facets/struct.rb'
require 'facets/symbol.rb'
require 'facets/time.rb'
#require 'facets/to_hash.rb'
require 'facets/unboundmethod.rb'
+80
View File
@@ -0,0 +1,80 @@
---
revision: 2013
type: ruby
sources:
- Indexfile
- Gemfile
authors:
- name: Thomas Sawyer
email: transfire@gmail.com
organizations:
- name: Rubyworks
requirements:
- groups:
- test
version: ">= 0"
name: lemon
- groups:
- test
version: ">= 0"
name: qed
- groups:
- test
version: ">= 0"
name: rubytest-cli
- groups:
- test
version: ">= 0"
name: rake
- groups:
- test
version: ">= 0"
name: simplecov
- groups:
- guard
version: ">= 0"
name: guard
conflicts: []
alternatives: []
resources:
- type: home
uri: http://rubyworks.github.com/facets
label: Homepage
- type: code
uri: http://github.com/rubyworks/facets
label: Source Code
- type: docs
uri: http://rubyworks.github.com/facets/learn.html
label: Documentation
- type: wiki
uri: http://wiki.github.com/rubyworks/facets
label: User Guide
- type: talk
uri: http://groups.google.com/group/facets-universal
repositories:
- name: upstream
scm: git
uri: git@github.com:rubyworks/facets.git
categories: []
copyrights:
- holder: Rubyworks
year: '2004'
license: BSD-2-Clause
customs: []
paths:
load:
- lib/core
- lib/standard
name: facets
title: Ruby Facets
version: 3.1.0
summary: The orginal well curated collection of extension methods for Ruby.
slogan: ALL YOUR BASE ARE BELONG TO RUBY!
description: Facets is the premier collection of extension methods for the Ruby programming
language. Facets extensions are unique by virtue of thier atomicity. They are stored
in individual files allowing for highly granular control of requirements. In addition,
Facets includes a few additional classes and mixins suitable to wide variety of
applications.
scm_uri: https://github.com/rubyworks/facets/tree/master
created: '2004-12-16'
date: '2016-05-09'
@@ -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

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