polyglot.rb 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. require 'pathname'
  2. module Polyglot
  3. @registrations ||= {} # Guard against reloading
  4. @loaded ||= {}
  5. class PolyglotLoadError < LoadError; end
  6. class NestedLoadError < LoadError
  7. def initialize le
  8. @le = le
  9. end
  10. def reraise
  11. raise @le
  12. end
  13. end
  14. def self.register(extension, klass)
  15. extension = [extension] unless Array === extension
  16. extension.each{|e|
  17. @registrations[e] = klass
  18. }
  19. end
  20. def self.find(file, *options, &block)
  21. is_absolute = Pathname.new(file).absolute?
  22. (is_absolute ? [""] : $:).each{|lib|
  23. base = is_absolute ? "" : lib+File::SEPARATOR
  24. # In Windows, repeated SEPARATOR chars have a special meaning, avoid adding them
  25. matches = Dir["#{base}#{file}{,.#{@registrations.keys*',.'}}"]
  26. # Revisit: Should we do more do if more than one candidate found?
  27. $stderr.puts "Polyglot: found more than one candidate for #{file}: #{matches*", "}" if matches.size > 1
  28. if path = matches[0]
  29. return [ path, @registrations[path.gsub(/.*\./,'')]]
  30. end
  31. }
  32. return nil
  33. end
  34. def self.load(*a, &b)
  35. file = a[0].to_str
  36. return if @loaded[file] # Check for $: changes or file time changes and reload?
  37. begin
  38. source_file, loader = Polyglot.find(file, *a[1..-1], &b)
  39. if (loader)
  40. begin
  41. loader.load(source_file)
  42. @loaded[file] = true
  43. rescue LoadError => e
  44. raise Polyglot::NestedLoadError.new(e)
  45. end
  46. else
  47. raise PolyglotLoadError.new("Failed to load #{file} using extensions #{(@registrations.keys+["rb"]).sort*", "}")
  48. end
  49. end
  50. end
  51. end
  52. module Kernel
  53. alias polyglot_original_require require
  54. def require(*a, &b)
  55. polyglot_original_require(*a, &b)
  56. rescue LoadError => load_error
  57. begin
  58. Polyglot.load(*a, &b)
  59. rescue Polyglot::NestedLoadError => e
  60. e.reraise
  61. rescue LoadError
  62. # Raise the original exception, possibly a MissingSourceFile with a path
  63. raise load_error
  64. end
  65. end
  66. end