#-- # Facets System # 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. #++ # Author:: Thomas Sawyer # Copyright:: Copyright (c) 2005 Thomas Sawyer # License:: Ruby License # = Facets System # # This is a central "meta" controller for the Facets system. # It can be used to dynmically gleen information about Facets. # Or used to load a facet give the symbol of the actual method. # # == Synopsis # # TODO # module Facets extend self 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'], } NOAUTO = %w{ array/op_fetch.rb array/op_store.rb binding/self/of_caller.rb hash/op_fetch.rb hash/op_store.rb numeric/succ.rb numeric/pred.rb string/succ.rb string/unpack.rb module/attr.rb hash/each.rb module/methods.rb object/method.rb nilclass/op_fetch.rb nilclass/empty.rb nilclass/include.rb nilclass/size.rb nilclass/length.rb nilclass/method_missing.rb date/* fileutils/* ostruct/* logger/* gem/* } METHDIR = "facet" def op_esc( str ) str = str.to_s.chomp('.rb') str = str.strip.gsub(OPERATORS_REGEXP){ OPERATORS_ESCAPE[$1] } str.chomp('?').chomp('!').chomp('=') end # 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 # Returns a file list of all extensions. def extensions return @all_extensions if @all_extensions Dir.chdir( File.join( Config::CONFIG['sitelibdir'], METHDIR ) ) do all = Dir.glob( '*/*.rb' ) + Dir.glob( '*/*/*.rb' ) end @extensions = all end # Returns file list of all extensions minus the ones that should not be autoloaded. def extensions_nice @safe_extensions ||= nice_only( extensions ) end # Removes the NOAUTO files from the given extensions list. def nice_only( exts ) exts = exts.dup NOAUTO.each do |f| if f.include?('*') re = %r"#{f.gsub('*','.*')}" exts.reject!{ |x| x =~ re } elsif exts.include?(f) exts.delete f end end exts.sort end #-- # NOTE Is there any other way to handle subclasses? #++ alias_method :require_facetless, :require def require( klass, fname ) klass = klass.to_s.downcase fname = op_esc(fname.to_s) if CLASS_ANCESTORS.key?( klass ) ancestors = [klass, *CLASS_ANCESTORS[klass]] begin require_facetless( File.join( METHDIR, klass, fname ) ) rescue LoadError => e klass = ancestors.shift retry if klass raise e end else require_facetless( File.join(METHDIR, klass.name.downcase, 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