Forum: Ruby-core [ruby-trunk - Feature #7548][Open] Load and Require Callbacks

Posted by Thomas Sawyer (7rans)
on 2012-12-12 05:15
(Received via mailing list)
Issue #7548 has been reported by trans (Thomas Sawyer).

----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by Yorick Peterse (Guest)
on 2012-12-12 09:13
(Received via mailing list)
Is there a particular benefit of this over the current setup of require?
require() calls are not async so I don't really see the benefit of
adding callbacks to them.

You mentioned you wanted to use it for monitoring, perhaps you can
further explain that to clarify what you're trying to get at.

Yorick
Posted by Thomas Sawyer (7rans)
on 2012-12-13 16:43
(Received via mailing list)
Issue #7548 has been updated by trans (Thomas Sawyer).


=begin
There are have been times when I wanted to see what libraries were being 
loaded and in what order. Usually because of some esoteric bug, and 
trying to isolate what libraries are involved. In such a case I've had 
to manually override load and require, something like:

  class << Kernel
    alias :_require, :require
    def require(*args)
      $stderr.puts "require: %s" % [args.inspect]
      _require(*args)
    end

    alias :_load, :load
    def load(*args)
      $stderr.puts "load: %s" % [args.inspect]
      _load(*args)
    end
  end

  module Kernel
    def require(*args)
      Kernel.require(*args)
    end
    def load(*args)
      Kernel.load(*args)
    end
  end
=end

Notice we have to do both Kernel instance and singleton methods to be 
sure we catch all of them. These days we might also need to add 
(({#require_relative})) to that.

So the thought then is, if there were callbacks, it would be easier to 
do, simply:

  def required(*args)
    $stderr.puts "require: %s" % [args.inspect]
  end

  def loaded(*args)
    $stderr.puts "load: %s" % [args.inspect]
  end

Actually considering this a bit more, it would probably be even better 
just to have one callback method that passed options to designate which 
kind of loading took place. e.g.

  def loaded(file, opts)
    opts[:load] => true means #load was used/
                   false means #require was used

    opts[:relative] => true means #require_relative was used

    opts[:wrap] => the wrap argument for #load.
  end


----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34709

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by Thomas Sawyer (7rans)
on 2012-12-16 17:28
(Received via mailing list)
Issue #7548 has been updated by trans (Thomas Sawyer).


=begin
Some additional thoughts on this. It occurs to me that #prepend would 
make this a ((*little*)) easier now. One could do:

  module LoadCallbacks
    def load(*args)
      super(*args)
      $stderr.puts "load: %s" % [args.inspect]
    end

    def require(*args)
      super(*args)
      $stderr.puts "require: %s" % [args.inspect]
    end

    def require_relative(*args)
      super(*args)
      $stderr.puts "require: %s" % [args.inspect]
    end
  end

  module Kernel
    prepend LoadCallbacks
    class << self
      prepend LoadCallbacks
    end
  end

That's a little more elegant, but still feels a bit clunky.

I think what would really make the difference, and what would make this 
callback feature request effectively pointless, is if Ruby had a single 
method through which all loading was routed. So (({#load})), 
(({#require})) and (({#require_relative})) would all call this one 
method passing in options (i.e. named parameters) to tell it which kind 
of loading is to happen. That would be nice b/c it would allow us a 
single target method to see what was going on, instead of the current 
((*six*)) methods!
=end
----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34778

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by boris_stitnicky (Boris Stitnicky) (Guest)
on 2012-12-16 18:50
(Received via mailing list)
Issue #7548 has been updated by boris_stitnicky (Boris Stitnicky).


It seems that you are shaping and changing your suggestion with each new 
post,
so it is a bit hard to react. But the way I see it, your suggestions 
belong
somewhere to Std-lib 'debug'. Perhaps it might be possible to change 
stdlib
'debug' to support cherrypicking like ActiveSupport, so you could call
require 'debug/kernel/load_callbacks' if you want those callbacks, but 
not the
DEBUGGER itself. I am against adding this directly to the core.
----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34779

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by Thomas Sawyer (7rans)
on 2012-12-17 05:43
(Received via mailing list)
Issue #7548 has been updated by trans (Thomas Sawyer).


> It seems that you are shaping and changing your suggestion with each new post,
> so it is a bit hard to react.

Well, it's a process and discussion. I didn't really post this as a set 
in stone sort of request, which is why I presented it first with a 
question.

> But the way I see it, your suggestions belong somewhere to Std-lib 'debug'.
> Perhaps it might be possible to change stdlib 'debug' to support
> cherrypicking like ActiveSupport,

You mean "cherrypicking like Facets" right? ;)

> so you could call require 'debug/kernel/load_callbacks' if you want those 
callbacks,
> but not the DEBUGGER itself. I am against adding this directly to the core.

I think that's very reasonable. Ultimately I like my last suggestion, 
the one about having a central method that handles loading. That strikes 
me as a more solid design for Ruby in general. So I think I will make a 
more concrete proposal for that in another ticket. But short of that, 
then I agree. Having a standard "cherrypickable" debugging library for 
this would be the nicest approach.



----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34789

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by Thomas Sawyer (7rans)
on 2012-12-18 05:57
(Received via mailing list)
Issue #7548 has been updated by trans (Thomas Sawyer).


=begin
Ran into a little snag with implementation of this as a simple Ruby 
library. It is not possible to override (({#require_relative})) to add 
the callback b/c it is lexically scoped (is that the right term for 
this?). In other words, (({#require_relative})) uses the (({__FILE__})) 
in which it is called. But any override ends up with the (({__FILE__})) 
in which the override is defined instead.

Is there a way around this? If not, then the only way to do this 
properly/completely is via core code.
=end

----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34819

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by charliesome (Charlie Somerville) (Guest)
on 2012-12-18 06:01
(Received via mailing list)
Issue #7548 has been updated by charliesome (Charlie Somerville).


=begin
You can use (({Kernel#caller})) to obtain the filename of the caller
=end
----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34820

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by Thomas Sawyer (7rans)
on 2012-12-18 15:44
(Received via mailing list)
Issue #7548 has been updated by trans (Thomas Sawyer).


=begin
@charliesome That doesn't quite fix the problem.

  # foo/require_relative.rb
  alias_method :require_relative_without_callback, :require_relative

  def require_relative(feature)
    result  = require_relative_without_callback(feature)
    Kernel.loaded(feature) if result
    result
  end

  # bar/use_it.rb
  load 'foo/require_relative.rb'
  require_relative "anything"

Produces

  LoadError: cannot load such file -- foo/anything

But it should be (({bar/anything})).

Your suggestion would allow me to *re-implement* #relative_require. I 
know how to do that, I've done it before for Facets. But I've never felt 
it a very robust solution.
=end

----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34831

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by boris_stitnicky (Boris Stitnicky) (Guest)
on 2012-12-20 21:37
(Received via mailing list)
Issue #7548 has been updated by boris_stitnicky (Boris Stitnicky).


trans (Thomas Sawyer) wrote:
> You mean "cherrypicking like Facets" right? ;)

Sorry, I'm a noob, not knowing whom to credit :]
----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-34919

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by Thomas Sawyer (7rans)
on 2012-12-24 00:49
(Received via mailing list)
Issue #7548 has been updated by trans (Thomas Sawyer).


I just release a gem called backload that basically handles this. But in 
working through the problem set, it's become clear that there are some 
features of a good load callback that just can't be done in pure Ruby. 
I've already mentioned the #relative_require issue. Another issue, is 
that it would be nice to get the full path of the loaded file, e.g. as 
an additional option called :fullpath. There's no way to do that in pure 
Ruby b/c there is no way to lookup a load path (see issue #6376). Even 
if there were, it would be redundant b/c Ruby is just going to look it 
up again in the C code.

So putting it all together, it seems this really needs to be implemented 
in the C if it is to be done right. I do not know if that would mean it 
cannot be an optional standard library, or not.

I almost did not bother to release backload (and I still have half a 
mind to yank it) b/c it can't be as complete and solid an implementation 
as it really ought, but I suppose for some uses it would suffice.

(http://rubyworks.github.com/backload)

----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-35040

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee:
Category:
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Posted by ko1 (Koichi Sasada) (Guest)
on 2013-02-22 01:27
(Received via mailing list)
Issue #7548 has been updated by ko1 (Koichi Sasada).

Category set to core
Assignee set to matz (Yukihiro Matsumoto)

I'm sorry I don't catch up this discussion.
I assigned this ticket to matz, but I'm not sure matz is good person to 
handle it.
Please correct me.

# Basically, I agree with this proposal.

----------------------------------------
Feature #7548: Load and Require Callbacks
https://bugs.ruby-lang.org/issues/7548#change-36751

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: next minor


=begin
Should #load and #require have callbacks? e.g.

  def required(path)
    ...
  end

  def loaded(path, wrap)
    ...
  end

On occasion I have wanted to do load monitoring to track down a bug. 
This would have made it easier.

Are there any other good use cases?
=end
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.