├── var ├── name ├── source ├── title ├── created ├── version ├── summary ├── authors ├── copyrights ├── repositories ├── requirements ├── description └── resources ├── Gemfile ├── spec ├── fixture │ ├── subpro │ │ ├── lib │ │ │ └── subpro.rb │ │ └── .ruby │ ├── ansi.rb │ └── abbrev.rb ├── runner.rb ├── helper.rb ├── spec_vendor_loader.rb ├── spec_ruby_loader.rb └── spec_gem_loader.rb ├── work ├── issue │ ├── fixture │ │ └── abbrev.rb │ └── tryit.rb ├── Profile ├── bench │ └── obj_vs_mod.rb └── reference │ ├── load_path_search.rb │ ├── vendor.rb │ └── search.rb ├── .ruby ├── .yardopts ├── .gitignore ├── lib ├── loadable.rb └── loadable │ ├── loaders │ ├── roll_loader.rb │ ├── original_loader.rb │ ├── ruby_loader.rb │ ├── gem_loader.rb │ └── vendor_loader.rb │ ├── class_require.rb │ ├── system.rb │ ├── version.rb │ ├── kernel.rb │ ├── domain.rb │ ├── core_ext │ └── rubygems.rb │ └── mixin.rb ├── .travis.yml ├── Rulefile ├── Assembly ├── MANIFEST ├── LICENSE.txt ├── HISTORY.md ├── .index ├── README.md ├── .gemspec └── INFRACTIONS.md /var/name: -------------------------------------------------------------------------------- 1 | loadable -------------------------------------------------------------------------------- /var/source: -------------------------------------------------------------------------------- 1 | Profile -------------------------------------------------------------------------------- /var/title: -------------------------------------------------------------------------------- 1 | Loadable -------------------------------------------------------------------------------- /var/created: -------------------------------------------------------------------------------- 1 | 2010-07-21 -------------------------------------------------------------------------------- /var/version: -------------------------------------------------------------------------------- 1 | 1.2.1 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | gemspec 3 | -------------------------------------------------------------------------------- /var/summary: -------------------------------------------------------------------------------- 1 | Safely Customize Ruby's Load System -------------------------------------------------------------------------------- /spec/fixture/subpro/lib/subpro.rb: -------------------------------------------------------------------------------- 1 | $SUBPRO = true 2 | -------------------------------------------------------------------------------- /work/issue/fixture/abbrev.rb: -------------------------------------------------------------------------------- 1 | AltAbbrev = true 2 | -------------------------------------------------------------------------------- /var/authors: -------------------------------------------------------------------------------- 1 | --- 2 | - Thomas Sawyer 3 | -------------------------------------------------------------------------------- /.ruby: -------------------------------------------------------------------------------- 1 | ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-linux] 2 | -------------------------------------------------------------------------------- /var/copyrights: -------------------------------------------------------------------------------- 1 | --- 2 | - (c) 2010 Thomas Sawyer, RubyWorks (BSD-2-Clause) 3 | -------------------------------------------------------------------------------- /var/repositories: -------------------------------------------------------------------------------- 1 | --- 2 | upstream: git://github.com/rubyworks/loadable.git 3 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --protected 2 | --private 3 | lib/ 4 | - 5 | [A-Z]*.* 6 | log/[A-Z].* 7 | -------------------------------------------------------------------------------- /spec/fixture/subpro/.ruby: -------------------------------------------------------------------------------- 1 | --- 2 | name: subpro 3 | version: 0.0.0 4 | load_path: [lib] 5 | 6 | -------------------------------------------------------------------------------- /spec/runner.rb: -------------------------------------------------------------------------------- 1 | # Load all specs. 2 | Dir['./spec/*_spec.rb'].each do |spec| 3 | require spec 4 | end 5 | 6 | -------------------------------------------------------------------------------- /var/requirements: -------------------------------------------------------------------------------- 1 | --- 2 | - detroit (build) 3 | - minitest (test) 4 | - minitap (test) 5 | - rake (build) 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .reap/digest 2 | .yardoc 3 | log 4 | doc 5 | pkg 6 | tmp 7 | man/*.html 8 | man/*.1 9 | man/*.5 10 | man/*.7 11 | web -------------------------------------------------------------------------------- /spec/fixture/ansi.rb: -------------------------------------------------------------------------------- 1 | # This is a dummy ansi.rb script to test 2 | # if ansi.rb from the ANSI gem can be loaded. 3 | $NO_ANSI = true 4 | -------------------------------------------------------------------------------- /spec/fixture/abbrev.rb: -------------------------------------------------------------------------------- 1 | # This is a dummy abbrev.rb script to test 2 | # is Ruby's standard abbrev.rb can be loaded. 3 | $NO_ABBREV = true 4 | -------------------------------------------------------------------------------- /lib/loadable.rb: -------------------------------------------------------------------------------- 1 | require 'loadable/system' 2 | 3 | Loadable.register(Loadable::RubyLoader.new) 4 | Loadable.register(Loadable::GemLoader.new) 5 | 6 | -------------------------------------------------------------------------------- /spec/helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/spec' 2 | require 'minitest/autorun' 3 | require 'minitap' 4 | 5 | MiniTest::Unit.runner = MiniTest::TapY.new 6 | 7 | -------------------------------------------------------------------------------- /var/description: -------------------------------------------------------------------------------- 1 | Loadable modifieds Ruby's load/require system to handle "load wedges", which work much like routes in web frameworks, but in this case determine which files get loaded. -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | script: "ruby -Ilib -Ispec spec/runner.rb" 3 | rvm: 4 | - 1.8.7 5 | - 1.9.2 6 | - 1.9.3 7 | - rbx 8 | - rbx-19mode 9 | - jruby 10 | - jruby-19mode 11 | 12 | -------------------------------------------------------------------------------- /Rulefile: -------------------------------------------------------------------------------- 1 | desc "Run unit tests" 2 | task :test do 3 | system "ruby -Ilib -Ispec spec/*.rb | tapout pretty" 4 | end 5 | 6 | desc "Generate man pages" 7 | task :ronn do 8 | system "ronn man/*.ronn" 9 | end 10 | 11 | -------------------------------------------------------------------------------- /work/issue/tryit.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift('./fixture') 2 | 3 | require '/usr/local/lib/ruby/1.9.1/abbrev.rb' 4 | 5 | raise unless Abbrev 6 | 7 | require 'abbrev' 8 | 9 | raise unless AltAbbrev 10 | 11 | puts "Looks good!" 12 | 13 | -------------------------------------------------------------------------------- /var/resources: -------------------------------------------------------------------------------- 1 | --- 2 | home: http://rubyworks.github.com/loadable 3 | code: http://github.com/rubyworks/loadable 4 | docs: http://rubydoc.info/github/rubyworks/loadable/master/frames 5 | mail: http://groups.google.com/group/rubyworks-mailinglist 6 | chat: irc://irc.freenode.net/rubyworks 7 | -------------------------------------------------------------------------------- /lib/loadable/loaders/roll_loader.rb: -------------------------------------------------------------------------------- 1 | require 'loadable/mixin' 2 | 3 | module Loadable 4 | 5 | # 6 | class RollLoader 7 | 8 | include Loadable 9 | 10 | # 11 | def call(fname, options={}) 12 | end 13 | 14 | # 15 | def each(options={}) 16 | end 17 | 18 | end 19 | 20 | end 21 | 22 | -------------------------------------------------------------------------------- /lib/loadable/class_require.rb: -------------------------------------------------------------------------------- 1 | class Module 2 | def module_require(child) 3 | child = child.to_s.gsub('::','/').downcase 4 | path = name.to_s.gsub('::','/').downcase 5 | path = File.join(path, child) 6 | require_relative(path) 7 | end 8 | alias_mehtod :class_require, :module_require 9 | end 10 | 11 | -------------------------------------------------------------------------------- /lib/loadable/system.rb: -------------------------------------------------------------------------------- 1 | require 'loadable/version' 2 | require 'loadable/mixin' 3 | require 'loadable/domain' 4 | require 'loadable/loaders/original_loader' 5 | require 'loadable/loaders/ruby_loader' 6 | require 'loadable/loaders/gem_loader' 7 | require 'loadable/loaders/vendor_loader' 8 | require 'loadable/kernel' 9 | 10 | Loadable.register(Loadable::OriginalLoader.new) 11 | 12 | -------------------------------------------------------------------------------- /lib/loadable/version.rb: -------------------------------------------------------------------------------- 1 | module RbConfig 2 | 3 | class LoadWedge 4 | 5 | # 6 | def self.metadata 7 | @metadata ||= ( 8 | require 'yaml' 9 | YAML.load_file(File.dirname(__FILE__) + '/load_wedge.yml') 10 | ) 11 | end 12 | 13 | # 14 | def self.method_missing(name) 15 | metadata[name.to_s.downcase] || super(name) 16 | end 17 | 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /work/Profile: -------------------------------------------------------------------------------- 1 | --- 2 | title : Wedge 3 | suite : rubyworks 4 | summary: Customize The Load 5 | contact: trans 6 | authors: Thomas Sawyer 7 | license: Apache 2.0 8 | created: 2010-07-21 9 | 10 | requires: 11 | - syckle (build) 12 | 13 | resources: 14 | home: http://rubyworks.github.com/wedge 15 | 16 | repositories: 17 | repo: git://github.com/rubyworks/wedge.git 18 | 19 | copyright: Copyright (c) 2010 Thomas Sawyer 20 | 21 | -------------------------------------------------------------------------------- /work/bench/obj_vs_mod.rb: -------------------------------------------------------------------------------- 1 | require 'benchmark' 2 | 3 | class X 4 | 5 | def self.x(arg1, arg2) 6 | arg1 + arg2 7 | end 8 | 9 | def initialize(arg1, arg2) 10 | @arg1 = arg1 11 | @arg2 = arg2 12 | end 13 | 14 | def x 15 | @arg1 + @arg2 16 | end 17 | 18 | end 19 | 20 | n = 500000 21 | Benchmark.bmbm do |x| 22 | x.report("X.x "){ n.times{ X.x(1,2) } } 23 | x.report("X.new.x "){ n.times{ X.new(1,2).x } } 24 | end 25 | 26 | -------------------------------------------------------------------------------- /work/reference/load_path_search.rb: -------------------------------------------------------------------------------- 1 | class << $LOAD_PATH 2 | 3 | # Search standard $LOAD_PATH. 4 | # 5 | # $LOAD_PATH.search('rdoc/discover.rb') 6 | # 7 | # NOTE: in older versions of RubyGems, activated gem versions are in here too. 8 | # 9 | def search(match, options={}) 10 | matches = [] 11 | self.uniq.each do |path| 12 | path = File.expand_path(path) 13 | list = Dir.glob(File.join(path, match)) 14 | list = list.map{ |d| d.chomp('/') } 15 | matches.concat(list) 16 | end 17 | matches 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | gem: 3 | active : true 4 | 5 | dnote: 6 | title : Developer's Notes 7 | labels : ~ 8 | output : log/DNOTE.rdoc 9 | active : true 10 | 11 | yard: 12 | yardopts: true 13 | output : doc 14 | 15 | minitest: 16 | tests : ~ 17 | exclude : ~ 18 | loadpath : ~ 19 | requires : ~ 20 | live : false 21 | active : false 22 | 23 | github: 24 | gh_pages: web 25 | 26 | email: 27 | mailto: 28 | - ruby-talk@ruby-lang.org 29 | - rubyworks-mailinglist@googlegroups.com 30 | 31 | vclog: 32 | output: 33 | - log/history.html 34 | - log/changes.html 35 | 36 | -------------------------------------------------------------------------------- /spec/spec_vendor_loader.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | require 'loadable' 3 | 4 | describe "VendorLoader" do 5 | 6 | dir = File.dirname(__FILE__) + '/fixture' 7 | 8 | it "should be able to vendor a directory directly" do 9 | loader = Loadable::VendorLoader.new(dir, :direct=>true) 10 | list = [] 11 | loader.each{ |f| list << f } 12 | list.must_include('abbrev.rb') 13 | list.must_include('ansi.rb') 14 | end 15 | 16 | it "should be able to vendor subprojects" do 17 | loader = Loadable::VendorLoader.new(dir, '*') 18 | list = [] 19 | loader.each{ |f| list << f } 20 | list.must_include('subpro.rb') 21 | end 22 | 23 | it "should vendor using the Loadable class method" do 24 | Loadable.vendor(dir, '*') 25 | require 'subpro' 26 | assert $SUBPRO, "Vendored project not loaded." 27 | end 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | #!mast .index .yardopts .ruby bin demo lib share spec test [A-Z]*.* 2 | .index 3 | .yardopts 4 | .ruby 5 | lib/loadable/class_require.rb 6 | lib/loadable/core_ext/rubygems.rb 7 | lib/loadable/domain.rb 8 | lib/loadable/kernel.rb 9 | lib/loadable/loaders/gem_loader.rb 10 | lib/loadable/loaders/original_loader.rb 11 | lib/loadable/loaders/roll_loader.rb 12 | lib/loadable/loaders/ruby_loader.rb 13 | lib/loadable/loaders/vendor_loader.rb 14 | lib/loadable/mixin.rb 15 | lib/loadable/system.rb 16 | lib/loadable/version.rb 17 | lib/loadable.rb 18 | spec/fixture/abbrev.rb 19 | spec/fixture/ansi.rb 20 | spec/fixture/subpro/.ruby 21 | spec/fixture/subpro/lib/subpro.rb 22 | spec/helper.rb 23 | spec/runner.rb 24 | spec/spec_gem_loader.rb 25 | spec/spec_ruby_loader.rb 26 | spec/spec_vendor_loader.rb 27 | LICENSE.txt 28 | HISTORY.md 29 | README.md 30 | INFRACTIONS.md 31 | -------------------------------------------------------------------------------- /spec/spec_ruby_loader.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | require 'loadable' 3 | 4 | describe "RubyLoader" do 5 | 6 | # setup alternate loadpath 7 | dir = File.expand_path(File.dirname(__FILE__) + '/fixture') 8 | 9 | before do 10 | $LOAD_PATH.unshift(dir) 11 | end 12 | 13 | after do 14 | $LOAD_PATH.delete(dir) 15 | end 16 | 17 | it "should load local library without the ruby prefix" do 18 | require 'abbrev' 19 | assert $NO_ABBREV, "Local `abbrev.rb' library not loaded." 20 | end 21 | 22 | it "should load the standard ruby library with the `:from` ruby option" do 23 | require 'abbrev', :from=>'ruby' 24 | assert Abbrev, "Ruby `abbrev.rb' library not loaded." 25 | end 26 | 27 | it "should iterate over standard ruby libs" do 28 | loader = Loadable::RubyLoader.new 29 | 30 | list = [] 31 | loader.each{ |f| list << f } 32 | 33 | assert list.include?('abbrev.rb') 34 | assert list.include?('ostruct.rb') 35 | end 36 | 37 | end 38 | 39 | -------------------------------------------------------------------------------- /lib/loadable/kernel.rb: -------------------------------------------------------------------------------- 1 | module Kernel 2 | 3 | # Aliases for original load and require. 4 | alias_method :load0, :load 5 | alias_method :require0, :require 6 | 7 | # TODO: I am not certain `:load` is the best name for this option. 8 | # Something like `:eval` is more meaningful. OTOH, we could flip 9 | # it about and use `:feature` or `:cache` to mean the opposite. 10 | 11 | # 12 | def require(fname, options={}) 13 | options[:load] = false unless options.key?(:load) 14 | Loadable.call(fname, options) 15 | #success = LoadSystem.require(fname, options) 16 | #if success.nil? 17 | # success = require_without_wedge(fname) 18 | #end 19 | #success 20 | end 21 | 22 | # 23 | def load(fname, options={}) 24 | options = Hash===options ? options : {:wrap=>options} 25 | options[:load] = true unless options.key?(:load) 26 | Loadable.call(fname, options) 27 | #success = LoadSystem.load(fname, options) 28 | #if success.nil? 29 | # success = load_without_wedge(fname) 30 | #end 31 | #success 32 | end 33 | 34 | end 35 | 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD-2-Clause License 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR 16 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # RELEASE HISTORY 2 | 3 | ## 1.2.1 / 2012-12-21 4 | 5 | Long overdo bug fix release. This release fixes a typo in the 6 | rubygems search function. 7 | 8 | Changes: 9 | 10 | * Fix bug in rubygems search function. 11 | 12 | 13 | ## 1.2.0 / 2011-10-15 14 | 15 | This release brings an almost complete rewrite of the API and 16 | a renaming of the project form 'wedge' to 'loadable'. See the 17 | API documentaiton for details. 18 | 19 | Changes: 20 | 21 | * Rewrite API almost entirely. 22 | * Rename project from 'wedge' to 'loadable'. 23 | * Utilize mixin rather than sublcass for loader classes. 24 | * OriginalLoader handles Ruby's default load mechanism. 25 | * New VendorLoader to support development. 26 | 27 | 28 | ## 1.1.0 / 2011-07-03 29 | 30 | The Ruby wedge is no longer automatuically loaded when using 31 | `require "wedge"`. Load it manually loaded with `require "wedge/ruby`". 32 | 33 | Changes: 34 | 35 | * Ruby wedge is not automatically loaded with wedge library. 36 | 37 | 38 | ## 1.0.0 / 2010-09-03 39 | 40 | This release is simply a maintenance release, updating some project metadata. 41 | No functionality has been changed. 42 | 43 | Changes: 44 | 45 | * Uupdate project metadata to latest POM. 46 | 47 | 48 | ## 1.0.0 / 2010-08-01 49 | 50 | Initial release of Wedge, a tool for easily creating custom 51 | load managers. 52 | 53 | Changes: 54 | 55 | * Happy Brithday! 56 | 57 | -------------------------------------------------------------------------------- /spec/spec_gem_loader.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | require 'loadable' 3 | 4 | # TODO: techincally these tests need to be isolated in separate processes 5 | # to truly work right, but we won't overly fret about it presently b/c 6 | # MiniTest randomizes execution order, so they will get fully tested 7 | # over the course a handful of runs. 8 | 9 | describe "GemLoader" do 10 | 11 | # setup alternate loadpath 12 | dir = File.expand_path(File.dirname(__FILE__) + '/fixture') 13 | 14 | before do 15 | $LOAD_PATH.unshift(dir) 16 | end 17 | 18 | after do 19 | $LOAD_PATH.delete(dir) 20 | end 21 | 22 | it "should load local library when neither `:gem` or `:from` option is supplied" do 23 | require 'ansi' 24 | assert $NO_ANSI, "Local `ansi.rb' library not loaded." 25 | end 26 | 27 | it "should load the gem when `:from` option is supplied" do 28 | require 'ansi', :gem=>'ansi' 29 | assert ANSI, "Ruby `ansi.rb' library not loaded." 30 | end 31 | 32 | it "should load from the gem when the `:gem` option is supplied" do 33 | require 'ansi', :from=>'ansi' 34 | assert ANSI, "Ruby `ansi.rb' library not loaded." 35 | end 36 | 37 | # This isn't a 100% thurough. 38 | it "should iterate over current gems files" do 39 | loader = Loadable::GemLoader.new 40 | 41 | list = [] 42 | loader.each(:gem=>'ansi'){ |f| list << f } 43 | 44 | assert list.include?('ansi.rb') 45 | assert list.include?('ansi/code.rb') 46 | end 47 | 48 | end 49 | 50 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | type: ruby 3 | revision: 2013 4 | sources: 5 | - var 6 | authors: 7 | - name: Thomas Sawyer 8 | email: transfire@gmail.com 9 | organizations: [] 10 | requirements: 11 | - groups: 12 | - build 13 | development: true 14 | name: detroit 15 | - groups: 16 | - test 17 | development: true 18 | name: minitest 19 | - groups: 20 | - test 21 | development: true 22 | name: minitap 23 | - groups: 24 | - build 25 | development: true 26 | name: rake 27 | conflicts: [] 28 | alternatives: [] 29 | resources: 30 | - type: home 31 | uri: http://rubyworks.github.com/loadable 32 | label: Homepage 33 | - type: code 34 | uri: http://github.com/rubyworks/loadable 35 | label: Source Code 36 | - type: docs 37 | uri: http://rubydoc.info/github/rubyworks/loadable/master/frames 38 | label: Documentation 39 | - type: mail 40 | uri: http://groups.google.com/group/rubyworks-mailinglist 41 | label: Mailing List 42 | - type: chat 43 | uri: irc://irc.freenode.net/rubyworks 44 | label: IRC Channel 45 | repositories: 46 | - name: upstream 47 | scm: git 48 | uri: git://github.com/rubyworks/loadable.git 49 | categories: [] 50 | paths: 51 | load: 52 | - lib 53 | copyrights: 54 | - holder: Thomas Sawyer, RubyWorks 55 | year: '2010' 56 | license: BSD-2-Clause 57 | created: '2010-07-21' 58 | summary: Safely Customize Ruby's Load System 59 | title: Loadable 60 | version: 1.2.1 61 | name: loadable 62 | description: Loadable modifieds Ruby's load/require system to handle "load wedges", 63 | which work much like routes in web frameworks, but in this case determine which 64 | files get loaded. 65 | date: '2012-12-21' 66 | -------------------------------------------------------------------------------- /lib/loadable/domain.rb: -------------------------------------------------------------------------------- 1 | module Loadable 2 | 3 | # Stores active loaders. 4 | $LOADERS = [] 5 | 6 | # Require/load script. 7 | # 8 | # @param [String] fname 9 | # The script to require/load. 10 | # 11 | def self.call(fname, options={}) 12 | success = nil 13 | $LOADERS.each do |wedge| 14 | success = wedge.call(fname, options) 15 | break unless success.nil? 16 | end 17 | return success 18 | end 19 | 20 | # Iterate over all requirable files. 21 | # 22 | # Loadable.each{ |file| p file } 23 | # 24 | # Note that esoteric load wedges may return a symbolic path rather than 25 | # an actual file path. 26 | # 27 | def self.each(options={}, &block) 28 | $LOADERS.each do |wedge| 29 | wedge.each(options, &block) 30 | end 31 | end 32 | 33 | # Search wedges for all matching paths. 34 | # 35 | # Loadable.search('detroit-*.rb') 36 | # 37 | # Note that "esoteric" wedges might return a symbolic identifier rather 38 | # than an actual file path. 39 | # 40 | # TODO: Handle default ruby extensions in search. 41 | def self.search(glob, options={}, &criteria) 42 | matches = [] 43 | $LOADERS.each do |wedge| 44 | wedge.each do |path| 45 | next unless criteria.call(path) if criteria 46 | matches << path if File.fnmatch?(glob, path.to_s) # TODO: add `options[:flags].to_i` ? 47 | end 48 | end 49 | matches 50 | end 51 | 52 | # Vendor location. 53 | # 54 | def self.vendor(*directory) 55 | $LOADERS.unshift(VendorLoader.new(*directory)) 56 | end 57 | 58 | # Add a loader to the $LOADERS global variable. 59 | # 60 | def self.register(loader) 61 | $LOADERS.unshift(loader) 62 | end 63 | 64 | end 65 | -------------------------------------------------------------------------------- /lib/loadable/loaders/original_loader.rb: -------------------------------------------------------------------------------- 1 | require 'loadable/mixin' 2 | require 'loadable/core_ext/rubygems' 3 | 4 | module Loadable 5 | 6 | # The original loader is simply an encpsulation of the Ruby's 7 | # built-in #require and #load functionality. This load wedge is 8 | # thus the first placed of the $LOADER list and the final 9 | # fallback if no other loader succeeds. 10 | # 11 | class OriginalLoader 12 | 13 | include Loadable 14 | 15 | alias_method :original_load, :load 16 | alias_method :original_require, :require 17 | 18 | # 19 | def call(fname, options={}) 20 | if options[:load] 21 | original_load(fname, options[:wrap]) 22 | else 23 | original_require(fname) 24 | end 25 | end 26 | 27 | # Iterate over each requirable file. Since RubyGems has become 28 | # a standard part of Ruby as of 1.9, this includes active and latest 29 | # versions of inactive gems. 30 | # 31 | # NOTE: in older versions of RubyGems, activated gem versions are in 32 | # the $LOAD_PATH too. This may cause some duplicate iterations. 33 | # 34 | def each(options={}, &block) 35 | each_loadpath(&block) 36 | each_rubygems(&block) 37 | self 38 | end 39 | 40 | private 41 | 42 | # 43 | def each_loadpath(options={}, &block) 44 | $LOAD_PATH.uniq.each do |path| 45 | path = File.expand_path(path) 46 | traverse(path, &block) 47 | end 48 | end 49 | 50 | # 51 | def each_rubygems(options={}, &block) 52 | return unless defined?(::Gem) 53 | Gem::Specification.current_specs.each do |spec| 54 | spec.require_paths.each do |require_path| 55 | path = File.join(spec.full_gem_path, require_path) 56 | traverse(path, &block) 57 | end 58 | end 59 | end 60 | 61 | end 62 | 63 | end 64 | -------------------------------------------------------------------------------- /work/reference/vendor.rb: -------------------------------------------------------------------------------- 1 | 2 | class VendorLoader < Loader 3 | 4 | # Add vendored projects to load path. For example: 5 | # 6 | # $LOAD_PATH.vendor(project_root_directoy, 'vendor') 7 | # 8 | # Then any projects in the vendor directory will be accessible 9 | # via require and load. This method looks for a .gemspec or .ruby 10 | # file in the project to determine it's proper load paths, baring 11 | # either of these it falls back to using `lib/`. 12 | # 13 | def self.vendor(*directory) 14 | raise ArgumentError if directory.empty? 15 | 16 | opt = Hash === directory.last ? directory.pop : {} 17 | dir = File.expand_path(File.join(*directory)) 18 | 19 | return $:.unshift(dir) if opt[:direct] 20 | 21 | gemspecs = Dir.glob(File.join(dir, '*/{*,}.gemspec')) 22 | dotrubys = Dir.glob(File.join(dir, '*/.ruby')) 23 | libpaths = Dir.glob(File.join(dir, '*/lib')) 24 | 25 | # TODO: if no paths fallback to direct path --good idea? 26 | return $:.unshift(dir) if gemspecs.empty? && dotrubys.empty? && libpaths.empty? 27 | 28 | # TODO: more efficient means of prevent duplicate paths? 29 | index = [] 30 | 31 | dotrubys.each do |path| 32 | root = File.dirname(path) 33 | next if index.include?(root) 34 | index << root 35 | 36 | spec = YAML.load(path) 37 | spec['load_path'].each do |lp| 38 | $:.unshift(File.join(root, rp)) 39 | end 40 | end 41 | 42 | if defined?(::Gem) # only if rubygems is in use 43 | gemspecs.each do |path| 44 | root = File.dirname(path) 45 | next if index.include?(root) 46 | index << root 47 | 48 | # TODO: handle YAML gemspecs 49 | spec = Gem::Specification.load(path) 50 | spec.require_paths.each do |rp| 51 | $:.unshift(File.join(root, rp)) 52 | end 53 | end 54 | end 55 | 56 | libpaths.each do |path| 57 | root = File.dirname(path) 58 | next if index.include?(root) 59 | index << root 60 | 61 | $:.unshift(path) 62 | end 63 | 64 | return $: 65 | end 66 | 67 | end 68 | -------------------------------------------------------------------------------- /lib/loadable/core_ext/rubygems.rb: -------------------------------------------------------------------------------- 1 | module Gem 2 | 3 | # Search RubyGems for matching paths in current gem versions. 4 | def self.search(match, options={}) 5 | return unless defined?(::Gem) 6 | matches = [] 7 | Gem::Specification.current_specs.each do |spec| 8 | glob = File.join(spec.lib_dirs_glob, match) 9 | list = Dir[glob] #.map{ |f| f.untaint } 10 | list = list.map{ |d| d.chomp('/') } 11 | matches.concat(list) 12 | end 13 | matches 14 | end 15 | 16 | class Specification 17 | # Return a list of active specs or latest version of spec if not active. 18 | def self.current_specs 19 | named = Hash.new{|h,k| h[k] = [] } 20 | each{ |spec| named[spec.name] << spec } 21 | list = [] 22 | named.each do |name, vers| 23 | if spec = vers.find{ |s| s.activated? } 24 | list << spec 25 | else 26 | spec = vers.max{ |a,b| a.version <=> b.version } 27 | list << spec 28 | end 29 | end 30 | return list 31 | end 32 | 33 | # Return full path of requireable file path given relative path. 34 | def find_requirable_file(file) 35 | root = full_gem_path 36 | 37 | require_paths.each do |lib| 38 | base = "#{root}/#{lib}/#{file}" 39 | Gem.suffixes.each do |suf| 40 | path = "#{base}#{suf}" 41 | return path if File.file? path 42 | end 43 | end 44 | 45 | return nil 46 | end 47 | end 48 | 49 | end 50 | 51 | 52 | 53 | =begin 54 | class GemPathSearcher 55 | # Return a list of matching files among active or latest gems. 56 | def current_files(glob) 57 | matches = {} 58 | gemspecs = init_gemspecs 59 | 60 | # loaded specs 61 | gemspecs.each do |spec| 62 | next unless spec.loaded? 63 | next if matches.key?(spec.name) 64 | files = matching_files(spec, glob) 65 | matches[spec.name] = files 66 | end 67 | 68 | # latest specs 69 | gemspecs.each do |spec| 70 | next if matches.key?(spec.name) 71 | files = matching_files(spec, glob) 72 | matches[spec.name] = files 73 | end 74 | 75 | matches.values.flatten.uniq 76 | end 77 | end 78 | =end 79 | 80 | -------------------------------------------------------------------------------- /lib/loadable/loaders/ruby_loader.rb: -------------------------------------------------------------------------------- 1 | # TODO: Maybe add support more refined selection of locations. 2 | 3 | # TODO: Add new vendor locations. 4 | 5 | require 'rbconfig' 6 | require 'loadable/mixin' 7 | 8 | module Loadable 9 | 10 | # The Ruby Wedge allows standaard libray scripts to be loaded in a isolated 11 | # fashion. 12 | # 13 | # require 'optparse', :from=>'ruby' 14 | # 15 | # The example would load optparse standard library regardless of Gem installed 16 | # that might have a script by the same name. 17 | 18 | class RubyLoader 19 | 20 | include Loadable 21 | 22 | # Notice that rubylibdir takes precendence. 23 | LOCATIONS = ::RbConfig::CONFIG.values_at( 24 | 'rubylibdir', 'archdir', 'sitelibdir', 'sitearchdir' 25 | ) 26 | 27 | # Load the the first standard Ruby library matching +file+. 28 | # 29 | # Returns +nil+ if this loader is not applicable, which is 30 | # determined by the use of `:from => 'ruby'` option. 31 | # 32 | def call(file, options={}) 33 | return unless apply?(file, options) 34 | 35 | LOCATIONS.each do |site| 36 | if path = lookup(site, file, options) 37 | return super(path, options) 38 | end 39 | end 40 | 41 | raise_load_error(file) 42 | end 43 | 44 | # 45 | def each(options={}, &block) 46 | LOCATIONS.each do |path| 47 | #path = File.expand_path(path) 48 | traverse(path, &block) 49 | end 50 | end 51 | 52 | # The `#apply?` methods determines if the load wedge is applicable. 53 | # 54 | # Returns +true+ if this loader is not applicable, which is 55 | # determined by the use of `:from => 'ruby'` option, otherwise `false`. 56 | # 57 | def apply?(fname, options={}) 58 | options[:from].to_s == 'ruby' 59 | end 60 | 61 | 62 | private 63 | 64 | # Retun first matching file from Ruby's standard library locations. 65 | # 66 | # Returns +nil+ if this loader is not applicable. 67 | # 68 | def find(glob, options={}) 69 | return unless apply?(file, options) 70 | 71 | LOCATIONS.each do |site| 72 | path = lookup(site, file, options) 73 | return path if path 74 | end 75 | end 76 | 77 | end 78 | 79 | end 80 | 81 | # Copyright 2010 Thomas Sawyer, Rubyworks (BSD-2-Clause license) 82 | -------------------------------------------------------------------------------- /work/reference/search.rb: -------------------------------------------------------------------------------- 1 | require 'rbconfig/core_ext/rubygems' if defined?(::Gem) 2 | 3 | module Free 4 | 5 | # Find library files (e.g. plugins), searching through standard $LOAD_PATH, 6 | # as well as RubyGems and Roll packages if these load systems are being used. 7 | # 8 | # RbConfig.library_search('rdoc/discover.rb') 9 | # 10 | def self.search(match, options={}) 11 | list = [] 12 | search_locators.each do |locator| 13 | list.concat(locator.call(match,options) || []) 14 | end 15 | list.uniq 16 | end 17 | 18 | # List of search procedures, in order of priority. 19 | def self.search_locators 20 | @search_locators ||= [] 21 | end 22 | 23 | # Search Roll system for current or latest libraries. 24 | # 25 | # This only searches actived libraries, or the most recent version 26 | # of any given library. 27 | # 28 | def self.search_rbledger(glob, options={}) 29 | return unless defined?(::Roll) 30 | ::Library.find_files(glob, options) 31 | end 32 | 33 | # Search standard $LOAD_PATH. 34 | # 35 | # NOTE: in older versions of RubyGems, activated gem versions are in here too. 36 | def self.search_loadpath(match, options={}) 37 | matches = [] 38 | $LOAD_PATH.uniq.each do |path| 39 | path = File.expand_path(path) 40 | list = Dir.glob(File.join(path, match)) 41 | list = list.map{ |d| d.chomp('/') } 42 | matches.concat(list) 43 | end 44 | matches 45 | end 46 | 47 | # Search gems for files. 48 | # 49 | def self.search_rubygems(glob, options={}) 50 | return unless defined?(::Gem) 51 | ::Gem.search(glob) 52 | end 53 | 54 | # TODO: proper order? 55 | search_locators << method(:search_rbledger) if defined?(::Roll) 56 | search_locators << method(:search_loadpath) 57 | search_locators << method(:search_rubygems) if defined?(::Gem) 58 | 59 | ## This is the same as +up+ but searches within the standard +plugins/+ 60 | ## directory. Using the standard +plugins+ directory makes it easier for 61 | ## developers to locate plugins, and helps prevent file name clashes with 62 | ## regular library scripts. For example, if your project is called 'milkdud' 63 | ## and it supports plugin scripts, they would reside in the a project's 64 | ## lib/plugins/milkdud/ directory. 65 | ## 66 | ## Look.up_plugins('syckle/*') 67 | ## 68 | #def self.up_plugins(match, options={}) 69 | # up(File.join('plugins',match), options) 70 | #end 71 | 72 | end 73 | -------------------------------------------------------------------------------- /lib/loadable/loaders/gem_loader.rb: -------------------------------------------------------------------------------- 1 | # TODO: Support colon notation again ? 2 | 3 | # TODO: If :gem AND :from options are given, perhaps try both 4 | # instead of either-or? 5 | 6 | require 'loadable/mixin' 7 | require 'loadable/core_ext/rubygems' 8 | 9 | module Loadable 10 | 11 | # The Gem Wedge allows gem files to be loaded in a isolated fashion. 12 | # 13 | # require 'tracepoint', :from=>'tracepoint' 14 | # 15 | # The example would load the tracepoint file from the tracepoint gem. 16 | # It will also fallback to the RubyLoader if 'tracepoint' is not found 17 | # among available gems. Loading can be limited to gems only by using 18 | # the `:gem` options instead. 19 | # 20 | # require 'tracepoint', :gem=>'tracepoint' 21 | # 22 | # Now, if the `tracepoint` script is not found among availabe gems, 23 | # a LoadError will be raised. 24 | # 25 | class GemLoader 26 | 27 | include Loadable 28 | 29 | # Load script from specific gem. 30 | # 31 | # Returns +nil+ if this loader is not applicable, which is determined 32 | # by the use of `:gem => 'foo'` or `:from => 'foo'` options. 33 | # 34 | def call(fname, options={}) 35 | return unless apply?(fname, options) 36 | 37 | gem_name = options[:gem] || options[:from] 38 | 39 | if vers = options[:version] 40 | spec = ::Gem::Specification.find_by_name(gem_name, vers) 41 | else 42 | spec = ::Gem::Specification.find_by_name(gem_name) 43 | end 44 | 45 | if options[:gem] 46 | raise_load_error(fname) unless spec 47 | else 48 | return unless spec 49 | end 50 | 51 | file = spec.find_requirable_file(fname) 52 | file = spec.find_requirable_file(File.join(gem_name, fname)) unless file 53 | 54 | if file 55 | super(file, options) 56 | else 57 | raise_load_error(fname) 58 | end 59 | end 60 | 61 | # Iterate over each loadable file in specified gem. 62 | # 63 | def each(options={}, &block) 64 | return unless apply?(nil, options) 65 | 66 | gem_name = (options[:gem] || options[:from]).to_s 67 | 68 | if vers = options[:version] 69 | spec = ::Gem::Specification.find_by_name(gem_name, vers) 70 | else 71 | spec = ::Gem::Specification.find_by_name(gem_name) 72 | end 73 | 74 | return unless spec 75 | 76 | #spec.activate 77 | 78 | spec.require_paths.each do |path| 79 | traverse(File.join(spec.full_gem_path, path), &block) 80 | end 81 | end 82 | 83 | # Determine if this load wedge is applicable given the +fname+ 84 | # and +options+. 85 | # 86 | def apply?(fname, options={}) 87 | return true if options[:gem] 88 | return true if options[:from] && ( 89 | ::Gem::Specification.find{ |s| options[:from].to_s == s.name } 90 | ) 91 | return false 92 | end 93 | 94 | end 95 | 96 | end 97 | 98 | # Copyright 2010 Thomas Sawyer, Rubyworks (BSD-2-Clause license) 99 | -------------------------------------------------------------------------------- /lib/loadable/loaders/vendor_loader.rb: -------------------------------------------------------------------------------- 1 | # TODO: Support `:from` option. 2 | 3 | require 'loadable/mixin' 4 | 5 | module Loadable 6 | 7 | # Add vendored projects to load path. For example: 8 | # 9 | # Loadable.vendor(project_root_directoy, 'vendor') 10 | # 11 | # Then any projects in the vendor directory will be accessible 12 | # via require and load. This method looks for a .gemspec or .ruby 13 | # file in the project to determine it's proper load paths, baring 14 | # either of these it falls back to using `lib/`. 15 | 16 | class VendorLoader 17 | 18 | include Loadable 19 | 20 | # 21 | def initialize(*directory) 22 | raise ArgumentError if directory.empty? 23 | 24 | @_yaml_loaded ||= !(require 'yaml').nil? 25 | 26 | settings = (Hash === directory.last ? directory.pop : {}) 27 | directory = File.expand_path(File.join(*directory)) 28 | 29 | @load_path = [] 30 | 31 | if settings[:direct] 32 | @load_path.concat(Dir.glob(directory)) 33 | else 34 | Dir.glob(directory).each do |dir| 35 | next unless File.directory?(dir) 36 | build_loadpath(dir) 37 | end 38 | end 39 | 40 | if @load_path.empty? 41 | # TODO: if load_path empty should we fallback to direct path ? 42 | end 43 | end 44 | 45 | # Load script from vendored locations. 46 | # 47 | def call(fname, options={}) 48 | @load_path.each do |path| 49 | file = lookup(path, fname, options) 50 | return super(file, options) if file 51 | end 52 | raise_load_error(fname) 53 | end 54 | 55 | # Iterate over each loadable file in vendored locations. 56 | # 57 | def each(options={}, &block) 58 | @load_path.uniq.each do |path| 59 | path = File.expand_path(path) 60 | traverse(path, &block) 61 | end 62 | end 63 | 64 | private 65 | 66 | # Build up load_path given a directory to check. Looks for a `.ruby` 67 | # or `.gemspec` file to get project's local load paths, otherwise if 68 | # looks for a `lib` directory. 69 | # 70 | def build_loadpath(dir) 71 | if dotruby_file = Dir.glob(File.join(dir, '.ruby')).first 72 | @load_path.concat(loadpath_dotruby(dotruby_file, dir)) 73 | 74 | elsif defined?(::Gem) && gemspec = Dir.glob(File.join(dir, '{*,}.gemspec')).first 75 | @load_path.concat(loadpath_gemspec(gemspec_file, dir)) 76 | 77 | elsif path = Dir.glob(File.join(dir, 'lib')).first 78 | @load_path << path 79 | 80 | else 81 | # TODO: is this an error, just ignore, or add dir directly ? 82 | end 83 | 84 | return @load_path 85 | end 86 | 87 | # Build the load_path given a '.ruby` file. 88 | # 89 | def loadpath_dotruby(dotruby_file, dir) 90 | data = YAML.load(dotruby_file) 91 | path = data['load_path'] || ['lib'] 92 | path.map do |lp| 93 | File.join(dir, lp) 94 | end 95 | end 96 | 97 | # Build the load_path given a '.gemspec` file. 98 | # 99 | def loadpath_gemspec(gemspec_file, dir) 100 | # TODO: handle YAML gemspecs 101 | spec = Gem::Specification.load(gemspec_file) 102 | spec.require_paths.map do |rp| 103 | File.join(dir, rp) 104 | end 105 | end 106 | 107 | end 108 | 109 | end 110 | -------------------------------------------------------------------------------- /lib/loadable/mixin.rb: -------------------------------------------------------------------------------- 1 | # Loadable is used in two ways. 2 | 3 | # First, it can be used as a mixin for loaders (also called load wedges). Loaders 4 | # are used to safely inject new import logic into Ruby's require/load system. 5 | # 6 | # Secondly, Loadable's class methods are used to override Ruby's built-in 7 | # require and load Kernel methods. 8 | # 9 | # Active load wedges are stored in `$LOADERS` global variable. 10 | # 11 | # IMPORTANT: This must be loaded before `loadable/kernel.rb`. 12 | 13 | module Loadable 14 | 15 | # TODO: Some extensions are platform specific --only add the ones needed 16 | # for the current platform. 17 | 18 | # Script extensions recognized by Ruby (MRI and variants). 19 | RB_EXTS = ['.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar'] #, ''] 20 | 21 | alias :require :require 22 | alias :load :load 23 | 24 | # 25 | def call(fname, options={}) 26 | if options[:load] 27 | load(fname, options[:wrap]) 28 | else 29 | require(fname) 30 | end 31 | end 32 | 33 | # A load wedge should provide a means for iterating over all requirable 34 | # files that its `#call` method could load. 35 | # 36 | # If a load wedge is "esoteric", in that it doesn't actually load 37 | # a file, then it's `#each` method can iterate over a list of suitable 38 | # symbolic identifiers, or if otherwise necessary nothing at all. But 39 | # be sure to document this prominantly!!! 40 | # 41 | def each(options={}, &block) 42 | end 43 | 44 | # Name of wedge. By default it is simply the class name. 45 | def name 46 | self.class.name 47 | end 48 | 49 | private 50 | 51 | # Given a base-path, and a path relative to it determine if a matching 52 | # file exists. Unless +:load+ option is +true+, this will check for each 53 | # viable Ruby suffix. If a match is found the full path to the file 54 | # is returned, otherwise +nil+. 55 | 56 | def lookup(base_path, relative_path, options={}) 57 | exts = default_file_extensions 58 | if options[:load] or exts.include?(File.extname(relative_path)) 59 | abspath = File.join(base_path, relative_path) 60 | File.exist?(abspath) ? abspath : nil 61 | else 62 | exts.each do |ext| 63 | abspath = File.join(base_path, relative_path + ext) 64 | return abspath if File.exist?(abspath) 65 | end 66 | nil 67 | end 68 | end 69 | 70 | # This helper method provides a fast way to traverse a directory 71 | # recursively iteratating over each file. 72 | 73 | def traverse(dir, base=dir, &block) 74 | return unless File.directory?(dir) 75 | Dir.new(dir).each do |file| 76 | next if file == '.' or file == '..' 77 | path = File.join(dir, file) 78 | if File.directory?(path) 79 | traverse(path, base, &block) 80 | else 81 | block.call(path.sub(base+'/','')) 82 | end 83 | end 84 | end 85 | 86 | # This method is used by `#lookup` to handle defualt file extensions. 87 | # By default it returns the value of the `RB_EXTS` constant. 88 | 89 | def default_file_extensions 90 | RB_EXTS 91 | end 92 | 93 | # Raise LoadError with an error message patterned after Ruby's standard 94 | # error message when a script can't be required or loaded. 95 | 96 | def raise_load_error(fname) 97 | raise LoadError, "no such file to load -- #{fname}" 98 | end 99 | 100 | end 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Website](http://github.com/rubyworks/loadable) / 2 | [Report Issue](http://github.com/rubyworks/loadable/issues) / 3 | [Source Code](http://github.com/rubyworks/loadable) 4 | ( [![Build Status](https://secure.travis-ci.org/rubyworks/loadable.png)](http://travis-ci.org/rubyworks/loadable) ) 5 | 6 | # Loadable 7 | 8 | *Safely Customize Ruby's Load System* 9 | 10 |
11 | 12 | ## 1 Description 13 | 14 | The Loadable gem provides a robust and convenient means of augmenting 15 | Ruby's load system, namely the `load` and `require` methods. Rather than 16 | alias and override these methods, Loadable keeps a list of load hooks 17 | (also called *load wedges*) that control the routing of require and load calls. 18 | 19 | In addition, the Loadable gem includes two pre-made load hooks that can be 20 | used to prevent name clashes between Ruby's standard library and gem packages 21 | (see INFRACTIONS.md for more on this). There is also a load hook for 22 | developers to make vendored sub-projects loadable. 23 | 24 | 25 | ## 2 Features 26 | 27 | * Safely augment Ruby's load system. 28 | * Prevent library name clashes. 29 | * Search load locations. 30 | 31 | 32 | ## 3 Usage 33 | 34 | ### 3.1 Installation 35 | 36 | Installing via RubyGems follows the usual pattern. 37 | 38 | gem install loadable 39 | 40 | To automatically load both the Gem and Ruby hooks, and the entire Loadable 41 | system, add `loadable` to your RUBYOPT environment variable. 42 | 43 | export RUBYOPT="-rloadable" 44 | 45 | Place this in your shell's configuration file, such as `~/.bashrc`. For csh 46 | syntax (e.g. in `~/.cshrc`) use: 47 | 48 | setenv RUBYOPT "-rloadable" 49 | 50 | If you do not want the default setup you can `require 'loadable/system'` instead. 51 | This will load in Loadable system, but only add an `OriginalLoader` to the 52 | `$LOADERS` list, leaving off the Ruby and Gem loaders. 53 | 54 | ### 3.2 Custom Loaders 55 | 56 | Loadable was written initially to provide the specific capability of loading 57 | Ruby standard libraries without potential interference from libraries 58 | installed via RubyGems (see INFRACTIONS.md). The code ultimately evolved 59 | into a more generic tool, useful for writing any kind of plug-in load 60 | router. 61 | 62 | The code for the Ruby hook serves as a good example of writing a load hook. 63 | (Note this is leaves out a few details of the real class for simplicity's sake.) 64 | 65 | require 'rbconfig' 66 | require 'loadable/mixin' 67 | 68 | class Loadable::RubyLoader 69 | include Loadable 70 | 71 | LOCATIONS = ::RbConfig::CONFIG.values_at( 72 | 'rubylibdir', 'archdir', 'sitelibdir', 'sitearchdir' 73 | ) 74 | 75 | def call(fname, options={}) 76 | return unless options[:from].to_s == 'ruby' 77 | LOCATIONS.each do |loadpath| 78 | if path = lookup(loadpath, fname, options) 79 | return super(path, options) 80 | end 81 | end 82 | raise_load_error(fname) 83 | end 84 | 85 | def each(options={}, &block) 86 | LOCATIONS.each do |loadpath| 87 | traverse(loadpath, &block) 88 | end 89 | end 90 | end 91 | 92 | To put this loader into action we simply need to register it with the Loadable 93 | domain. 94 | 95 | Loadable.register(Loadable::RubyLoader.new) 96 | 97 | Under the hood, this simply appends the instance to the `$LOADERS` global variable. 98 | 99 | Loaders, also called load hooks or wedges, are easy to write as their interface 100 | is very simple. Any object that responds to #call, taking parameters of 101 | (fname, options={}), can be used as a load hook. A load hook 102 | should also support `#each(options={}, &block)` which is used to iterate over 103 | all requirable files a loader supports. 104 | 105 | The `Loadable` mixin is just a convenience module that makes writing loaders 106 | a bit easier. Load hooks can be written without it, however the mixin 107 | provides a few methods that are often useful to any load hook. An example is 108 | the `lookup` method used in the above example, which will search a 109 | load path in accordance with the Ruby's built-in require and load lookup 110 | procedures, i.e. automatically trying default extensions like `.rb`. 111 | 112 | You might wonder how the single method, `#call`, handles both load and require 113 | operations. The secret is in the `options` hash. If options[:load] 114 | resolves to true, then it is a *load* operation, otherwise it is a *require* 115 | operation. The `$LOADERS` global variable is iterated over in order. 116 | When `#load` or `#require` is called each hook is tried in turn. The return 117 | value of `#call` controls how this loop proceeds. If the return value is `true` 118 | then the load was successful, and the loop can break. If it is `false` it means 119 | the loading has already been handled and the loop can also break. But if the 120 | return value is `nil`, it means the hook does not apply and the loop should 121 | continue. If all hooks have been tried and all have returned `nil` then it 122 | falls back to the original `#load` and `#require` calls, via an instance of 123 | `OriginalLoader` which should always be the last loader in the `$LOADERS` list. 124 | 125 | 126 | ## 4 Built-in Loaders 127 | 128 | The Loadable gem provides three special loaders out-of-the-box: the `RubyLoader`, 129 | the `GemLoader` and the `VendorLoader`. The first two are probably not exactly 130 | what you think they are, going just by their names, so keep reading... 131 | 132 | ### 4.1 RubyLoader 133 | 134 | The Ruby hook makes it possible to load a Ruby standard library without 135 | interference from installed gems or other package systems. It does this by 136 | checking for a `:from` option passed to the require or load methods. 137 | 138 | require 'ostruct', :from=>'ruby' 139 | 140 | This will load the `ostruct.rb` script from the Ruby standard library regardless 141 | of whether someone else dropped an `ostruct.rb` file in their project's `lib/` 142 | directory without understanding the potential consequences. 143 | 144 | ### 4.2 GemLoader 145 | 146 | The Gem hook is similar to the Ruby hook, in that it isolates the loading 147 | of a gem's files from other gems. 148 | 149 | gem 'facets', '~>2.8' 150 | 151 | require 'string/margin', :from=>'facets' 152 | 153 | With this we can be sure that 'facets/string/margin' was loaded from the Facets 154 | library regardless of whether some other gem has a 'facets/string/margin' file 155 | in its `lib/` directory. If no gem has this file, it will fallback to the 156 | remaining loaders. However, if we use the `:gem` options instead, it will 157 | raise a load error. 158 | 159 | require 'string/does_not_exit', :gem=>'facets' 160 | 161 | The Gem hook also supports version constraints, so you do not have to use 162 | `gem()` method for one-off requires from a given gem. 163 | 164 | require 'string/margin', :from=>'facets', :version=>'~>2.8' 165 | 166 | ### 4.3 VendorLoader 167 | 168 | The Vendor hook is used to add vendored projects to the load system. 169 | This is especially useful for development. Vendored projects can be added 170 | in two ways, by registering an instance of VendorLoader, e.g. 171 | 172 | Loadable.register Loadable::VendorLoader.new('vendor/*') 173 | 174 | Or using the dedicated `Loadable.vendor(*dir)` method that Loadable provides 175 | to make this more convenient. 176 | 177 | Loadable.vendor('vendor/*') 178 | 179 | 180 | ## 5 Development 181 | 182 | Source code for Loadable is hosted by [GitHub](http://github.com/rubyworks/loadable). 183 | 184 | If you come across any issues, we encourage you to fork the repository and 185 | submit a pull request with the fix. When submitting a pull request, it is best 186 | if the changes are organized into a new topic branch. 187 | 188 | If you don't have time to code up patches yourself, please do not hesitate to 189 | simply report the issue on the [issue tracker](http://github.com/rubyworks/loadable/issues). 190 | 191 | 192 | ## 6 Copyrights 193 | 194 | Loadable if copyrighted open source software. 195 | 196 | Copyright (c) 2010 Rubyworks 197 | 198 | Load is distributed under the terms of the **BSD-2-Clause** license. 199 | 200 | See LICENSE.txt file for details. 201 | -------------------------------------------------------------------------------- /.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | require 'pathname' 5 | 6 | module Indexer 7 | 8 | # Convert index data into a gemspec. 9 | # 10 | # Notes: 11 | # * Assumes all executables are in bin/. 12 | # * Does not yet handle default_executable setting. 13 | # * Does not yet handle platform setting. 14 | # * Does not yet handle required_ruby_version. 15 | # * Support for rdoc entries is weak. 16 | # 17 | class GemspecExporter 18 | 19 | # File globs to include in package --unless a manifest file exists. 20 | FILES = ".index .yardopts alt bin data demo ext features lib man spec test try* [A-Z]*.*" unless defined?(FILES) 21 | 22 | # File globs to omit from FILES. 23 | OMIT = "Config.rb" unless defined?(OMIT) 24 | 25 | # Standard file patterns. 26 | PATTERNS = { 27 | :root => '{.index,Gemfile}', 28 | :bin => 'bin/*', 29 | :lib => 'lib/{**/}*', #.rb', 30 | :ext => 'ext/{**/}extconf.rb', 31 | :doc => '*.{txt,rdoc,md,markdown,tt,textile}', 32 | :test => '{test,spec}/{**/}*.rb' 33 | } unless defined?(PATTERNS) 34 | 35 | # For which revision of indexer spec is this converter intended? 36 | REVISION = 2013 unless defined?(REVISION) 37 | 38 | # 39 | def self.gemspec 40 | new.to_gemspec 41 | end 42 | 43 | # 44 | attr :metadata 45 | 46 | # 47 | def initialize(metadata=nil) 48 | @root_check = false 49 | 50 | if metadata 51 | root_dir = metadata.delete(:root) 52 | if root_dir 53 | @root = root_dir 54 | @root_check = true 55 | end 56 | metadata = nil if metadata.empty? 57 | end 58 | 59 | @metadata = metadata || YAML.load_file(root + '.index') 60 | 61 | if @metadata['revision'].to_i != REVISION 62 | warn "This gemspec exporter was not designed for this revision of index metadata." 63 | end 64 | end 65 | 66 | # 67 | def has_root? 68 | root ? true : false 69 | end 70 | 71 | # 72 | def root 73 | return @root if @root || @root_check 74 | @root_check = true 75 | @root = find_root 76 | end 77 | 78 | # 79 | def manifest 80 | return nil unless root 81 | @manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first 82 | end 83 | 84 | # 85 | def scm 86 | return nil unless root 87 | @scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym 88 | end 89 | 90 | # 91 | def files 92 | return [] unless root 93 | @files ||= \ 94 | if manifest 95 | File.readlines(manifest). 96 | map{ |line| line.strip }. 97 | reject{ |line| line.empty? || line[0,1] == '#' } 98 | else 99 | list = [] 100 | Dir.chdir(root) do 101 | FILES.split(/\s+/).each do |pattern| 102 | list.concat(glob(pattern)) 103 | end 104 | OMIT.split(/\s+/).each do |pattern| 105 | list = list - glob(pattern) 106 | end 107 | end 108 | list 109 | end.select{ |path| File.file?(path) }.uniq 110 | end 111 | 112 | # 113 | def glob_files(pattern) 114 | return [] unless root 115 | Dir.chdir(root) do 116 | Dir.glob(pattern).select do |path| 117 | File.file?(path) && files.include?(path) 118 | end 119 | end 120 | end 121 | 122 | def patterns 123 | PATTERNS 124 | end 125 | 126 | def executables 127 | @executables ||= \ 128 | glob_files(patterns[:bin]).map do |path| 129 | File.basename(path) 130 | end 131 | end 132 | 133 | def extensions 134 | @extensions ||= \ 135 | glob_files(patterns[:ext]).map do |path| 136 | File.basename(path) 137 | end 138 | end 139 | 140 | def name 141 | metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') 142 | end 143 | 144 | def homepage 145 | page = ( 146 | metadata['resources'].find{ |r| r['type'] =~ /^home/i } || 147 | metadata['resources'].find{ |r| r['name'] =~ /^home/i } || 148 | metadata['resources'].find{ |r| r['name'] =~ /^web/i } 149 | ) 150 | page ? page['uri'] : false 151 | end 152 | 153 | def licenses 154 | metadata['copyrights'].map{ |c| c['license'] }.compact 155 | end 156 | 157 | def require_paths 158 | paths = metadata['paths'] || {} 159 | paths['load'] || ['lib'] 160 | end 161 | 162 | # 163 | # Convert to gemnspec. 164 | # 165 | def to_gemspec 166 | if has_root? 167 | Gem::Specification.new do |gemspec| 168 | to_gemspec_data(gemspec) 169 | to_gemspec_paths(gemspec) 170 | end 171 | else 172 | Gem::Specification.new do |gemspec| 173 | to_gemspec_data(gemspec) 174 | to_gemspec_paths(gemspec) 175 | end 176 | end 177 | end 178 | 179 | # 180 | # Convert pure data settings. 181 | # 182 | def to_gemspec_data(gemspec) 183 | gemspec.name = name 184 | gemspec.version = metadata['version'] 185 | gemspec.summary = metadata['summary'] 186 | gemspec.description = metadata['description'] 187 | 188 | metadata['authors'].each do |author| 189 | gemspec.authors << author['name'] 190 | 191 | if author.has_key?('email') 192 | if gemspec.email 193 | gemspec.email << author['email'] 194 | else 195 | gemspec.email = [author['email']] 196 | end 197 | end 198 | end 199 | 200 | gemspec.licenses = licenses 201 | 202 | requirements = metadata['requirements'] || [] 203 | requirements.each do |req| 204 | next if req['optional'] 205 | next if req['external'] 206 | 207 | name = req['name'] 208 | groups = req['groups'] || [] 209 | 210 | version = gemify_version(req['version']) 211 | 212 | if groups.empty? or groups.include?('runtime') 213 | # populate runtime dependencies 214 | if gemspec.respond_to?(:add_runtime_dependency) 215 | gemspec.add_runtime_dependency(name,*version) 216 | else 217 | gemspec.add_dependency(name,*version) 218 | end 219 | else 220 | # populate development dependencies 221 | if gemspec.respond_to?(:add_development_dependency) 222 | gemspec.add_development_dependency(name,*version) 223 | else 224 | gemspec.add_dependency(name,*version) 225 | end 226 | end 227 | end 228 | 229 | # convert external dependencies into gemspec requirements 230 | requirements.each do |req| 231 | next unless req['external'] 232 | gemspec.requirements << ("%s-%s" % req.values_at('name', 'version')) 233 | end 234 | 235 | gemspec.homepage = homepage 236 | gemspec.require_paths = require_paths 237 | gemspec.post_install_message = metadata['install_message'] 238 | end 239 | 240 | # 241 | # Set gemspec settings that require a root directory path. 242 | # 243 | def to_gemspec_paths(gemspec) 244 | gemspec.files = files 245 | gemspec.extensions = extensions 246 | gemspec.executables = executables 247 | 248 | if Gem::VERSION < '1.7.' 249 | gemspec.default_executable = gemspec.executables.first 250 | end 251 | 252 | gemspec.test_files = glob_files(patterns[:test]) 253 | 254 | unless gemspec.files.include?('.document') 255 | gemspec.extra_rdoc_files = glob_files(patterns[:doc]) 256 | end 257 | end 258 | 259 | # 260 | # Return a copy of this file. This is used to generate a local 261 | # .gemspec file that can automatically read the index file. 262 | # 263 | def self.source_code 264 | File.read(__FILE__) 265 | end 266 | 267 | private 268 | 269 | def find_root 270 | root_files = patterns[:root] 271 | if Dir.glob(root_files).first 272 | Pathname.new(Dir.pwd) 273 | elsif Dir.glob("../#{root_files}").first 274 | Pathname.new(Dir.pwd).parent 275 | else 276 | #raise "Can't find root of project containing `#{root_files}'." 277 | warn "Can't find root of project containing `#{root_files}'." 278 | nil 279 | end 280 | end 281 | 282 | def glob(pattern) 283 | if File.directory?(pattern) 284 | Dir.glob(File.join(pattern, '**', '*')) 285 | else 286 | Dir.glob(pattern) 287 | end 288 | end 289 | 290 | def gemify_version(version) 291 | case version 292 | when /^(.*?)\+$/ 293 | ">= #{$1}" 294 | when /^(.*?)\-$/ 295 | "< #{$1}" 296 | when /^(.*?)\~$/ 297 | "~> #{$1}" 298 | else 299 | version 300 | end 301 | end 302 | 303 | end 304 | 305 | end 306 | 307 | Indexer::GemspecExporter.gemspec -------------------------------------------------------------------------------- /INFRACTIONS.md: -------------------------------------------------------------------------------- 1 | # INFRACTIONS 2 | 3 | One of the rarely mentioned edge cases with the way in which RubyGems loads 4 | library files, and in fact the way Ruby's load system works in general, is 5 | that the _lib space_ is a free for all. Any library can drop any file into 6 | their package's loadpath (i.e. the lib/ directory) and potentially clobber 7 | a file of the same name in some one else's library. 8 | 9 | Here's an example irb session that demonstrate the issue. Here I already added 10 | a `matrix.rb` file, that does nothing but puts "HERE!", to the `cuts` 11 | gem and installed it. 12 | 13 | require 'rubygems' 14 | => true 15 | gem "cuts" 16 | => true 17 | require 'matrix' 18 | HERE! 19 | => true 20 | 21 | Now, a good gem citizen knows to put their scripts in a directory with 22 | the same name as their gem package, nonetheless you might be surprised to see 23 | how often this simple but important practice is violated. 24 | Consequently the order in which such gems are searched becomes of 25 | paramount importance --something that worked just fine on one machine can 26 | suddenly stop working on another for no obvious reason. 27 | 28 | 29 | ## ISOLATIONISTS 30 | 31 | It is also worth noting that the recent crop of gem isolation systems, such as 32 | Bundler and Isolate, while serving to reduce the likelihood of possible name 33 | clashes still do not fully remedy the issue. They merely reduce the number of 34 | gems that could cause the problem for any given dependent application. 35 | 36 | 37 | ## SOLUTION 38 | 39 | The Ruby and Gem wedges solves the issue entirely by allowing us to load files 40 | from a single gem and only that gem. It does so by adding a new valid syntax 41 | to Ruby's #load and #require methods. As an example, let's say we wanted to 42 | load the troff.rb script from the unroller library. 43 | 44 | require 'troff', :from => 'unroller' 45 | 46 | The colon is used to separate the gem name from the rest of the pathname. 47 | With this we can be 100% certain that the troff.rb file was required 48 | from the unroller gem and not a 'troff.rb' file from any other 49 | gem that might have created a script by the same name. 50 | 51 | 52 | ## EXTENT OF THE ISSUE 53 | 54 | You might be suprised to find out how many libraries violate the best practice 55 | of putting all thier scripts in a subdirectory by the same name as the package. 56 | Just on my development system alone, which really has but a small number of 57 | gems installed, there are quite a few cases. 58 | 59 | ParseTree-2.2.0/lib/: 60 | 61 | composite_sexp_processor.rb 62 | parse_tree.rb 63 | sexp.rb 64 | sexp_processor.rb 65 | unified_ruby.rb 66 | unique.rb 67 | 68 | ParseTree-3.0.3/lib/: 69 | 70 | gauntlet_parsetree.rb 71 | parse_tree.rb 72 | parse_tree_extensions.rb 73 | unified_ruby.rb 74 | unique.rb 75 | 76 | RedCloth-4.1.9/lib/: 77 | 78 | case_sensitive_require 79 | redcloth 80 | redcloth.rb 81 | redcloth_scan.so 82 | 83 | RedCloth-4.2.2/lib/: 84 | 85 | case_sensitive_require 86 | redcloth 87 | redcloth.rb 88 | redcloth_scan.so 89 | tasks 90 | 91 | ZenTest-4.0.0/lib/: 92 | autotest 93 | autotest.rb 94 | focus.rb 95 | functional_test_matrix.rb 96 | multiruby.rb 97 | unit_diff.rb 98 | zentest.rb 99 | zentest_mapping.rb 100 | 101 | bossman-0.4.1/lib/: 102 | 103 | bossman 104 | bossman.rb 105 | extensions 106 | 107 | builder-2.1.2/lib/: 108 | 109 | blankslate.rb 110 | builder 111 | builder.rb 112 | 113 | chardet-0.9.0/lib/: 114 | 115 | Big5Freq.rb 116 | Big5Prober.rb 117 | CharDistributionAnalysis.rb 118 | CharSetGroupProber.rb 119 | CharSetProber.rb 120 | CodingStateMachine.rb 121 | ESCSM.rb 122 | EUCJPProber.rb 123 | EUCKRFreq.rb 124 | EUCKRProber.rb 125 | EUCTWFreq.rb 126 | EUCTWProber.rb 127 | EscCharSetProber.rb 128 | GB2312Freq.rb 129 | GB2312Prober.rb 130 | HebrewProber.rb 131 | JISFreq.rb 132 | JapaneseContextAnalysis.rb 133 | LangBulgarianModel.rb 134 | LangCyrillicModel.rb 135 | LangGreekModel.rb 136 | LangHebrewModel.rb 137 | LangHungarianModel.rb 138 | LangThaiModel.rb 139 | Latin1Prober.rb 140 | MBCSGroupProber.rb 141 | MBCSSM.rb 142 | MultiByteCharSetProber.rb 143 | SBCSGroupProber.rb 144 | SJISProber.rb 145 | SingleByteCharSetProber.rb 146 | UTF8Prober.rb 147 | UniversalDetector.rb 148 | 149 | eventmachine-0.12.10/lib/: 150 | 151 | em 152 | eventmachine.rb 153 | evma 154 | evma.rb 155 | fastfilereaderext.so 156 | jeventmachine.rb 157 | pr_eventmachine.rb 158 | rubyeventmachine.so 159 | 160 | hpricot-0.8.1/lib/: 161 | 162 | fast_xs.so 163 | hpricot 164 | hpricot.rb 165 | hpricot_scan.so 166 | 167 | html5-0.10.0/lib/: 168 | 169 | core_ext 170 | html5 171 | html5.rb 172 | 173 | http_router-0.2.5/lib/: 174 | 175 | ext 176 | http_router 177 | http_router.rb 178 | 179 | httpclient-2.1.5.2/lib/: 180 | 181 | http-access2 182 | http-access2.rb 183 | httpclient 184 | httpclient.rb 185 | tags 186 | 187 | linecache-0.43/lib/: 188 | 189 | linecache.rb 190 | trace_nums.so 191 | tracelines.rb 192 | 193 | liquid-2.0.0/lib/: 194 | 195 | extras 196 | liquid 197 | liquid.rb 198 | 199 | mail-2.2.5/lib/: 200 | 201 | VERSION 202 | mail 203 | mail.rb 204 | mail.rbc 205 | tasks 206 | 207 | maruku-0.5.9/lib/: 208 | 209 | maruku 210 | maruku.rb 211 | sort_prof.rb 212 | 213 | mechanize-0.9.3/lib/: 214 | 215 | mechanize.rb 216 | www 217 | 218 | memcache-client-1.7.8/lib/: 219 | 220 | continuum_native.rb 221 | memcache.rb 222 | memcache_util.rb 223 | 224 | mocha-0.9.8/lib/: 225 | 226 | mocha 227 | mocha.rb 228 | mocha_standalone.rb 229 | stubba.rb 230 | 231 | packr-3.1.0/lib/: 232 | 233 | packr 234 | packr.rb 235 | string.rb 236 | 237 | qed-2.3.0/lib/: 238 | 239 | qed 240 | qed.rb 241 | qedoc 242 | 243 | quality_extensions-1.1.6/lib/: 244 | 245 | Xfind_bug_test.rb 246 | quality_extensions 247 | quality_extensions.rb 248 | 249 | radiant-0.8.2/lib/: 250 | 251 | annotatable.rb 252 | autotest 253 | generators 254 | inheritable_class_attributes.rb 255 | local_time.rb 256 | login_system.rb 257 | method_observer.rb 258 | plugins 259 | radiant 260 | radiant.rb 261 | simpleton.rb 262 | task_support.rb 263 | tasks 264 | 265 | rails-2.3.5/lib/: 266 | 267 | code_statistics.rb 268 | commands 269 | commands.rb 270 | console_app.rb 271 | console_sandbox.rb 272 | console_with_helpers.rb 273 | dispatcher.rb 274 | fcgi_handler.rb 275 | initializer.rb 276 | performance_test_help.rb 277 | rails 278 | rails_generator 279 | rails_generator.rb 280 | railties_path.rb 281 | ruby_version_check.rb 282 | rubyprof_ext.rb 283 | source_annotation_extractor.rb 284 | tasks 285 | test_help.rb 286 | webrick_server.rb 287 | 288 | railties-3.0.0.beta/lib/: 289 | 290 | generators 291 | rails 292 | rails.rb 293 | 294 | ramaze-2010.01/lib/: 295 | 296 | proto 297 | ramaze 298 | ramaze.rb 299 | vendor 300 | 301 | rdiscount-1.3.5/lib/: 302 | 303 | markdown.rb 304 | rdiscount.rb 305 | rdiscount.so 306 | 307 | red-3.5.0/lib/: 308 | 309 | javascripts 310 | red 311 | red.rb 312 | 313 | red-4.1.7/lib/: 314 | 315 | red 316 | red.rb 317 | source 318 | 319 | rmagick-2.12.2/lib/: 320 | 321 | RMagick.rb 322 | RMagick2.so 323 | rvg 324 | 325 | ruby-prof-0.7.3/lib/: 326 | 327 | ruby-prof 328 | ruby-prof.rb 329 | ruby_prof.so 330 | unprof.rb 331 | 332 | ruby_parser-2.0.4/lib/: 333 | 334 | gauntlet_rubyparser.rb 335 | ruby_lexer.rb 336 | ruby_parser.rb 337 | ruby_parser.y 338 | ruby_parser_extras.rb 339 | 340 | rubygems-update-1.3.7/lib/: 341 | 342 | gauntlet_rubygems.rb 343 | rbconfig 344 | rubygems 345 | rubygems.rb 346 | ubygems.rb 347 | 348 | s3sync-1.2.5/lib/: 349 | 350 | HTTPStreaming.rb 351 | S3.rb 352 | S3_s3sync_mod.rb 353 | S3encoder.rb 354 | s3config.rb 355 | s3try.rb 356 | thread_generator.rb 357 | version.rb 358 | 359 | sexp_processor-3.0.1/lib/: 360 | 361 | composite_sexp_processor.rb 362 | sexp.rb 363 | sexp_processor.rb 364 | 365 | sexp_processor-3.0.3/lib/: 366 | 367 | composite_sexp_processor.rb 368 | sexp.rb 369 | sexp_processor.rb 370 | unique.rb 371 | 372 | slim_scrooge-1.0.5/lib/: 373 | 374 | callsite_hash.so 375 | slim_scrooge 376 | slim_scrooge.rb 377 | 378 | treetop-1.2.4/lib/: 379 | 380 | metagrammar.rb 381 | treetop 382 | treetop.rb 383 | 384 | unroller-1.0.0/lib/: 385 | 386 | troff.rb 387 | tron.rb 388 | unroller.rb 389 | 390 | xcb-0.0.1/lib/: 391 | 392 | directory_monitor.rb 393 | extreme_continuous_builder.rb 394 | notifiers.rb 395 | stacking_config.rb 396 | xcb_command.rb 397 | 398 | --------------------------------------------------------------------------------