This commit is contained in:
@@ -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>") #=> "<tag>"
|
||||
# escape_html("Example\nString", :newlines) #=> "Example String"
|
||||
# escape_html("\"QUOTE\"", false) #=> "\"QUOTE\""
|
||||
#
|
||||
def self.escape_html(string, *modes)
|
||||
modes << :defualt if modes.empty?
|
||||
|
||||
unless modes.include?(:nonstandard)
|
||||
string = string.gsub(/&/, '&').gsub(/>/, '>').gsub(/</, '<')
|
||||
end
|
||||
|
||||
modes.each do |mode|
|
||||
string = \
|
||||
case mode
|
||||
when :quote, :quotes
|
||||
string.gsub(%r|"|,'"').gsub(%r|'|,''')
|
||||
when :newlines, :newlines
|
||||
string.gsub(/[\r\n]+/,' ')
|
||||
when :ampersand
|
||||
string.gsub(/&/, '&')
|
||||
when :bracket, :brackets
|
||||
string.gsub(/>/, '>').gsub(/</, '<')
|
||||
when :default, true
|
||||
string.gsub(/\"/, '"')
|
||||
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
Reference in New Issue
Block a user