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

This commit is contained in:
2026-09-16 13:11:16 -06:00
parent c8ac4fcae5
commit 4cee170d66
17576 changed files with 895740 additions and 2 deletions
@@ -0,0 +1,53 @@
require 'facets/functor'
class Object
# Objectified message or block application. Only a message
# or a block can be given, not both.
#
# msg - method and arguments [Array]
# blk - procedure block [Proc]
#
# Examples
#
# a = [1,2,3,4,5]
# c = a.against(:>, 2)
# c.select #=> [3,4,5]
#
# a = [1,2,3,4,5]
# c = a.against(:>)
# c.select(2) #=> [3,4,5]
#
# Returns [Functor]
#
# TODO: Better name for this method?
def against(*msg, &blk)
raise ArgumentError, "too many arguments" if blk && !msg.empty?
this = self
blk = ::Proc.new{ |x,*a| x.__send__(*msg, *a) } unless blk
#if blk
Functor.new do |m, *a, &b|
if b
b2 = ::Proc.new{ |*x| blk.call(*b.call(*x), *a) }
else
b2 = blk
end
this.__send__(m, &b2)
end
#else
# Functor.new do |m, *a, &b|
# if b
# b2 = ::Proc.new{ |*x| b.call(*x).__send__(*msg, *a) }
# else
# b2 = ::Proc.new{ |x| x.__send__(*msg, *a) }
# end
# this.__send__(m, &b2)
# end
#end
end
end
@@ -0,0 +1,343 @@
# = ArgVector
#
# == Synopsis
#
# ArgVector provides a very simple means of parsing
# command line arguments.
#
# Unlike other more complex libs this provides only
# the most basic and standard parsing functionality.
# In many cases that's all one really needs.
#
# Usage is straight foward. Simply instantiate the
# class and query it for the particular "views" of
# the command line you want.
#
# cargs = ArgVector.new("-a foo -b=2")
#
# cargs.parameters #=> [['foo'],{'a'=>true,'b'=>'2'}]
# cargs.flags #=> ['a']
# cargs.preoptions #=> {'a'=>true}
# cargs.preflags #=> ['a']
# cargs.subcommand #=> ['foo', [], {'b'=>'2'}]
#
# == Authors
#
# * Thomas Sawyer
#
# == Copying
#
# Copyright (c) 2006 Thomas Sawyer
#
# Ruby License
#
# This module is free software. You may use, modify, and/or
# redistribute this software under the same terms as Ruby.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE.
require 'shellwords'
# = Argvector
#
# Argvector provides a very simple means of parsing
# command line arguments.
#
# Unlike other more complex libs this provides only
# the most basic and standard parsing functionality.
# In many cases that's all one really needs.
#
# Usage is straight foward. Simply instantiate the
# class and query it for the particular "views" of
# the command line you want.
#
# cargs = Argvector.new("-a foo -b=2")
#
# cargs.parameters #=> [['foo'],{'a'=>true,'b'=>'2'}]
# cargs.flags #=> ['a']
# cargs.preoptions #=> {'a'=>true}
# cargs.preflags #=> ['a']
# cargs.subcommand #=> ['foo', [], {'b'=>'2'}]
#
class Argvector
def self.parameters(*args)
new.parameters(*args)
end
attr :line
attr :argv
attr :arity
##attr :opts
##alias :flags :options
# Takes the command line string (or array) and options.
# Options have flags and end with a hash of option arity.
#
def initialize(line=nil, arity=nil)
@line, @argv = parse_line(line)
@arity = parse_arity(arity||{})
parse
end
public
# Returns operand array.
def operands
@operands
end
# deprecate alias ?
alias arguments operands
# Returns options hash.
def options
@options
end
# Returns [operands, options], which is good for plugging
# directly into a method.
def parameters
return @operands, @options
end
# Return flags, which are true options.
def flags
f = []
@options.each do |k, v|
if TrueClass===v or FalseClass===v # not that it's ever false
f << k
end
end
return f
end
# Assumes the first operand is a "subcommand" and
# returns it and the argments following it as
# parameters.
def subcommand_with_parameters
opts, args = *parse_preoptions(argv)
cmd = args.shift
subargs = self.class.new(args, @arity)
return [cmd, *subargs.parameters]
end
alias subcommand subcommand_with_parameters
#
def subcommand_with_preoptions
pre, args = *parse_preoptions(argv)
cmd = args.shift
subargs = self.class.new(args, @arity)
args, opts = *subargs.parameters
return [cmd, args, pre.merge(opts)]
end
# Assumes the first operand is a "subcommand" and
# returns it and the argments following it as
# another Arguments object.
#
# TODO: This probably should be called 'subcommand'.
#
def subcommand_with_arguments
opts, args = *parse_preoptions(argv)
cmd = args.shift
subargs = self.class.new(args, @arity)
return cmd, subargs
end
# Returns a hash of options that occur before
# the first operand. This works well with
# subcommand to get the main command's options.
#
# line = "--trace stamp --file VERSION"
# cargs = Argvector.new(line)
# opts = cargs.preoptions
# opts #=> {"trace"=>true}
#
def preoptions
preopts, remainder = *parse_preoptions(argv)
return preopts
end
# Same as +flags+ but only returns flags in the
# preoptions.
def preflags
preopts, remainder = *parse_preoptions(argv)
f = []
preopts.each do |k, v|
if TrueClass===v or FalseClass===v # not that it's ever false
f << k
end
end
return f
end
# Like parameters but without allowing for duplicate options.
def parameters_without_duplicates
opts = {}
@options.each do |k,v|
if Array===v
opts[k] = v[0]
else
opts[k] = v
end
end
return @operands, opts
end
#private
# Basic parser partitions the command line into options and
# operands. Options are converted to a hash and the two
# parts are returned.
#
# line = "--trace stamp --file=VERSION"
# argv = Argvector.new(line)
#
# args, keys = *argv.parse
#
# args #=> ["stamp"]
# keys #=> {"trace"=>true, "file"=>"VERSION"}
#
def parse
args = assoc_options(argv) #, *opts_arity)
opts, opds = args.partition{ |a| Array === a }
@operands = opds
@options = format_options(opts)
return @operands, @options
end
# First pass parser to split the command line into an
# array using Shellwords, if not already so divided.
def parse_line(line=nil)
if line
case line
when String
argv = Shellwords.shellwords(line)
else
argv = line.to_ary.dup
line = argv.join(' ')
end
else
argv = ARGV.dup
line = argv.join(' ')
end
return line, argv
end
## Ensure opts are a uniform.
##
##def clean_opts( opts )
## opts2 = opts.collect{ |o| o.to_sym }
## opts2 = opts2 & [:simple, :repeat] # valid options only
## return opts2
##end
# Ensure arity is uniform.
def parse_arity(arity)
arity2 = {}
arity.each{ |k,v| arity2[k.to_s] = v.to_i }
return arity2
end
# Parse preoptions. A "preoption" is one that
# occurs before the first operans (if any).
def parse_preoptions(args)
##args = args.dup
args = multi_flag(args) #unless opts.include?(:simple)
flags = []
while args.first =~ /^-/
key = args.shift
key.sub!(/^-{1,2}/,'')
if key.index('=')
key, val = key.split('=')
elsif a = arity[key]
val = args.slice!(0,a)
val = val.first if a == 1
else
val = true
end
flags << [key, val]
end
flags = format_options(flags)
return flags, args
end
# Parse flags takes the command line and transforms it such that
# flags (eg. -x and --x) are elemental associative arrays.
#
# line = "--foo hello --try=this"
# argv = Argvector.new(line)
#
# args = line.split(/\s/)
# argv.assoc_options(args) #=> [ ["foo",true], "hello", ["try","this"] ]
#
def assoc_options(args)
##args = args.dup
args = multi_flag(args) #unless opts.include?(:simple)
i = 0
while i < args.size
arg = args[i]
case arg
when /^-/
arg = arg.sub(/^-{1,2}/,'')
if arg.index('=')
key, val = arg.split('=')
args[i] = [key, val||true]
elsif arity.key?(arg)
cnt = arity[arg]
key = arg
val = args[i+1,cnt]
args[i,cnt+1] = [[key, *val]]
i += (cnt - 1)
else
key = arg
args[i] = [key,true]
end
end
i += 1
end
return args
end
# Split single letter option groupings into separate options.
# ie. -xyz => -x -y -z
def multi_flag(args=nil)
args ||= argv
args.collect { |arg|
if md = /^-(\w{2,})/.match( arg )
md[1].split(//).collect { |c| "-#{c}" }
else
arg.dup
end
}.flatten
end
# Format flag options. This converts the associative array of
# options/flags into a hash. Repeat options will be placed in arrays.
def format_options(assoc_options)
opts = {}
assoc_options.each do |k,v|
if opts.key?(k)
opts[k] = [opts[k]].flatten << v
else
opts[k] = v
end
end
return opts
end
end
ArgVector = Argvector
@@ -0,0 +1,75 @@
# Facets' BasicObject is an implementation of Jim Weirich's BlankSlate.
#
# BlankSlate
# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
# All rights reserved.
#
# Since Ruby 1.9 has a BasicObject class this will of course be
# deprecated as 1.9 goes mainstream.
unless defined? BasicObject # in case it already exists!
# BasicObject provides an abstract base class with no predefined
# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
# BlankSlate is useful as a base class when writing classes that
# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
class BasicObject
class << self
# Hide the method named +name+ in the BlankSlate class. Don't
# hide +instance_eval+ or any method beginning with "__".
#
# According to 1.9.1 it should have only these methods:
#
# * #__send__
# * #instance_eval
# * #instance_exec
# * #equal?
# * #==
# * #!
# * #!=
# * respond_to?
#
# Seems to me it should have #__id__ too.
def hide(name)
undef_method name if
instance_methods.include?(name.to_s) and
name !~ /^(__|respond_to\?|instance_eval$|instance_exec$|equal\?$|\=\=$)/
end
end
instance_methods.each{ |m| hide(m) }
end
# Since Ruby is very dynamic, methods added to the ancestors of
# BlankSlate <em>after BlankSlate is defined</em> will show up in the
# list of available BlankSlate methods. We handle this by defining a
# hook in the Object and Kernel classes that will hide any defined
module Kernel #:nodoc:
class << self
alias_method :facets_basic_object_method_added, :method_added
# Detect method additions to Kernel and remove them in the
# BlankSlate class.
def method_added(name)
facets_basic_object_method_added(name)
return if self != Kernel
BasicObject.hide(name)
end
end
end
class Object #:nodoc:
class << self
alias_method :facets_basic_object_method_added, :method_added
# Detect method additions to Object and remove them in the
# BlankSlate class.
def method_added(name)
facets_basic_object_method_added(name)
return if self != Object
BasicObject.hide(name)
end
end
end
end
@@ -0,0 +1,44 @@
class Binding
# Allows the evaluation of blocks by a Binding in the same way that strings
# can be evaluated.
#
# x = 5
# $my_binding = binding
#
# class Test # just here to provide a scope gate
# $my_binding.block_exec { x }
# end
#
# # => 5
#
# NOTE: The implementation of this method uses a method_missing trick.
# Consequently it is a bit of a hack.
#
def block_exec(*args, &block)
BlockEnvironment.new(self, *args, &block).call
end
# This class is used for evaluating blocks in a particular context.
# It is not really meant to be used independently; instead it is used
# with Binding#block_exec method.
class BlockEnvironment < BasicObject
def initialize(context, *args, &block)
@context = context
@args = args
@block = block
end
def call
instance_exec(*@args, &@block)
end
def method_missing(name)
eval(name.to_s, @context) rescue super
end
end
end
@@ -0,0 +1,6 @@
require 'cgi'
require 'facets/cgi/marshal'
require 'facets/cgi/escape_html'
@@ -0,0 +1,11 @@
require 'facets/cgi/escape_html'
class CGI
# Instance level method for {CGI::escape_html}.
def esc(string, *modes)
self.class.escape_html(string, *modes)
end
end
@@ -0,0 +1,63 @@
require 'cgi'
class CGI
# Extends `#escape_html` to support escape modes. By default all strings
# are escaped on `&`, `>` and `<`. Add the `:nonstandard` mode to omit
# this conversion.
#
# If no mode is given then the `:default` mode is used.
#
# Available modes include:
# * `:quote` - escapes single and double quotes
# * `:newlines` - escapes newline characters (\r and \n)
# * `:ampersand` - escapes the ampersand sign
# * `:brackets` - escapes less-than and greater-than signs
# * `:default` - escapes double quotes
#
# @example
# escape_html("<tag>") #=> "&lt;tag&gt;"
# escape_html("Example\nString", :newlines) #=> "Example&#13;&#10;String"
# escape_html("\"QUOTE\"", false) #=> "\"QUOTE\""
#
def self.escape_html(string, *modes)
modes << :defualt if modes.empty?
unless modes.include?(:nonstandard)
string = string.gsub(/&/, '&amp;').gsub(/>/, '&gt;').gsub(/</, '&lt;')
end
modes.each do |mode|
string = \
case mode
when :quote, :quotes
string.gsub(%r|"|,'&quot;').gsub(%r|'|,'&#39;')
when :newlines, :newlines
string.gsub(/[\r\n]+/,'&#13;&#10;')
when :ampersand
string.gsub(/&/, '&amp;')
when :bracket, :brackets
string.gsub(/>/, '&gt;').gsub(/</, '&lt;')
when :default, true
string.gsub(/\"/, '&quot;')
when false
else
raise ArgumentError, "unrecognized HTML escape mode -- #{node}"
end
end
end
class << self
# @deprecated
alias :escapeHTML :escape_html
end
if RUBY_VERSION < '1.9'
class << self
alias :unescape_html :unescapeHTML
alias :escape_element :escapeElement
alias :unescape_element :unescapeElement
end
end
end
@@ -0,0 +1,20 @@
require 'cgi'
class CGI
# Create an hidden input field through which an object can can be marshalled.
# This makes it very easy to pass form data betwenn requests.
def marshal_to_cgi(name, iobj)
data = CGI.escape(Marshal.dump(iobj))
return %Q{<input type="hidden" name="__#{name}__" value="#{data}"/>\n}
end
# Create an hidden input field through which an object can can be marshalled.
# This makes it very easy to pass form data between requests.
def marshal_from_cgi(name)
if self.params.has_key?("__#{name}__")
return Marshal.load(CGI.unescape(self["__#{name}__"][0]))
end
end
end
@@ -0,0 +1,54 @@
module Kernel
private
#
# CLI is based on Clap library
# Copyright (c) 2010 Michel Martens
#
def cli(*args)
opts = args.pop
argv = (args.first || ARGV).dup
args = []
# Split option aliases.
opts = opts.inject({}) do |h,(k,v)|
k.to_s.split(/\s+/).each{|o| h[o]=v}; h
end
# Convert single dash flags into multiple flags.
argv = argv.inject([]) do |a, v|
if v[0,1] == '-' && v[1,1] != '-'
a.concat(v[1..-1].chars.map{|c| "-#{c}"})
else
a << v
end
a
end
while argv.any?
item = argv.shift
flag = opts[item]
if flag
# Work around lambda semantics in 1.8.7.
arity = [flag.arity, 0].max
# Raise if there are not enough parameters
# available for the flag.
if argv.size < arity
raise ArgumentError
end
# Call the lambda with N items from argv,
# where N is the lambda's arity.
flag.call(*argv.shift(arity))
else
# Collect the items that don't correspond to
# flags.
args << item
end
end
args
end
end
@@ -0,0 +1,67 @@
# Clonable provides a standard basis for adding deep cloneablity to a class
# via the standard #dup and #clone methods.
#
# Cloneable was originally ported from Jim Weirich's Rake.
# The current version is the work of Ken Bloom.
#
# DEPRECATED: A better approach is to provide a #deep_dup and and a #deep_clone,
# then if a class needs these for #dup and #clone they can just alias them.
#
# CREDIT: Ken Bloom
module Cloneable
def initialize_copy(sibling)
# First duplicate my superclass' state. Note that if it's duplicating
# instance variables, this will be overwritten, but this is important
# because we could be dealing with a C extension with state hidden from
# the Ruby interpreter.
super
# We want to know if we're being dup'ed or clone'd, because we want to
# preserve the state of our internals the same way our state is being
# preserved. (If we can't figure it out, we'll just use #dup.)
operation = (
copy_call = caller.find{|x| x !~ /'initialize_copy'/}
copy_match = copy_call.match(/`(dup|clone)'/)
copy_match ? copy_match[1] : :dup
)
sibling.instance_variables.each do |ivar|
value = sibling.instance_variable_get(ivar)
# Set my instance variable to be a #dup or #clone
# or my sibling, depending on what's happening to me right now.
instance_variable_set(ivar, value.send(operation))
end
end
# TODO: Is there a more robust means of determining if clone or dup is used?
#def clone
# @_copy_operation = :clone
# super
#end
#
#def dup
# @_copy_operation = :dup
# super
#end
end
# OLD VERSION
#module Cloneable
# def clone
# sibling = self.class.new
# instance_variables.each do |ivar|
# value = self.instance_variable_get(ivar)
# sibling.instance_variable_set(ivar, value.dup) #rake_dup)
# end
# sibling
# end
# alias_method :dup, :clone
#end
@@ -0,0 +1,56 @@
if defined?(Continuation)
# = Continuation Extension
#
# Creates a continuation in a way that is easier to use than callcc.
# On the initial call this will return the created Continuation and
# the arguments you gave to Continuation.create in an Array. If you
# then issue .call() on the Continuation execution will jump back to
# the point of time where you initially invoked Continuation.create,
# but this time it will return the Continuation and the arguments
# you supplied in an Array.
#
# You can supply a block instead of default arguments which will
# cause that block to be executed once and its result to be returned
# along side the created Continuation, but this form is confusing
# and does only rarely make sense.
#
# # Count from 0 to 10
# cc, counter = Continuation.create(0)
# counter #~> 0..10
# cc.call(counter + 1) if counter < 10
#
# # Implement something similar to Array#inject using Continuations.
# # For simplicity's sake, this is not fully compatible with the real
# # inject. Make sure that you understand Array#inject before you try
# # to understand this.
# class ::Array
# def cc_inject(value = nil)
# copy = self.clone
# cc, result, item = Continuation.create(value, nil)
# next_item = copy.shift
# if result and item
# # Aggregate the result using the block.
# cc.call(yield(result, item), next_item)
# elsif next_item
# # item not yet set and Array is not empty:
# # This means we did not get a value and thus need to use the
# # first item from the Array before we can start using the
# # block to aggregate the result.
# cc.call(next_item, result)
# end
#
# return result
# end
# end
# [1,2,3,4,5].cc_inject { |acc, n| acc + n } # => 15
#
def Continuation.create(*args, &block)
args = [args] if not args.nil? and not args.is_a? Array # 1.6.8 compatibility
cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
result ||= args
return *[cc, *result]
end
end
@@ -0,0 +1,433 @@
require 'date'
require 'facets/time/stamp'
# = Date
#
# This new version of Date extension has been largely improved by
# porting some of the methods used by ActiveSupport. The old version
# already had much in common with the Active Support library, so it
# was decided to take it a step further in that direction for the
# sake of interoparability.
#
# Hopefully most of these methods will find there way into Ruby's
# own standard library eventually.
#
# The biggest difference with ActiveSupport is the lack of many
# of the "English-esque" methods, and that we use #stamp with
# Date::FORMAT, instead of #to_formmated_s with Date::DATE_FORMATS.
# We do not override the standard #to_s method like ActiveSupport does.
class Date
FORMAT = {
:short => "%e %b",
:long => "%B %e, %Y",
:db => "%Y-%m-%d",
:number => "%Y%m%d",
:rfc822 => "%e %b %Y",
:default => "%Y-%m-%d",
nil => "%Y-%m-%d"
}
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
def self.yesterday
::Date.today.yesterday
end
# Returns a new Date representing the date 1 day after today (i.e. tomorrow's date).
def self.tomorrow
::Date.today.tomorrow
end
# Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today.
def self.current
::Time.zone_default ? ::Time.zone.today : ::Date.today
end
# A method to keep Time, Date and DateTime instances interchangeable
# on conversions. In this case, it simply returns +self+.
def to_date
self
end unless method_defined?(:to_date) # 1.9+ ?
# Converts a Date instance to a DateTime, where the time is set to the beginning of the day
# and UTC offset is set to 0.
#
# date = Date.new(2007, 11, 10) # Sat, 10 Nov 2007
# date.to_datetime # Sat, 10 Nov 2007 00:00:00 0000
#
def to_datetime
::DateTime.civil(year, month, day, 0, 0, 0, 0)
end unless method_defined?(:to_datetime) # 1.9+ ?
# Converts a Date instance to a Time, where the time is set to the beginning of the day.
# The timezone can be either :local or :utc (default :local).
#
# date = Date.new(2007, 11, 10) # Sat, 10 Nov 2007
#
# date.to_time # Sat Nov 10 00:00:00 0800 2007
# date.to_time(:local) # Sat Nov 10 00:00:00 0800 2007
#
# date.to_time(:utc) # Sat Nov 10 00:00:00 UTC 2007
#
def to_time(form=:local)
::Time.send(form, year, month, day)
##::Time.send("#{form}_time", year, month, day)
end
#
def xmlschema
to_time.xmlschema
end
# Returns the number of days in the date's month.
#
# Date.new(2004,2).days_in_month #=> 29
#
# CREDIT: Ken Kunz.
def days_in_month
Date.civil(year, month, -1).day
end
def days_of_month
(1..days_in_month).to_a
end
# Get the month name for this date object
#
# CREDIT: Benjamin Oakes
def month_name
MONTHNAMES[self.month]
end
# Convert to a formatted string. See DATE_FORMATS for predefined formats.
#
# This method is aliased to <tt>to_s</tt>.
#
# date = Date.new(2007, 11, 10) # Sat, 10 Nov 2007
#
# date.stamp(:db) # => "2007-11-10"
# date.stamp(:short) # => "10 Nov"
# date.stamp(:long) # => "November 10, 2007"
# date.stamp(:rfc822) # => "10 Nov 2007"
#
# == Adding your own formats to stamp
# You can add your own formats to the Date::FORMAT hash.
# Use the format name as the hash key and a strftime string
# as the value. Eg.
#
# Date::FORMAT[:month_and_year] = "%B %Y"
#
def stamp(format=:default)
if formatter = FORMAT[format]
strftime(formatter)
else
to_s
end
end
## Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
##def inspect
## strftime("%a, %d %b %Y")
##end
# Provides precise Date calculations for years, months, and days.
# The +options+ parameter takes a hash with any of these keys:
# <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
def advance(options)
d = self
d = d >> options.delete(:years) * 12 if options[:years]
d = d >> options.delete(:months) if options[:months]
d = d + options.delete(:weeks) * 7 if options[:weeks]
d = d + options.delete(:days) if options[:days]
d
end
# Returns a new Date where one or more of the elements have been changed
# according to the +options+ parameter.
#
# Date.new(2007, 5, 12).change(:day=>1) # Date.new(2007, 5, 1)
# Date.new(2007, 5, 12).change(:year=>2005, :month=>1) # Date.new(2005, 1, 12)
#
def change(options)
::Date.new(
options[:year] || self.year,
options[:month] || self.month,
options[:day] || self.day
)
end
# Converts Date to a Time (or DateTime if necessary) with the time portion
# set to the beginning of the day (0:00) and then subtracts the specified
# number of seconds
def ago(seconds)
to_time.since(-seconds)
end
# Converts Date to a Time (or DateTime if necessary) with the time portion
# set to the beginning of the day (0:00) and then adds the specified number
# of seconds.
def since(seconds)
to_time.since(seconds)
end
alias :in :since
# Converts Date to a Time (or DateTime if necessary) with the time portion
# set to the beginning of the day (0:00).
def beginning_of_day
to_time
end
alias :midnight :beginning_of_day
# Convenience method which returns a new Date/DateTime representing the
# time 1 day ago.
def yesterday
self - 1
end
# Convenience method which returns a new Date/DateTime representing
# the time 1 day since the instance time.
def tomorrow
self + 1
end
end
class DateTime
#
def self.local_offset
::Time.local(2007).utc_offset.to_r / 86400
end
def future?
self > ::DateTime.current
end
def past?
self < ::DateTime.current
end
# Converts self to a Ruby Date object; time portion is discarded
def to_date
::Date.new(year, month, day)
end
# Attempts to convert self to a Ruby Time object; returns self if
# out of range of Ruby Time class. If self has an offset other than 0,
# self will just be returned unaltered, since there's no clean way
# to map it to a Time.
def to_time
self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec) : self
end
# To be able to keep Times, Dates and DateTimes interchangeable on conversions
def to_datetime
self
end
# Convert to a formatted string. See Time::FORMAT for predefined formats.
#
# This method is aliased to <tt>to_s</tt>.
#
# datetime = DateTime.civil(2007,12,4,0,0,0,0) # Tue, 04 Dec 2007 00:00:00 +0000
#
# datetime.stamp(:db) # => "2007-12-04 00:00:00"
# datetime.stamp(:db) # => "2007-12-04 00:00:00"
# datetime.stamp(:number) # => "20071204000000"
# datetime.stamp(:short) # => "04 Dec 00:00"
# datetime.stamp(:long) # => "December 04, 2007 00:00"
# datetime.stamp(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
#
# == Adding your own datetime formats to stamp
#
# DateTime formats are shared with Time. You can add your own to the
# Time::FORMAT hash. Use the format name as the hash key and
# a strftime string as the value. Eg.
#
# Time::FORMAT[:month_and_year] = "%B %Y"
#
def stamp(format=:default)
if formatter = ::Time::FORMAT[format]
strftime(formatter)
else
to_s
end
end
# Seconds since midnight: DateTime.now.seconds_since_midnight
def seconds_since_midnight
self.sec + (self.min * 60) + (self.hour * 3600)
end
# Returns a new DateTime where one or more of the elements have been
# changed according to the +options+ parameter. The time options
# (hour, minute, sec) reset cascadingly, so if only the hour is
# passed, then minute and sec is set to 0. If the hour and
# minute is passed, then sec is set to 0.
def change(options)
::DateTime.civil(
options[:year] || self.year,
options[:month] || self.month,
options[:day] || self.day,
options[:hour] || self.hour,
options[:min] || (options[:hour] ? 0 : self.min),
options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec),
options[:offset] || self.offset,
options[:start] || self.start
)
end
# Uses Date to provide precise Time calculations for years, months, and days.
# The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
# <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
# <tt>:minutes</tt>, <tt>:seconds</tt>.
def advance(options)
d = to_date.advance(options)
datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
seconds_to_advance == 0 ? datetime_advanced_by_date : datetime_advanced_by_date.since(seconds_to_advance)
end
# Returns a new DateTime representing the time a number of seconds ago
# Do not use this method in combination with x.months, use months_ago instead!
def ago(seconds)
self.since(-seconds)
end
# Returns a new DateTime representing the time a number of seconds since the instance time
# Do not use this method in combination with x.months, use months_since instead!
def since(seconds)
self + Rational(seconds.round, 86400)
end
alias :in :since
# Returns a new DateTime representing the start of the day (0:00)
def beginning_of_day
change(:hour => 0)
end
alias :midnight :beginning_of_day
# Returns a new DateTime representing the end of the day (23:59:59)
def end_of_day
change(:hour => 23, :min => 59, :sec => 59)
end
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0
#
# Example:
#
# DateTime.civil(2005,2,21,10,11,12,Rational(-6, 24)) # Mon, 21 Feb 2005 10:11:12 -0600
# DateTime.civil(2005,2,21,10,11,12,Rational(-6, 24)).utc # Mon, 21 Feb 2005 16:11:12 +0000
#
def utc
new_offset(0)
end
alias_method :getutc, :utc
# Returns true if offset == 0
def utc?
offset == 0
end
# Returns the offset value in seconds
def utc_offset
(offset * 86400).to_i
end
# Converts datetime to an appropriate format for use in XML
def xmlschema
strftime("%Y-%m-%dT%H:%M:%S%Z")
end unless method_defined?(:xmlschema) # 1.9+ ?
# Converts self to a floating-point number of seconds since the Unix epoch
def to_f
days_since_unix_epoch = self - ::DateTime.civil(1970)
(days_since_unix_epoch * 86_400).to_f
end
end
class Time
#
def self.local_time(*args)
time_with_datetime_fallback(:local, *args)
end
#
def self.utc_time(*args)
time_with_datetime_fallback(:utc, *args)
end
#
def self.time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
rescue
offset = utc_or_local.to_sym == :local ? ::DateTime.local_offset : 0
::DateTime.civil(year, month, day, hour, min, sec, offset)
end
public :to_date
public :to_datetime
# Converts a Time object to a Date, dropping hour, minute, and second precision.
#
# my_time = Time.now # Mon Nov 12 22:59:51 -0500 2007
# my_time.to_date # Mon, 12 Nov 2007
#
# your_time = Time.parse("1/13/2009 1:13:03 P.M.") # Tue Jan 13 13:13:03 -0500 2009
# your_time.to_date # Tue, 13 Jan 2009
#
def to_date
::Date.new(year, month, day)
end
## # Convert a Time to a Date. Time is a superset of Date.
## # It is the year, month and day that are carried over.
##
## def to_date
## require 'date' # just in case
## jd = Date.__send__(:civil_to_jd, year, mon, mday, Date::ITALY)
## Date.new!(Date.__send__(:jd_to_ajd, jd, 0, 0), 0, Date::ITALY)
## end
# Converts a Time instance to a Ruby DateTime instance, preserving UTC offset.
#
# my_time = Time.now # Mon Nov 12 23:04:21 -0500 2007
# my_time.to_datetime # Mon, 12 Nov 2007 23:04:21 -0500
#
# your_time = Time.parse("1/13/2009 1:13:03 P.M.") # Tue Jan 13 13:13:03 -0500 2009
# your_time.to_datetime # Tue, 13 Jan 2009 13:13:03 -0500
#
def to_datetime
::DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400))
end
end
class String
#
def to_time(form = :utc)
::Time.__send__("#{form}_time", *::Date._parse(self, false).values_at(:year, :mon, :mday, :hour, :min, :sec).map{|arg| arg || 0 })
end
# Convert string to DateTime.
def to_datetime
date = ::Date._parse(self, false).values_at(:year, :mon, :mday, :hour, :min, :sec).map { |arg| arg || 0 }
::DateTime.civil(*date)
end
# Parse data from string.
def to_date
#::Date::civil(*ParseDate.parsedate(self)[0..2])
::Date.new(*::Date._parse(self, false).values_at(:year, :mon, :mday))
end
end
@@ -0,0 +1,2 @@
require 'facets/digest/base64digest'
require 'facets/digest/salted_digest'
@@ -0,0 +1,45 @@
require 'digest'
module Digest
module Instance
# For Ruby < 1.9.2
unless instance_methods.include? :base64digest
# From Ruby 1.9.2 source
def base64digest(str = nil)
[str ? digest(str) : digest].pack('m0')
end
end
unless instance_methods.include? :base64digest!
# From Ruby 1.9.2 source
def base64digest!
[digest!].pack('m0')
end
end
end
class Class
# For Ruby < 1.9.2
unless methods.include? :base64digest
# From Ruby 1.9.2 source
def self.base64digest(str, *args)
[self.digest(str, *args)].pack('m0')
end
end
end
end
@@ -0,0 +1,44 @@
require 'digest'
require 'facets/string/random_binary'
module Digest
module Instance
# CREDIT: Guido De Rosa
def salted_digest(str='', salt=:auto)
if salt == :auto
salt = String.random_binary(digest_length)
end
digest(str + salt) + salt
end
# CREDIT: Guido De Rosa
def salted_hexdigest(str, salt)
Digest.hexencode(salted_digest(str, salt))
end
# CREDIT: Guido De Rosa
def salted_base64digest(str, salt)
[salted_digest(str, salt)].pack('m0')
end
end
class Class
# CREDIT: Guido De Rosa
def self.salted_digest(str, salt=:auto, *args)
new(*args).salted_digest(str, salt)
end
# CREDIT: Guido De Rosa
def self.salted_hexdigest(str, salt=:auto, *args)
new(*args).salted_hexdigest(str, salt)
end
# CREDIT: Guido De Rosa
def self.salted_base64digest(str, salt=:auto, *args)
new(*args).salted_base64digest(str, salt)
end
end
end
@@ -0,0 +1,191 @@
module Enumerable
# This is a simple reimplementation of the core Enumerable module
# to allow its methods to take and pass-on arbitrary arguments to the
# underlying #each call. This library uses Enumerator and scans
# Enumerable so it can alwasy stay in sync.
#
# NOTE: Any Enumerable method with a negative arity cannot pass arguments
# due to ambiguity in the argument count. So the methods #inject and #zip
# do NOT work this way, but simply work as they do in Enumerable. However,
# The methods #find and #detect have been made modified to work by removing
# its rarely used optional parameter and providing instead an optional
# keyword parameter (:ifnone => ...). Please keep these difference in mind.
#
# Example
# require 'enumargs'
#
# class T
# include Enumerable::Argumentable
# def initialize(arr)
# @arr = arr
# end
# def each(n)
# arr.each{ |e| yield(e+n) }
# end
# end
#
# t = T.new([1,2,3])
# t.collect(4)
# #=> [5,6,7]
#
module Argumentable
# Helper method to wrap Enumerable methods.
def self.wrap_enumerable_method( methodname )
m = methodname
meth = Enumerable.instance_method(m)
arity = meth.arity
case arity <=> 0
when 0
class_eval %{
def #{m}( *args, &yld )
enum_for(:each, *args).#{m}( &yld )
end
}
when 1
class_eval %{
def #{m}( *args, &yld )
args, each_args = args[0...#{arity}], args[#{arity}..-1]
enum_for(:each, *each_args).#{m}( *args, &yld )
end
}
else
# this branch is used when the method has a variable number of arguments
# resulting in an arity of -1. Right now this is bugged as it does
# not pass the argument to the each, and always passes the argument
# to the method. This makes methods like .min amdn .max to act
# in an unexpected manner.
class_eval %{
def #{m}( *args, &yld )
enum_for(:each).#{m}( *args, &yld )
end
}
end
end
# Wrap all Enumerable's public instance methods
Enumerable.instance_methods(false).each do |m|
wrap_enumerable_method( m )
end
# Support for #to_a.
#
def to_a(*args)
#map(*args){ |x| x }
enum_for(:each, *args).to_a
end
# Make exception for #find (a negative arity method) to accept
# keyword argument.
#
# ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... }
# ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... }
#
def find(*args, &yld) # future use **keys ?
if Hash === args.last and args.last.key?(:ifnone)
ifnone = args.last.delete(:ifnone)
args.pop if args.last.empty?
enum_for(:each, *args).find( ifnone, &yld )
else
enum_for(:each, *args).find( &yld )
end
end
alias_method :detect, :find
end
# DEPRECATED: Module alias for old name.
Arguments = Argumentable
end
=begin OLD CODE
module EnumerableArgs
def collect(*args) # :yield:
a = []
each(*args){ |n| a << yield(n) }
a
end
alias_method( :map, :collect )
def detect(*args) # :yield:
each(*args){ |n| return n if yield(n) }
nil
end
alias_method( :find, :detect )
def each_with_index(*args)
i=0
each(*args){ |*n| n << i; yield(*n); i+=1 }
self
end
def to_a(*args)
a = []
each(*args){ |n| a << n }
a
end
alias_method( :entries, :to_a )
# An additional method not part of standard Enumerable.
# The regular version of this method can be found in Facets,
# but it is a bit more advanced then this one.
# At some point they need to be put into sync.
def each_slice(*args, &yld)
a = []; s = []
ar = yld.arity.abs
each(*args){ |n|
s << n
if s.length >= ar
yld.call(*s)
s = []
end
}
a
end
alias_method( :each_by, :each_slice )
def select(*args) # :yield:
a = []
each(*args){ |n| a << n if yield(n) }
a
end
alias_method( :find_all, :select )
def grep(pattern, *args)
a = []
each(*args){ |n| a << (block_given? ? yield(n) : n) if pattern === n }
a
end
def include?(anObj, *args)
each(*args){ |n| return true if anObj == n }
false
end
alias_method( :member?, :include? )
def max(*args)
to_a(*args).max
end
def min(*args)
to_a(*args).min
end
def reject(*args)
a = []
each(*args){ |n| a << n if ! yield(n) }
a
end
def sort(*args)
# TODO
end
end
=end
# Copyright (c) 2004 Rubyworks (BSD-2-Clause)
@@ -0,0 +1,76 @@
# = Equitable
#
# This mixin provides methods of equality based
# on a single #identity method which must return
# a list of accessors used as the identity keys.
#
# It also provides a "shortcut" for creating the
# #identity method based on given accessors and returns
# the Equitable module for inclusion.
#
# include Equitable(:a, :b)
#
# is equivalent to including a module containing:
#
# def ==(other)
# self.a == other.a && self.b == other.b
# end
#
# def eql?(other)
# self.a.eql?(other.a) && self.b.eql?(other.b)
# end
#
# def hash()
# self.a.hash ^ self.b.hash
# end
#
module Equitable
def self.identify(base, *accessors)
base.send(:define_method, :identity){ accessors }
self
end
def ==(o)
identity.all?{ |a| send(a) == o.send(a) }
end
def eql?(o)
identity.all?{ |a| send(a).eql?(o.send(a)) }
end
def hash
identity.inject(0){ |memo, a| memo ^ send(a).hash }
end
end
class Module
# This function provided a "shortcut" for creating the
# #identity method based on given accessors and returns
# the Equitable module for inclusion.
#
# include Equitable(:a, :b)
#
# is equivalent to including a module containing:
#
# def ==(other)
# self.a == other.a && self.b == other.b
# end
#
# def eql?(other)
# self.a.eql?(other.a) && self.b.eql?(other.b)
# end
#
# def hash()
# self.a.hash ^ self.b.hash
# end
#
def Equitable(*accessors)
Equitable.identify(self, *accessors)
end
end
@@ -0,0 +1,66 @@
require 'erb'
# = OpenTemplate
#
# The Erb OpenTemplate provides a quick and convenient way to
# create a clean rendering space with the desired responses.
#
# Ruby 1.8.6 or less can't handle object scope methods with blocks.
#
# TODO: This might make a good addon library. Just add
# require 'erb' to the erb_result method? Call it OpenResponse?
#
class ERB::OpenTemplate
# TODO: Should we do this? Perhaps offer it as an option?
instance_methods.each do |m|
undef_method(m) unless /^(__|instance_|inspect$|extend$|object_id$)/ =~ m.to_s
end
#
def initialize(*objs_ioc)
ioc = Hash===objs_ioc.last ? objs_ioc.pop : {}
objs = objs_ioc
mods = []
objs.each do |obj|
mod = Module.new
obj.public_methods.each do |m|
mod.module_eval do
#define_method(m){ |*a,&b| obj.__send__(m,*a,&b) }
define_method(m, &obj.method(m).to_proc)
end
end
mods << mod
end
mod = Module.new
ioc.each do |k,v|
mod.module_eval do
define_method(k){ v }
end
end
mods << mod
extend *mods.reverse
end
#
def erb_result(str)
ERB.new(str).result(binding)
end
##
##def method_missing(sym, *args, &block)
## #if @ioc.key?(sym)
## # @ioc[sym]
## if obj = @objs.find{ |o| o.respond_to?(sym) }
## obj.__send__(sym, *args, &block)
## else
## super
## end
##end
end
@@ -0,0 +1,13 @@
# TODO: Deprecate #safe_ln, if #ln has been fixed to do this.
require 'fileutils'
require 'facets/fileutils/amass'
require 'facets/fileutils/cp_rx'
require 'facets/fileutils/ln_r'
require 'facets/fileutils/outofdate'
require 'facets/fileutils/safe_ln'
require 'facets/fileutils/slice' # includes head and tail
require 'facets/fileutils/stage'
require 'facets/fileutils/wc'
require 'facets/fileutils/whereis'
require 'facets/fileutils/which'
@@ -0,0 +1,34 @@
module FileUtils
module_function
# An intergrated glob like method that takes a set of include globs,
# exclude globs and ignore globs to produce a collection of paths.
#
# The ignore_globs differ from exclude_globs in that they match by
# the basename of the path rather than the whole pathname.
#
# TODO: Should ignore be based on any portion of the path, not just the basename?
#
def amass(include_globs, exclude_globs=[], ignore=[])
include_files = [include_globs].flatten.map{ |g| Dir.glob(g) }.flatten.uniq
exclude_files = [exclude_globs].flatten.map{ |g| Dir.glob(g) }.flatten.uniq
include_files = include_files.map{ |f| File.directory?(f) ? File.join(f, '**/*') : f } # Recursive!
exclude_files = exclude_files.map{ |f| File.directory?(f) ? File.join(f, '**/*') : f } # Recursive!
include_files = include_files.flatten.map{ |g| Dir.glob(g) }.flatten.uniq
exclude_files = exclude_files.flatten.map{ |g| Dir.glob(g) }.flatten.uniq
files = include_files - exclude_files
files = files.reject{ |f| [ignore].flatten.any?{ |x| File.fnmatch?(x, File.basename(f)) } }
files
end
# Make public (for all submodules too).
public :amass
end
@@ -0,0 +1,44 @@
module FileUtils
module_function
# Both of these are modified from the implementations in fileutils.rb from Ruby 1.9.1p378.
# Like FileUtils.cp_r, but takes a filter proc that can return false to skip a file:
#
# cp_rx "bigDirectoryTree", "dest", {:noop => true} do |name|
# /dontCopyThis$/.match(name)
# end
#
# Note that if the filter rejects a subdirectory then everything within that
# subdirectory is automatically skipped as well.
def cp_rx(src, dest, options = {}, &filter)
fu_check_options(options, OPT_TABLE['cp_r'])
if options[:verbose]
fu_output_message("cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}")
end
return if options[:noop]
fu_each_src_dest(src, dest) do |s, d|
copy_entryx(s, d, filter, options[:preserve], options[:dereference_root], options[:remove_destination])
end
end
# Like FileUtils.copy_entry, but takes a filter proc that can return false to skip a file.
#
# Note that if the filter rejects a subdirectory then everything within that
# subdirectory is automatically skipped as well.
def copy_entryx(src, dest, filter, preserve = false, dereference_root = false, remove_destination = false)
Entry_.new(src, nil, dereference_root).traverse do |ent|
if filter.call(ent.path) then
destent = Entry_.new(dest, ent.rel, false)
File.unlink destent.path if remove_destination && File.file?(destent.path)
ent.copy destent.path
ent.copy_metadata(destent.path) if preserve
end
end
end
end
@@ -0,0 +1 @@
require 'facets/fileutils/slice'
@@ -0,0 +1,99 @@
module FileUtils
unless method_defined?(:ln_r)
#
# Options: noop verbose dereference_root remove_destination
#
# Hard link +src+ to +dest+. If +src+ is a directory, this method links
# all its contents recursively. If +dest+ is a directory, links
# +src+ to +dest/src+.
#
# +src+ can be a list of files.
#
# # Installing ruby library "mylib" under the site_ruby
# FileUtils.rm_r site_ruby + '/mylib', :force
# FileUtils.ln_r 'lib/', site_ruby + '/mylib'
#
# # Examples of copying several files to target directory.
# FileUtils.ln_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
# FileUtils.ln_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true
#
# # If you want to copy all contents of a directory instead of the
# # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
# # use following code.
# FileUtils.ln_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest,
# # but this doesn't.
#
# TODO: Why --remove-destination and not just --force?
def ln_r(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_r']
fu_output_message "ln -r#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
options = options.dup
options[:dereference_root] = true unless options.key?(:dereference_root)
fu_each_src_dest(src, dest) do |s, d|
link_entry s, d, options[:dereference_root], options[:remove_destination]
end
end
module_function :ln_r
OPT_TABLE = {} unless const_defined?(:OPT_TABLE)
OPT_TABLE['ln_r'] = [:noop, :verbose, :dereference_root, :remove_destination]
#
# Hard links a file system entry +src+ to +dest+.
# If +src+ is a directory, this method links its contents recursively.
#
# Both of +src+ and +dest+ must be a path name.
# +src+ must exist, +dest+ must not exist.
#
# If +dereference_root+ is true, this method dereference tree root.
#
# If +remove_destination+ is true, this method removes each destination file before copy.
#
def link_entry(src, dest, dereference_root = false, remove_destination = false)
Entry_.new(src, nil, dereference_root).traverse do |ent|
destent = Entry_.new(dest, ent.rel, false)
File.unlink destent.path if remove_destination && File.file?(destent.path)
ent.link destent.path
end
end
module_function :link_entry
class Entry_ #:nodoc:
def link(dest)
case
when directory?
if !File.exist?(dest) and descendant_diretory?(dest, path)
raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest]
end
begin
Dir.mkdir dest
rescue
raise unless File.directory?(dest)
end
else file?
File.link path(), dest
end
end
unless const_defined?(:DIRECTORY_TERM)
if File::ALT_SEPARATOR
DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)".freeze
else
DIRECTORY_TERM = "(?=/|\\z)".freeze
end
SYSCASE = File::FNM_SYSCASE.nonzero? ? "-i" : ""
end
unless method_defined?(:descendant_diretory?)
def descendant_diretory?(descendant, ascendant)
/\A(?#{SYSCASE}:#{Regexp.quote(ascendant)})#{DIRECTORY_TERM}/ =~ File.dirname(descendant)
end
end
end
end
end
@@ -0,0 +1,38 @@
require 'fileutils'
module FileUtils
module_function
# The opposite of #uptodate?
def outofdate?(path, *sources)
#return true unless File.exist?(path)
! uptodate?(path, sources.flatten)
end
# Alias for #outofdate?
alias_method :out_of_date?, :outofdate?
# Alias for #uptodate?
alias_method :up_to_date?, :uptodate?
# # TODO: Does a path need updating, based on given +sources+?
# # This compares mtimes of give paths. Returns false
# # if the path needs to be updated.
# #
# # DEPRECATE: Is this in any way better than `! uptodate?` ?
# def out_of_date?(path, *sources)
# return true unless File.exist?(path)
#
# sources = sources.collect{ |source| Dir.glob(source) }.flatten
# mtimes = sources.collect{ |file| File.mtime(file) }
#
# return true if mtimes.empty? # TODO: This the way to go here?
#
# File.mtime(path) < mtimes.max
# end
# Make public (for all submodules too).
public :outofdate?
public :out_of_date?
public :up_to_date?
end
@@ -0,0 +1,27 @@
require 'fileutils'
module FileUtils
module_function
LINKING_SUPPORTED = [true]
# Attempt to do a normal file link, but fall back
# to a copy if the link fails.
#
# CREDIT: Jim Weirich
def safe_ln(*args)
unless LINKING_SUPPORTED[0]
cp(*args)
else
begin
ln(*args)
rescue Errno::EOPNOTSUPP
LINKING_SUPPORTED[0] = false
cp(*args)
end
end
end
end
@@ -0,0 +1,55 @@
require 'fileutils'
module FileUtils
module_function
# In block form, yields lines +from+-+to+. In non-block form, returns
# an array of lines +from+-+to+:
#
# # Returns lines 8-12 of 'myfile'
# FileUtils.body("myfile",8,12)
#
# CREDIT Shashank Date, via Daniel Berger.
def slice(filename,from,to) #:yield:
IO.readlines(filename)[from-1..to-1]
end
# In block form, yields the first number of +lines+ of file +filename+.
# In non-block form, it returns an array of the first number of +lines+:
#
# # Returns first 10 lines of 'myfile'
# FileUtils.head("myfile", 10)
#
def head(filename,lines) #:yield:
a = []
IO.foreach(filename){|line|
break if lines <= 0
lines -= 1
if block_given?
yield line
else
a << line
end
}
return a.empty? ? nil : a
end
# In block form, yields the last number of +lines+ of file +filename+.
# In non-block form, it returns the lines as an array.
#
# Note that this method slurps the entire file, so I don't recommend it
# for very large files. If you want an advanced form of +tail+, I
# suggest using file-tail, by Florian Frank (available on the RAA):
#
# # Returns last 3 lines of 'myfile'
# FileUtils.tail("myfile",3)
#
# And no tail -f.
def tail(filename,lines) #:yield
IO.readlines(filename).reverse[0..lines-1].reverse
end
end
@@ -0,0 +1,66 @@
require 'fileutils'
module FileUtils
module_function
# Stage by hard linking included files to a stage directory.
#
# stage_directory - Where to stage the files
# source_directory - Where to find files to stage
# files - Files to link in stage relative to source
#
# TODO: Rename to #link_stage or something less likely to name clash?
# TODO: Add options for :verbose, :noop and :dryrun ?
#
def stage(stage_directory, source_directory, files, options={})
return stage_directory if options[:noop] || options[:dryrun]
stage_directory, source_directory = stage_directory.to_s, source_directory.to_s
## ensure existance of staging area
rm_r(stage_directory) if File.directory?(stage_directory)
mkdir_p(stage_directory)
## link files into staging area
files.each do |f|
src = File.join(source_directory, f)
file = File.join(stage_directory, f)
if File.directory?(src)
mkdir_p(file) unless File.exist?(file)
else
fdir = File.dirname(file)
mkdir_p(fdir) unless File.exist?(fdir)
unless File.exist?(file) and File.mtime(file) >= File.mtime(src)
ln(src, file) #safe_ln ?
end
end
end
return stage_directory
end
# Make public (for all submodules too).
public :stage
module NoWrite
module_function
def stage(stage_directory, files, options={})
options[:noop] = true
FileUtils.stage(stage_directory, files, options={})
end
end
module Verbose
module_function
def stage(stage_directory, files, options={})
options[:verbose] = true
FileUtils.stage(stage_directory, files, options={})
end
end
module DryRun
module_function
def stage(stage_directory, files, options={})
options[:dryrun] = true
FileUtils.stage(stage_directory, files, options={})
end
end
end
@@ -0,0 +1 @@
require 'facets/fileutils/slice'
@@ -0,0 +1,63 @@
require 'fileutils'
module FileUtils
module_function
# With no arguments, returns a four element array consisting of the number
# of bytes, characters, words and lines in _filename_, respectively.
#
# Valid options are +bytes+, +characters+ (or just 'chars'),
# +words+ and +lines+:
#
# # Return the number of words in 'myfile'
# FileUtils.wc("myfile",'words')
#
# CREDIT: Daniel J. Berger
def wc(filename,option='all')
option.downcase!
valid = %w/all bytes characters chars lines words/
unless valid.include?(option)
raise "Invalid option: '#{option}'"
end
n = 0
if option == 'lines'
IO.foreach(filename){ n += 1 }
return n
elsif option == 'bytes'
File.open(filename){ |f|
f.each_byte{ n += 1 }
}
return n
elsif option == 'characters' || option == 'chars'
File.open(filename){ |f|
while f.getc
n += 1
end
}
return n
elsif option == 'words'
IO.foreach(filename){ |line|
n += line.split.length
}
return n
else
bytes,chars,lines,words = 0,0,0,0
IO.foreach(filename){ |line|
lines += 1
words += line.split.length
chars += line.split('').length
}
File.open(filename){ |f|
while f.getc
bytes += 1
end
}
return [bytes,chars,words,lines]
end
end
end
@@ -0,0 +1,66 @@
require 'fileutils'
module FileUtils
if const_defined?(:Win32Exts)
Win32Exts.concat %w{.exe .com .bat .cmd}
Win32Exts.uniq!
else
Win32Exts = %w{.exe .com .bat .cmd}
end
module_function
# In block form, yields each ((*program*)) within ((*path*)). In non-block
# form, returns an array of each ((*program*)) within ((*path*)). Returns
# (({nil})) if not found.
#
# On the MS Windows platform, it looks for executables ending with .exe,
# .bat and .com, which you may optionally include in the program name:
#
# FileUtils.whereis("ruby") #=> ['/usr/local/bin/ruby','/opt/bin/ruby']
#
# CREDIT: Daniel J. Berger
def whereis(prog, path=ENV['PATH']) #:yield:
dirs = []
path.split(File::PATH_SEPARATOR).each{|dir|
# Windows checks against specific extensions
if File::ALT_SEPARATOR
if prog.include?('.')
f = File.join(dir,prog)
if File.executable?(f) && !File.directory?(f)
if block_given?
yield f.gsub(/\//,'\\')
else
dirs << f.gsub(/\//,'\\')
end
end
else
Win32Exts.find_all{|ext|
f = File.join(dir,prog+ext)
if File.executable?(f) && !File.directory?(f)
if block_given?
yield f.gsub(/\//,'\\')
else
dirs << f.gsub(/\//,'\\')
end
end
}
end
else
f = File.join(dir,prog)
# Avoid /usr/lib/ruby, for example
if File.executable?(f) && !File.directory?(f)
if block_given?
yield f
else
dirs << f
end
end
end
}
dirs.empty? ? nil : dirs
end
end
@@ -0,0 +1,60 @@
require 'fileutils'
module FileUtils
if const_defined?(:Win32Exts)
Win32Exts.concat %w{.exe .com .bat .cmd}
Win32Exts.uniq!
else
Win32Exts = %w{.exe .com .bat .cmd}
end
module_function
# Looks for the first occurrence of _program_ within _path_.
#
# On the MS Windows platform, it looks for executables ending with .exe,
# .bat and .com, which you may optionally include in the program name.
# Returns <tt>nil</tt> if not found.
#
# CREDIT: Daniel J. Berger, Michael Granger
#
#--
# The which() method was adopted from Daniel J. Berger, via PTools
# which in in turn was adopted fromt the FileWhich code posted by
# Michael Granger on http://www.rubygarden.org.
#++
def which(prog, path=ENV['PATH'])
path.split(File::PATH_SEPARATOR).each {|dir|
# Windows checks against specific extensions
if File::ALT_SEPARATOR
ext = Win32Exts.find{|ext|
if prog.include?('.') # Assume extension already included
f = File.join(dir,prog)
else
f = File.join(dir,prog+ext)
end
File.executable?(f) && !File.directory?(f)
}
if ext
# Use backslashes, not forward slashes
if prog.include?('.') # Assume extension already included
f = File.join( dir, prog ).gsub(/\//,'\\')
else
f = File.join( dir, prog + ext ).gsub(/\//,'\\')
end
return f
end
else
f = File.join(dir,prog)
# Avoid /usr/lib/ruby, for example
if File.executable?(f) && !File.directory?(f)
return File::join( dir, prog )
end
end
}
nil
end
end
@@ -0,0 +1,2 @@
require 'facets/find/select'
@@ -0,0 +1,16 @@
require 'facets/enumerator'
module Find
# Identical to find except select returns the matching files as an array.
# (find returns nil, which is not very useful if you actually wanted an array.)
# Calls the associated block with the name of every file and directory listed
# as arguments, then recursively on their subdirectories, and so on.
# Return a true (non-false) value from the block for every path that
# you want to be returned in the resulting array. You can still use Find.prune.
#
# CREDIT: Tyler Rick
def self.select(*paths, &block)
Enumerator.new(self, :find, *paths).select{|value| yield value}
end
end
@@ -0,0 +1,18 @@
require 'facets/gem/specification/current_specs'
module Gem
# Search RubyGems for matching paths in current gem versions.
def self.search(match, options={})
matches = []
Gem::Specification.current_specs.each do |spec|
glob = File.join(spec.lib_dirs_glob, match)
list = Dir[glob] #.map{ |f| f.untaint }
list = list.map{ |d| d.chomp('/') }
matches.concat(list)
end
matches
end
end
@@ -0,0 +1,21 @@
module Gem
class Specification
# Return a list of active specs or latest version of spec if not active.
def self.current_specs
named = Hash.new{|h,k| h[k] = [] }
each{ |spec| named[spec.name] << spec }
list = []
named.each do |name, vers|
if spec = vers.find{ |s| s.activated? }
list << spec
else
spec = vers.max{ |a,b| a.version <=> b.version }
list << spec
end
end
return list
end
end
end
@@ -0,0 +1,21 @@
module Gem
class Specification
# Return full path of requireable file given relative path.
def find_requireable_file(file)
root = full_gem_path
require_paths.each do |lib|
base = File.join(root, lib, file)
Gem.suffixes.each do |suf|
path = "#{base}#{suf}"
return path if File.file? path
end
end
return nil
end
end
end
@@ -0,0 +1,59 @@
require 'getoptlong'
# = GetoptLong
#
# Ruby's standard GetoptLong class with an added DSL.
#
# opts = GetoptLong.new do
# reqs '--expect', '-x'
# flag '--help', '-h'
# end
#
# See GetoptLong::DSL for details.
class GetoptLong
alias :init :initialize
#
def initialize(*arguments, &block)
if block_given?
raise ArgumentError unless arguments.empty?
arguments = DSL.new(&block).arguments
end
init(*arguments)
end
# DSL-mode parser.
class DSL
attr :arguments
def initialize(&block)
@arguments = []
instance_eval(&block)
end
#
def flag(*opts)
@arguments << (opts << GetoptLong::NO_ARGUMENT)
end
#
def required(*opts)
@arguments << (opts << GetoptLong::REQUIRED_ARGUMENT)
end
#
alias :reqs :required
#
def optional(*opts)
@arguments << (opts << GetoptLong::OPTIONAL_ARGUMENT)
end
#
alias :opts :optional
end
end
@@ -0,0 +1,46 @@
# HashBuilder takes a procedure and builds a Hash out of it.
#
# The procedure must conform to a set of rules to be useful in this respect.
# They must either take an argument and use that argument to set values, or
# if no argument is taken then `#instance_eval` is used to evaluate the
# procedure such that each method represents a key.
#
class HashBuilder < BasicObject
#
def initialize(hash={}, &block)
@hash = hash
case block.arity
when 0
instance_eval(&block)
else
block.call(self)
end
end
#
def to_h
@hash
end
#
def method_missing(s, *a, &b)
m = s.to_s
if a.empty? && !b
@hash[m.to_sym]
else
if b
@hash[m.chomp('=').to_sym] = HashBuilder.new(&b).to_h
else
if a.size > 1
@hash[m.chomp('=').to_sym] = a
else
@hash[m.chomp('=').to_sym] = a.first
end
end
end
end
end
@@ -0,0 +1,25 @@
# = Instantiable
#
# Initialize modules, almost as if they were classes.
#
# Alows a module to be used much like a class, by defining
# a #new method that creates a class on demand.
#
module Instantiable
def self.append_features(mod)
mod.extend self
end
# Never use a class again! ;)
def new(*args,&blk)
mod = self
@instantiable_class ||= Class.new{include mod}
@instantiable_class.new(*args,&blk)
end
end
@@ -0,0 +1,277 @@
require 'facets/multiton'
require 'facets/enumargs'
#require 'facets/infinity'
# TODO: Tie in Infinity with Interval.
# While Ruby support the Range class out of the box, is does not quite
# fullfil the role od a real Interval class. For instance, it does
# not support excluding the front sentinel. This is because Range also
# tries to do triple duty as a simple sequence and as a simple tuple-pair,
# thus limiting its potential as an Interval. The Interval class remedies
# the situation by commiting to interval behavior, and then extends the class'
# capabilites beyond that of the standard Range in ways that naturally
# fall out of that.
#
# Range depends on two methods: #succ and #<=>. If numeric ranges were the
# only concern, those could just as well be #+ and #<=>, but esoteric forms
# make that unfeasible --the obvious example being a String range. But a
# proper Interval class requires mathematical continuation, thus the Interval
# depends on #+ and #<=>, as well as #- as the inverse of #+.
#
# i = Interval.new(1,5)
# i.to_a #=> [1,2,3,4,5]
#
# i = Interval[0,5]
# i..step(2).to_a #=> [0,2,4]
#
# i = Interval[1,5]
# i.step(-1).to_a #=> [5,4,3,2,1]
#
# i = Interval[1,3]
# i.step(1,2).to_a #=> [1.0,1.5,2.0,2.5,3.0]
#
class Interval
include Multiton
include Enumerable::Arguments
#
def self.[]( *args )
self.new( *args )
end
#
def initialize(first, last, exclude_first=false, exclude_last=false )
raise ArgumentError, "bad value for interval" if first.class != last.class
@first = first
@last = last
@exclude_first = exclude_first
@exclude_last = exclude_last
@direction = (@last <=> @first)
end
# Returns a two element array of first and last sentinels.
#
# (0..10).sentinels #=> [0,10]
#
def sentinels
return [@first, @last]
end
# Returns the first or last sentinal of the interval.
def first ; @first ; end
def last ; @last ; end
#
def exclude_first? ; @exclude_first ; end
def exclude_last? ; @exclude_last ; end
# (IMHO) these should be deprectated
alias_method( :begin, :first )
alias_method( :end, :last )
alias_method( :exclude_begin?, :exclude_first? )
alias_method( :exclude_end?, :exclude_last? )
# Returns +true+ if the start and end sentinels are equal and the interval is closed; otherwise +false+.
def degenerate? ; @direction == 0 and ! (@exclusive_first or @exclusive_last) ; end
# Returns +true+ if the start and end sentinels are equal and the interval is open; otherwise +false+.
def null? ; @direction == 0 and @exclusive_first and @exclusive_last ; end
# Returns the direction of the interval indicated by +1, 0 or -1.
#
# (1..5).direction #=> 1
# (5..1).direction #=> -1
# (1..1).direction #=> 0
#
def direction ; @direction ; end
# Returns a new interval inclusive of of both sentinels.
def closed; Interval.new(@first, @last, true, true) ; end
# Returns a new interval exclusive of both sentinels.
def opened; Interval.new(@first, @last, true, true) ; end
# Returns a new interval with either the first or the last sentinel exclusive.
# If the parameter is false, the deafult, then the first sentinel is excluded;
# if the parameter is true, the last sentinel is excluded.
def half_closed(e=false)
e ? Interval.new(@first, @last, true, false) : Interval.new(@first, @last, false, true)
end
# Returns a new interval with one of the two sentinels opened or closed
def first_closed ; Interval.new(@first, @last, false, true) ; end
def last_closed ; Interval.new(@first, @last, true, false) ; end
def first_opened ; Interval.new(@first, @last, true, false) ; end
def last_opened ; Interval.new(@first, @last, false, true) ; end
# Unary shorthands. These return a new interval exclusive of first,
# last or both sentinels, repectively.
def +@ ; Interval.new(first, last, true, false) ; end
def -@ ; Interval.new(first, last, false, true) ; end
def ~@ ; Interval.new(first, last, true, true) ; end
# Returns a new interval with the sentinels reversed.
#
# (0..10).reversed #=> 10..0
#
def reversed
Interval.new(@last, @first, true, true)
end
# Returns the length of the interval as the difference between
# the first and last elements. Returns +nil+ if the sentinal objects
# do not support distance comparison (#distance).
#
# TODO: Add +n+ parameter to count segmentations like those produced by #each.
def distance
@last - @first
#if @last.respond_to?( :distance )
# @last.distance( @first )
#else
# #self.to_a.length
#end
end
alias_method( :length, :distance )
alias_method( :size, :distance )
# Returns the lesser of the first and last sentinals.
def min
((@first <=> @last) == -1) ? @first : @last
end
# Returns the greater of the first and last sentinals.
def max
((@first <=> @last) == 1) ? @first : @last
end
# Returns true or false if the element is part of the interval.
def include?(x)
# todo: infinity?
tf = exclude_first? ? 1 : 0
tl = exclude_last? ? -1 : 0
(x <=> first) >= tf and (x <=> last) <= tl
end
alias_method( :===, :include? )
alias_method( :member?, :include? )
=begin
# def include?(x)
# tf = exclude_first? ? 1 : 0
# tl = exclude_last? ? -1 : 0
# # if other classes handled Infinity in their <=> method
# # (which probably they should) this clause would not be required
# if first.kind_of?(InfinityClass)
# ft = ((first <=> x) <= tf)
# else
# ft = (x <=> first) >= tf
# end
# if last.kind_of?(InfinityClass)
# fl = ((last <=> x) >= tl)
# else
# fl = (x <=> last) <= tl
# end
# ft && fl
# end
=end
# Iterates over the interval, passing each _n_th element to the block.
# If n is not given then n defaults to 1. Each _n_th step is determined
# by invoking +\++ or +\-+ n, depending on the direction of the interval.
# If n is negative the iteration is preformed in reverse form end sentinal
# to front sentinal. A second parameter, d, can be given in which case
# the applied step is calculated as a fraction of the interval's length
# times n / d. This allows iteration over the whole interval in equal sized
# segments.
#
# 1..5.each { |e| ... } #=> 1 2 3 4 5
# 1..5.each(2) { |e| ... } #=> 1 3 5
# 1..5.each(1,2) { |e| ... } #=> 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
#
# @todo Deprecate arguments and simplify each definition accordingly.
def each(n=nil, d=nil) # :yield:
if n
warn "FACETS: `interval.each(n,d){...}` will be deprecated.\n" +
"Use `interval.step(n,d).each{...}` instead."
else
n = 1
end
return (n < 0 ? @last : @first) if degenerate? # is this right for all values of n ?
s = d ? self.length.to_f * (n.to_f / d.to_f) : n.abs
raise "Cannot iterate over zero length steps." if s == 0
s = s * @direction
if n < 0
e = @exclude_last ? @last - s : @last
#e = @exclude_last ? @last.pred(s) : @last
t = @exclude_last ? 1 : 0
#while e.cmp(@first) >= t
while (e <=> @first) >= t
yield(e)
e -= s
#e = e.pred(s)
end
else
e = @exclude_first ? @first + s : @first
#e = @exclude_first ? @first.succ(s) : @first
t = @exclude_last ? -1 : 0
#while e.cmp(@last) <= t
while (e <=> @last) <= t
yield(e)
e += s
#e = e.succ(s)
end
end
end
#
def step(n=1, d=nil) # :yield:
return (n < 0 ? @last : @first) if degenerate? # is this right for all values of n ?
if block_given?
s = d ? self.length.to_f * (n.to_f / d.to_f) : n.abs
raise "Cannot iterate over zero length steps." if s == 0
s = s * @direction
if n < 0
e = @exclude_last ? @last - s : @last
#e = @exclude_last ? @last.pred(s) : @last
t = @exclude_last ? 1 : 0
#while e.cmp(@first) >= t
while (e <=> @first) >= t
yield(e)
e -= s
#e = e.pred(s)
end
else
e = @exclude_first ? @first + s : @first
#e = @exclude_first ? @first.succ(s) : @first
t = @exclude_last ? -1 : 0
#while e.cmp(@last) <= t
while (e <=> @last) <= t
yield(e)
e += s
#e = e.succ(s)
end
end
else
Enumerator.new(self, :step, n, d)
end
end
# Should there be a #reverse_each ?
# Since #each can now take a negative argument, this isn't really needed.
# Should it exist anyway and routed to #each?
# Also, alias_method( :reverse_step, :reverse_each )
# Compares two intervals to see if they are equal
def eql?(other)
return false unless @first == other.first
return false unless @last == other.last
return false unless @exclude_first == other.exclude_first?
return false unless @exclude_last == other.exclude_last?
true
end
end
@@ -0,0 +1,26 @@
module ::Kernel
class << self
alias_method :require_without_monitor, :require
alias_method :load_without_monitor, :load
end
alias_method :require_without_monitor, :require
alias_method :load_without_monitor, :load
# Require script and print what is being require.
def require(file)
$stderr.puts "monitor require: #{file}\n#{caller.inspect}\n\n"
require_without_monitor(file)
end
module_function :require
# Load script and print what is being loaded.
def load(file, wrap=false)
$stderr.puts "monitor load: #{file}\n#{caller.inspect}\n\n"
load_without_monitor(file, wrap)
end
module_function :load
end
@@ -0,0 +1,58 @@
require_relative 'math/abs.rb'
require_relative 'math/acot.rb'
require_relative 'math/acoth.rb'
require_relative 'math/acsc.rb'
require_relative 'math/acsch.rb'
require_relative 'math/amd.rb'
require_relative 'math/approx_equal.rb'
require_relative 'math/asec.rb'
require_relative 'math/asech.rb'
require_relative 'math/atkinson_index.rb'
require_relative 'math/beta.rb'
require_relative 'math/cdf.rb'
require_relative 'math/ceil.rb'
require_relative 'math/cot.rb'
require_relative 'math/coth.rb'
require_relative 'math/csc.rb'
require_relative 'math/csch.rb'
require_relative 'math/delta.rb'
require_relative 'math/ec.rb'
require_relative 'math/epsilon.rb'
require_relative 'math/exp2.rb'
require_relative 'math/exp10.rb'
require_relative 'math/factorial.rb'
require_relative 'math/floor.rb'
require_relative 'math/gcd.rb'
require_relative 'math/gini_coefficient.rb'
require_relative 'math/kldivergence.rb'
require_relative 'math/lcm.rb'
require_relative 'math/lgamma.rb'
require_relative 'math/lngamma.rb'
require_relative 'math/linsolve.rb'
require_relative 'math/log2.rb'
require_relative 'math/max.rb'
require_relative 'math/mean.rb'
require_relative 'math/median.rb'
require_relative 'math/min.rb'
require_relative 'math/percentile.rb'
require_relative 'math/pow.rb'
require_relative 'math/pstd.rb'
require_relative 'math/pvariance.rb'
require_relative 'math/rmd.rb'
require_relative 'math/root.rb'
require_relative 'math/round.rb'
require_relative 'math/sec.rb'
require_relative 'math/sech.rb'
require_relative 'math/sign.rb'
require_relative 'math/sinc.rb'
require_relative 'math/sqr.rb'
require_relative 'math/sqsolve.rb'
require_relative 'math/std.rb'
require_relative 'math/stderr.rb'
require_relative 'math/sum.rb'
require_relative 'math/summed_sqdevs.rb'
require_relative 'math/tau.rb'
require_relative 'math/tgamma.rb'
require_relative 'math/theil_index.rb'
require_relative 'math/variance.rb'
@@ -0,0 +1,8 @@
module Math
# Absolute value of +x+.
def self.abs(x)
x.abs
end
end
@@ -0,0 +1 @@
require 'facets/math/acsc'
@@ -0,0 +1,8 @@
module Math
# Arcus cotangens of +x+
def self.acot(x)
(PI * 0.5) - atan(x)
end
end
@@ -0,0 +1,8 @@
module Math
# Area cotangens hyperbolicus of +x+
def self.acoth(x)
0.5 * log((x + 1.0) / (x - 1.0))
end
end
@@ -0,0 +1,13 @@
module Math
# Arcus cosecans of `x`.
def self.acsc(x)
asin(1.0 / x)
end
# Arcus cosecans of `x`.
def self.acosec(x)
asin(1.0 / x)
end
end
@@ -0,0 +1,8 @@
module Math
# Area cosecans hyperbolicus of +x+
def acsch(x)
::Math.log(1.0 / x + Math.sqrt(1.0 + 1.0 / (x * x)))
end
end
@@ -0,0 +1,17 @@
require 'facets/math/rmd'
require 'facets/math/mean'
module Math
# The average absolute difference of two independent values drawn
# from the sample. Equal to the RMD * mean.
def self.amd(array)
rmd(array) * mean(array)
end
class << self
alias_method :absolute_mean_difference, :amd
#alias_method :md, :mean_difference
end
end
@@ -0,0 +1,15 @@
module Math
#
EPSILON = 0.000000001
# Approximately equal.
#
# TODO: Use core extension Numeric#approx? instead (?)
def self.approx_equal(a, b, epsilon=EPSILON)
c = a - b
c *= -1.0 if c < 0
c < epsilon
end
end
@@ -0,0 +1,8 @@
module Math
# Arcus secans of +x+
def self.asec(x)
acos(1.0 / x)
end
end
@@ -0,0 +1,8 @@
module Math
# Area secans hyperbolicus of +x+
def asech(x)
log((1.0 + sqrt(1.0 - x * x)) / x)
end
end
@@ -0,0 +1,16 @@
require 'facets/math/theil_index'
module Math
# Closely related to the Theil index and easily expressible
# in terms of it.
#
# AI = 1-e^{theil_index}
#
# http://en.wikipedia.org/wiki/Atkinson_index
def self.atkinson_index(array)
t = theil_index(array)
(t < 0) ? -1 : 1-Math::E**(-t)
end
end
@@ -0,0 +1,14 @@
require 'facets/math/tgamma'
module Math
# Beta function of `x` and `y`.
#
# beta(x, y) = tgamma(x) * tgamma(y) / tgamma(x + y)
#
def self.beta(x, y)
#exp(lgamma(x).first + lgamma(y).first - lgamma(x+y).first)
tgamma(x) * tgamma(y) / tgamma(x + y)
end
end
@@ -0,0 +1,10 @@
module Math
# Returns the Cumulative Density Function of this
# sample (normalised to a fraction of 1.0).
def self.cdf(array, normalised=1.0)
s = sum(array).to_f
array.sort.inject([0.0]) { |c,d| c << c[-1] + normalised*d.to_f/s }
end
end
@@ -0,0 +1,8 @@
module Math
# Smallest integer not smaller than +x+.
def self.ceil(x)
x.ceil
end
end
@@ -0,0 +1 @@
require 'facets/math/csc'
@@ -0,0 +1 @@
require 'facets/math/csch'
@@ -0,0 +1,8 @@
module Math
# Cotangens of +x+
def self.cot(x)
tan((PI * 0.5) - x)
end
end
@@ -0,0 +1,8 @@
module Math
# Cotangens hyperbolicus of +x+
def self.coth(x)
1.0 / tanh(x)
end
end
@@ -0,0 +1,13 @@
module Math
# Cosecans of `x`.
def self.csc(x)
1.0 / sin(x)
end
# Cosecans of `x`.
def self.cosec(x)
1.0 / sin(x)
end
end
@@ -0,0 +1,13 @@
module Math
# Cosecans hyperbolicus of `x`.
def self.csch(x)
1.0 / sinh(x)
end
# Cosecans hyperbolicus of `x`.
def self.cosech(x)
1.0 / sinh(x)
end
end
@@ -0,0 +1,9 @@
module Math
# Kronecker symbol of +i+ and +j+.
# Returns 1 if +i+ and +j+ are equal, 0 otherwise.
def self.delta(i, j)
return Integer(i) == Integer(j) ? 1 : 0
end
end
@@ -0,0 +1,19 @@
module Math
# Calculates the Euclidean Distance between points +p+ and +q+.
#
# `p`, `q` is assumed to described coordinates in N-dimensions, e. g.:
#
# Math.distance([1, 1], [2, 2]) # 2D coordinates
# Math.distance([1, 1, 1], [2, 2, 2]) # 3D coordinates
#
# If N is 1, then `::distance` may also be invoked like so:
#
# Math.distance(1, 1)
#
def self.distance(p, q)
p, q = [p].flatten, [q].flatten
sqrt(p.zip(q).inject(0){ |sum, coord| sum + (coord.first - coord.last)**2 })
end
end
@@ -0,0 +1,5 @@
module Math
# Euler's constant.
EC = 0.577_215_664_901_532_861
end
@@ -0,0 +1,21 @@
module Math
# Levi-Civita symbol of +i+, +j+, and +k+ - 1 if (+i+, +j+, +k+)
# is (1, 2, 3), (2, 3, 1), or (3, 1, 2), -1 if it is (1, 3, 2),
# (2, 1, 3), or (3, 2, 1), 0 as long as +i+, +j+, and +k+ are
# all elements of {1, 2, 3}, otherwise returns <code>nil</code>.
def self.epsilon(i, j, k)
i = Integer(i)
return nil if i < 1 or i > 3
j = Integer(j)
return nil if j < 1 or j > 3
k = Integer(k)
return nil if k < 1 or k > 3
case i * 16 + j * 4 + k
when 27, 45, 54 then return 1
when 30, 39, 57 then return -1
end
0
end
end
@@ -0,0 +1,8 @@
module Math
# 10 to the power +x+
def self.exp10(x)
10.0 ** x
end
end
@@ -0,0 +1,8 @@
module Math
# 2 to the power +x+
def self.exp2(x)
2.0 ** x
end
end
@@ -0,0 +1,37 @@
module Math
# First 16 factorials.
FACTORIALS = [
1,
1,
2,
6,
24,
120,
720,
5_040,
40_320,
362_880,
3_628_800,
39_916_800,
479_001_600,
6_227_020_800,
87_178_291_200,
1_307_674_368_000
]
# 1 * 2 * ... * +n+, <code>nil</code> for negative numbers
def self.factorial(n)
n = Integer(n)
if n < 0
nil
elsif FACTORIALS.length > n
FACTORIALS[n]
else
h = FACTORIALS.last
(FACTORIALS.length .. n).each { |i| FACTORIALS.push h *= i }
h
end
end
end
@@ -0,0 +1,8 @@
module Math
# Largest integer not larger than +x+.
def self.floor(x)
x.floor
end
end
@@ -0,0 +1,23 @@
module Math
# Greatest common divisor of +m+ and +n+, +nil+ for non-positive
# numbers - gcd is computed by means of the Euclidian algorithm.
def self.gcd(m, n)
m = Integer(m)
n = Integer(n)
if m <= 0 || n <= 0
return nil
end
loop {
if m < n
m, n = n, m
end
if (l = m % n) == 0
break
end
m = l
}
n
end
end
@@ -0,0 +1,33 @@
require 'facets/math/approx_equal'
module Math
# Calculates the Gini Coefficient (a measure of inequality of a distribution
# based on the area between the Lorenz curve and the uniform curve).
#
# http://en.wikipedia.org/wiki/Gini_coefficient
#
# This is a slightly cleaner way of calculating the Gini Coefficient then
# the previous implementationj.
#
# GC = \frac{\sum_{i=1}^N (2i-N-1)x_i}{N^2-\bar{x}}
#
def self.gini_coefficient(array)
return -1 if size <= 0 or any? { |x| x < 0 }
return 0 if size < 2 or all? { |x| approx_equal(x,0) }
s = 0
sort.each_with_index { |li,i| s += (2*i+1-size)*li }
s.to_f/(size**2*mean).to_f
end
## OLD WAY
## GC = \frac{1}{N} \left ( N+1-2\frac{\sum_{i=1}^N (N+1-i)y_i}{\sum_{i=1}^N y_i} \right )
## def self.gini_coefficient2(array)
## return -1 if size <= 0 or any? { |x| x < 0 }
## return 0 if size < 2 or all? { |x| Math::float_equal(x,0) }
## s = 0
## sort.each_with_index { |yi,i| s += (size - i)*yi }
## (size+1-2*(s.to_f/sum.to_f)).to_f/size.to_f
## end
end
@@ -0,0 +1,19 @@
module Math
# The Kullback-Leibler divergence from this array to that of +q+.
#
# NB: You will possibly want to sort both P and Q before calling this
# depending on what you're actually trying to measure.
#
# http://en.wikipedia.org/wiki/Kullback-Leibler_divergence
#
def self.kldivergence(array, q)
fail "Buggy."
fail "Cannot compare differently sized arrays." unless size = q.size
kld = 0
each_with_index { |pi,i| kld += pi*Math::log(pi.to_f/q[i].to_f) }
kld
end
end
@@ -0,0 +1,15 @@
module Math
# Least common multiple of +m+ and +n+, computed by multiplying
# +m+ and +n+ and dividing the product by the gcd of +m+ and +n+,
# +nil+ for non-positive numbers.
def self.lcm(m, n)
m = Integer(m)
n = Integer(n)
if m <= 0 || n <= 0
return nil
end
m / gcd(m, n) * n
end
end
@@ -0,0 +1,23 @@
require 'facets/math/lngamma'
## This is the old definition by Josef Schugt.
##
## Around v2.0, Ruby finally added it's own `lgamma`
## function. That's good, but unforutnately it returns
## an array that includes the `sign(gamma(x))` too.
#
# def Math.lgamma(x)
# h = x + 5.5
# h -= (x + 0.5) * log(h)
#
# sum = 1.000_000_000_190_015
# sum += 76.180_091_729_471_46 / (x + 1.0)
# sum -= 86.505_320_329_416_77 / (x + 2.0)
# sum += 24.014_098_240_830_91 / (x + 3.0)
# sum -= 1.231_739_572_450_155 / (x + 4.0)
# sum += 0.120_865_097_386_617_9e-2 / (x + 5.0)
# sum -= 0.539_523_938_495_3e-5 / (x + 6.0)
#
# -h + log(2.506_628_274_631_000_5 * sum / x)
# end
@@ -0,0 +1,12 @@
module Math
# Returns real solution(s) of <code>+a+x + +b+ = +c+</code> or +nil+
# if no or an infinite number of solutions exist. If
# <code>c</code> is missing it is assumed to be 0.
#
# @author Josef Schugt
def self.linsolve(a, b, c = 0.0)
a == 0 ? nil : (c - b) / a
end
end
@@ -0,0 +1,18 @@
module Math
# Logarithmus naturalis of gamma function of `x`.
#
# Notice the use of `ln` prefix to differentiate from
# Ruby's built-in `#lgamma` function which returns an Array.
#
def self.lngamma(x)
lgamma(x).first
end
# Old name used by Extmath library.
def self.ln_gamma(x)
lgamma(x).first
end
end
@@ -0,0 +1,14 @@
module Math
INVERSE_LN_2 = 1.0 / ::Math.log(2.0)
unless defined?(log2)
# Logarithmus dualis of +x+.
def self.log2(x)
Math.log(x) * INVERSE_LN_2
end
end
end
@@ -0,0 +1 @@
require 'facets/math/min'
@@ -0,0 +1,16 @@
require 'facets/math/sum'
module Math
# Mean average.
def self.mean(array, &blk)
s = array.size
return 0.0 if s == 0
sum(array, &blk) / s
end
class << self
alias_method :mean_average, :mean
end
end
@@ -0,0 +1,30 @@
require 'facets/math/percentile'
module Math
# Returns the numerical median for the an array of values;
# or nil if array is empty.
#
def self.median(array)
percentile(array, 50)
end
# better definition ?
=begin
#
def self.median(array)
return 0 if array.size == 0
tmp = array.sort
mid = tmp.size / 2
if (tmp.size % 2) == 0
(tmp[mid-1] + tmp[mid]).to_f / 2
else
tmp[mid]
end
end
=end
end
@@ -0,0 +1,35 @@
module Math
#
def self.min(array, &block)
if block_given?
if min = array.find{ |i| i }
min = yield(min)
array.each do |i|
j = yield(i)
min = j if min > j
end
min
end
else
array.min
end
end
#
def self.max(array, block)
if block_given?
if max = find{|i| i}
max = yield(max)
each{|i|
j = yield(i)
max = j if max < j
}
max
end
else
array.max
end
end
end
@@ -0,0 +1,40 @@
module Math
# Returns the percentile value for percentile _pcnt_; nil if array is empty.
#
# +pcnt+ should be expressed as an integer, e.g. `percentile(90)` returns
# the 90th percentile of the array.
#
# Algorithm from NIST[http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm]
#
# NOTE: This is not a common core extension and is not
# loaded automatically when using <code>require 'facets'</code>.
#
# CREDIT: Ben Koski
#
# @non-core
# require 'facets/array/precentile'
#
def self.percentile(array, pcnt)
sorted_array = array.sort
return nil if array.length == 0
rank = (pcnt.to_f / 100) * (array.length + 1)
whole = rank.truncate
# if has fractional part
if whole != rank
s0 = sorted_array[whole - 1]
s1 = sorted_array[whole]
f = (rank - rank.truncate).abs
return (f * (s1 - s0)) + s0
else
return sorted_array[whole - 1]
end
end
end
@@ -0,0 +1,13 @@
module Math
# `x` to the power `y`.
def self.pow(x, y)
x ** y
end
# `x` to the power `y`.
def self.pwr(x, y)
x ** y
end
end
@@ -0,0 +1 @@
require 'facets/math/std'
@@ -0,0 +1 @@
require 'facets/math/variance'
@@ -0,0 +1,16 @@
require 'facets/math/approx_equal'
module Math
# Calculates the relative mean difference of this sample.
# Makes use of the fact that the Gini Coefficient is half the RMD.
def self.rmd(array)
return 0.0 if approx_equal(mean(array), 0.0)
gini_coefficient(array) * 2
end
class << self
alias_method :relative_mean_difference, :rmd
end
end
@@ -0,0 +1,8 @@
module Math
# The `y` root of `x`.
def self.root(x, y)
x ** (1.0 / y)
end
end
@@ -0,0 +1,9 @@
module Math
# Round number to an integer.
#
def self.round(x)
x.round
end
end
@@ -0,0 +1,8 @@
module Math
# Secans of +x+.
def self.sec(x)
1.0 / cos(x)
end
end
@@ -0,0 +1,8 @@
module Math
# Secans hyperbolicus of +x+
def self.sech(x)
1.0 / cosh(x)
end
end
@@ -0,0 +1,20 @@
module Math
# Sign of `x`. This function returns `-1.0` if `x` is negative,
# `+1.0` if `x` is positive `x`, and `0.0` if `x = 0`.
def self.sign(x, zero=0.0)
(x > 0.0) ? 1.0 : ((x < 0.0) ? -1.0 : zero)
end
# Same as `Math.sign`.
def self.sgn(x, zero=0.0)
(x > 0.0) ? 1.0 : ((x < 0.0) ? -1.0 : zero)
end
# The *Heaviside step function*, also called the the *unit step function*.
# This functions works like `Math.sign` but by default returns `1.0` for zero.
def self.unit_step(x, zero=1.0)
(x > 0.0) ? 1.0 : ((x < 0.0) ? -1.0 : zero)
end
end
@@ -0,0 +1,8 @@
module Math
# Sinc function of +x+.
def self.sinc(x)
(x == 0.0) ? 1.0 : sin(x) / x
end
end
@@ -0,0 +1,8 @@
module Math
# Square of number.
def self.sqr(x)
x * x
end
end
@@ -0,0 +1,55 @@
require 'facets/math/linsolve'
module Math
# Returns array of real solution of <code>ax**2 + bx + c = d</code>
# or <code>nil</code> if no or an infinite number of solutions exist.
# If +d+ is missing it is assumed to be 0.
#
# In order to solve <code>ax**2 + bx + c = d</code> +sqsolve+ identifies several cases:
# * <code>a == 0:</code>
# The equation to be solved is the linear equation <code>bx + c = d</code>. #sqsolve> delegates the computation to
# #linsolve>. If it results in +nil+, +nil+ is returned (not <code>[nil]</code>!). Otherwise a one-element array
# containing result of #linsolve is returned.
# * <code>a != 0:</code>
# The equation to be solved actually is a second order one.
# * <code>c == d</code>
# The equation to be solved is <code>ax**2 + bx = 0</code>. One solution of this equation obviously is
# <code>x = 0</code>, the second one solves <code>ax + b = 0</code>. The solution of the latter is
# delegated to +linsolve+. An array containing both results in ascending order is returned.
# * <code>c != d</code>
# The equation cannot be separated into <code>x</code> times some factor.
# * <code>b == 0</code>
# The equation to be solved is <code>ax**2 + c = d</code>. This can be written as the linear equation
# <code>ay + c = d</code> with <code>y = x ** 2</code>. The solution of the linear equation is delegated
# to +linsolve+. If the returned value for +y+ is +nil+, that becomes the overall return value.
# Otherwise an array containing the negative and positive squareroot of +y+ is returned
# * <code>b != 0 </code>
# The equation cannot be reduced to simpler cases. We now first have to compute what is called the
# discriminant <code>x = b**2 + 4a(d - c)</code> (that's what we need to compute the square root of).
# If the descriminant is negative no real solution exists and <code>nil</code> is returned. The ternary
# operator checking whether <code>b</code> is negative does ensure better numerical stability --only one
# of the two solutions is computed using the widely know formula for solving second order equations.
# The second one is computed from the fact that the product of both solutions is <code>(c - d) / a</code>.
# Take a look at a book on numerical mathematics if you don't understand why this should be done.
#
# @author Josef Schugt
def self.sqsolve(a, b, c, d = 0.0)
if a == 0.0
x = linsolve(b, c, d)
return x.nil? ? nil: [ linsolve(b, c, d) ]
else
return [0.0, linsolve(a, b)].sort if c == d
if b == 0.0
x = linsolve(a, c, d)
x < 0.0 ? nil : [-Math.sqrt(x), Math.sqrt(x)]
else
x = b * b + 4.0 * a * (d - c)
return nil if x < 0.0
x = b < 0 ? b - Math.sqrt(x) : b + Math.sqrt(x)
[-0.5 * x / a, 2.0 * (d - c) / x].sort
end
end
end
end
@@ -0,0 +1,27 @@
require 'facets/math/variance'
module Math
# Standard deviation of a sample.
#
def self.std(array, &block)
sqrt(variance(array, &block))
end
class << self
alias_method :standard_deviation, :std
end
# Standard deviation of a population.
#
def self.pstd(array, &block)
Math::sqrt(pvariance(array, &block))
end
# Calculates the standard error of a sample.
def self.stderr(array)
return 0.0 if array.size < 2
std(array) / sqrt(array.size)
end
end
@@ -0,0 +1 @@
require 'facets/math/std'
@@ -0,0 +1,16 @@
module Math
# Returns sum. When a block is given, summation is taken over the
# each result of block evaluation.
#
def self.sum(array) #:yield:
sum = 0.0
if block_given?
array.each{|i| sum += yield(i)}
else
array.each{|i| sum += i}
end
sum
end
end
@@ -0,0 +1,14 @@
require 'facets/math/sum'
require 'facets/math/mean'
module Math
# The sum of the squared deviations from the mean.
#
def self.summed_sqdevs(array)
return 0 if array.size < 2
m = mean(array)
sum(array.map{ |x| (x - m) ** 2 })
end
end
@@ -0,0 +1,5 @@
module Math
# See http://tauday.com/tau-manifesto
TAU = 2 * PI
end

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