This commit is contained in:
@@ -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'
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user