#-- # Facets # # Copyright (c) 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. # # ========================================================================== # Revision History # -------------------------------------------------------------------------- # 2006-03-23 Trans * Clean-up, finally ready enough for regular usage. # # ========================================================================== # #++ # :title: Facets # # This the base system. It automitically loads the facets methods # considered base and appends the facets locations to the load path. # # == Synopsis # # require 'facets' # require 'string/blank' # require 'functor' # # == Author(s) # # * Thomas Sawyer # $: << File.join( File.dirname(__FILE__), 'facets/core' ) $: << File.join( File.dirname(__FILE__), 'facets/more' ) # These are the methods considered "base". # A method is deemed base if it is obvious, # simple, unobtrusive and/or widely useful. # # This list is still being refined. # # NOTE # # The #cmp methods are simply aliases for #<=>, they # are here b/c String.succ is not compataible # with it's own #<=> method. The #cmp method proves # an effective way of dealing with when needs be. # DEPRECATED Use Facets.require instead (now not even that!) #require 'kernel/require_facet' # Elementary require 'facets/core/comparable/cmp' require 'facets/core/string/cmp' require 'facets/core/nilclass/to_h' require 'facets/core/binding/eval' require 'facets/core/binding/self' require 'facets/core/binding/caller' require 'facets/core/module/basename' require 'facets/core/proc/to_method' require 'facets/core/kernel/constant' require 'facets/core/kernel/called' # better name? require 'facets/core/symbol/to_proc' # Elementary (Know Thyself) require 'facets/core/hash/to_h' require 'facets/core/range/to_r' require 'facets/core/regexp/to_re' require 'facets/core/time/to_time' # "Minis" (Shorthands) require 'facets/core/module/is' require 'facets/core/kernel/fn' require 'facets/core/kernel/here' require 'facets/core/kernel/own' # better name? # Convenience require 'facets/core/array/to_h' require 'facets/core/enumerable/to_h' require 'facets/core/enumerable/collect_with_index' require 'facets/core/enumerable/each_slice' require 'facets/core/file/self/read_list' require 'facets/core/float/round_to' require 'facets/core/float/round_at' require 'facets/core/hash/slice' require 'facets/core/matchdata/match' require 'facets/core/matchdata/matchtree' require 'facets/core/string/blank' require 'facets/core/string/to_re' # New Features require 'facets/core/symbol/not' require 'facets/core/kernel/as' module Facets extend self # This simply subs terms for Ruby's operators # and removes any trailing ? ! or =. def op_esc_path( name ) ri = name.rindex('/') if ri dir, file = name[0...ri], name[ri+1..-1] else dir, file = nil, name end file = op_esc(file.strip) dir ? File.join( dir, file ) : file end def op_esc( str ) str = str.to_s.chomp('.rb') str = str.strip.gsub(OPERATORS_REGEXP){ OPERATORS_ESCAPE[$1] } str.chomp('?').chomp('!').chomp('=') end OPERATORS = %w{ +@ -@ + - ** * / % ~ <=> << >> < > === == =~ <= >= | & ^ []= [] } OPERATORS_REGEXP = Regexp.new( '(' << OPERATORS.collect{ |k| Regexp.escape(k) }.join('|') << ')' ) OPERATORS_ESCAPE = { "+@" => "op_plus_self", "-@" => "op_minus_self", "+" => "op_plus", "-" => "op_minus", "**" => "op_pow", "*" => "op_mul", "/" => "op_div", "%" => "op_mod", "~" => "op_tilde", "<=>" => "op_cmp", "<<" => "op_lshift", ">>" => "op_rshift", "<" => "op_lt", ">" => "op_gt", "===" => "op_case_eq", "==" => "op_equal", "=~" => "op_apply", "<=" => "op_lt_eq", ">=" => "op_gt_eq", "|" => "op_or", "&" => "op_and", "^" => "op_xor", "[]=" => "op_store", "[]" => "op_fetch" } CLASS_ANCESTORS = { 'array' => ['enumerable','kernel'], 'binding' => ['kernel'], 'class' => ['module','kernel'], 'comparable' => ['kernel'], 'continuation' => ['kernel'], 'date' => ['comparable','kernel'], 'dir' => ['enumerable','kernel'], 'enumerable' => ['kernel'], 'file' => ['io','enumerable','kernel'], 'fileutils' => ['kernel'], 'float' => ['precision','numeric','comparable','kernel'], 'hash' => ['enumerable','kernel'], 'integer' => ['precision','numeric','comparable','kernel'], 'kernel' => ['kernel'], 'logger' => ['kernel'], 'matchdata' => ['kernel'], 'module' => ['kernel'], 'nilclass' => ['kernel'], 'numeric' => ['comparable','kernel'], 'ostruct' => ['kernel'], 'pathname' => ['kernel'], 'proc' => ['kernel'], 'range' => ['enumerable','kernel'], 'regexp' => ['kernel'], 'string' => ['enumerable','comparable','kernel'], 'symbol' => ['kernel'], 'time' => ['comparable','kernel'], 'unboundmethod' => ['kernel'], } METHDIR = "facet" alias_method :require_facet, :require def require( fname ) paths = fname.split('/') klass = paths[0].downcase if CLASS_ANCESTORS.key?( klass ) if paths.size > 1 klass = paths[0].downcase ancestors = CLASS_ANCESTORS[ klass ] || [] paths[-1] = op_esc( paths[-1] ) begin paths[0] = klass require_facet( File.join( METHDIR, *paths ) ) rescue LoadError => e klass = ancestors.shift retry if klass raise e end else require_facet( File.join( METHDIR, fname ) ) end else require_facet( File.join( METHDIR, fname ) ) end end end # Override Kernel require method to reroute Facet requires. # #module Kernel # # alias_method :require_facetless, :require # # def require( fname ) # if /^(facet|facets|nano)[\/\\]/ =~ fname # Facets.require($') # else # require_facetless( fname ) # end # end # #end