From: timr Date: 2010-08-29T23:48:01+09:00 Subject: Re: require from a method On Aug 29, 3:25 am, Ammar Ali wrote: > Hello, > > Are there any gotchas in requiring files from within a method? It > seems to work, but I have a sinking feeling that I'm missing something > here. > > def require_relative(start, path) >   require File.expand_path( File.join( File.dirname(start), path ) ) > end > > require_relative __FILE__, %w{.. tests tester.rb} > > 1.upto(3) {|i| >   Tester.run i, "some", [3,6,9], :foo => :bar > > } > > Thanks, > Ammar Hi Ammar, I recently wrote a script to graph out (using a .dot file and Graphviz for visualization) what files load when a given gem is loaded. When I started looking at gems this way I realized that it was not uncommon for one file to require a second more than once. When I inspect in the code, there is usually two require statement within separate method calls. The logic is just as Robert explained, better efficiency by only loading something when you need it. I can give you a quick example from the yadis gem. requiring 'yadis' causes a chain reaction of file loading resulting in 73 files loading! One of those is a 'cgi.rb' file, which itself loads tempfile twice. Looking in cgi.rb shows the following def for the read_multipart method definition. Note the two require 'tempfile' statements in one method definition. Regards, Tim def read_multipart(boundary, content_length) params = Hash.new([]) boundary = "--" + boundary quoted_boundary = Regexp.quote(boundary, "n") buf = "" bufsize = 10 * 1024 boundary_end="" # start multipart/form-data stdinput.binmode if defined? stdinput.binmode boundary_size = boundary.size + EOL.size content_length -= boundary_size status = stdinput.read(boundary_size) if nil == status raise EOFError, "no content body" elsif boundary + EOL != status raise EOFError, "bad content body" end loop do head = nil if 10240 < content_length require "tempfile" body = Tempfile.new("CGI") else begin require "stringio" body = StringIO.new rescue LoadError require "tempfile" body = Tempfile.new("CGI") end end body.binmode if defined? body.binmode until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf) if (not head) and /#{EOL}#{EOL}/n.match(buf) buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do head = $1.dup "" end next end if head and ( (EOL + boundary + EOL).size < buf.size ) body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)] buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = "" end c = if bufsize < content_length stdinput.read(bufsize) else stdinput.read(content_length) end if c.nil? || c.empty? raise EOFError, "bad content body" end buf.concat(c) content_length -= c.size end buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary} ([\r\n]{1,2}|--)/n) do body.print $1 if "--" == $2 content_length = -1 end boundary_end = $2.dup "" end body.rewind /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^; \s]*))/ni.match(head) filename = ($1 or $2 or "") if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and (not /MSIE/ni.match(env_table['HTTP_USER_AGENT'])) filename = CGI::unescape(filename) end /Content-Type: ([^\s]*)/ni.match(head) content_type = ($1 or "") (class << body; self; end).class_eval do alias local_path path define_method(:original_filename) {filename.dup.taint} define_method(:content_type) {content_type.dup.taint} end /Content-Disposition:.* name="?([^\";\s]*)"?/ni.match(head) name = $1.dup if params.has_key?(name) params[name].push(body) else params[name] = [body] end break if buf.size == 0 break if content_length == -1 end raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/ params end # read_multipart