RFC - One word alias for require_relative

Discussion in 'Ruby' started by Ilias Lazaridis, Jun 11, 2011.

  1. This is a simple Request for Comments.

    Scenario:

    require_relative 'lib/alter'
    require 'alibrary'

    Some project manager complains about "require_relative", and asks you
    to find a one-word alias.

    Which name would you select and for what reasons?

    Requirements
    must:
    * one word

    optional:
    * ideally a 7 letter word

    ..
     
    Ilias Lazaridis, Jun 11, 2011
    #1
    1. Advertisements

  2. require 'alibrary'
    locally 'lib/alter'
    (Uh oh. I replied to Ilias! ;-)

    -Rob

    Rob Biedenharn
    http://AgileConsultingLLC.com/
    http://GaslightSoftware.com/
     
    Rob Biedenharn, Jun 11, 2011
    #2
    1. Advertisements

  3. Ilias Lazaridis

    Intransition Guest

    Okay, I'm willing to respond to this b/c I think there's an
    interesting alternative here that would be an improvement over the
    current system.[1]

    Instead of having two different methods, have the one #require that
    does both. How would it work? Kind of like constant lookup. First the
    require method would look locally, if it failed to find it there it
    could look relative to the current loading project, and then from
    there globally. Of course the problem is name conflict, but that can
    easily be solved. Let's say I have lib file called 'ostruct.rb', say
    it has an extension to ruby's OpenStruct class. Because of the
    relative loading we wouldn't be able to just require 'ostruct' b/c it
    would try to load itself. So instead we have to tell it to look
    globally. We just need a way to denote it, e.g.

    require '::eek:struct'

    We could also be more specific and actually specify the library it is
    in, which could be used to speed up load times and prevent name
    clashes altogether, with:

    require 'ruby:eek:struct'.

    This idea of course presents backward compatibility issues, but it is
    a way to do it that actually improves the robustness and efficiency of
    the load system.


    [1] Hey, get what you can out of him.
     
    Intransition, Jun 11, 2011
    #3
  4. If it breaks backwards compatibility, it's neither effective nor
    robust, I'd say.

    Especially since your idea introduces a *lot* of mental overhead on my part=
    :

    Do I want a local or a global file? What's the syntax for a global
    require, again? And it's almost, but not entirely, completely unlike
    accessing nested constants (Module::Class vs ::file).

    And running non "::require"-aware code leads to fun bugs and security
    issues (imagine a "ostruct" file in the load path that wipes your
    filesystem. The joys...).

    On the flip side, require and require_relative make it completely
    clear that I load either globally or in relation to my source files
    *without* having to remember what a particular bit of line noise
    means.

    If the issue is that you have to type so much more, set up a macro in
    your favourite editor. Or if you happen to use AutoHotKey:
    ::r#::require
    ::rr#::require_relative

    (using the # to avoid situations where you want to type literal "r" and "rr=
    "s)

    You can then tell your project manager to do some actual work, instead
    of worrying about 8 bytes worth of storage.

    --=20
    Phillip Gawlowski

    A method of solution is perfect if we can forsee from the start,
    and even prove, that following that method we shall attain our aim.
    =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0-- Leibnitz
     
    Phillip Gawlowski, Jun 11, 2011
    #4
  5. Ilias Lazaridis

    Intransition Guest

     
    Intransition, Jun 11, 2011
    #5
  6. Mu. Address the point I made.
    require # works globally
    require_relative # works relative to current working directory

    What these methods do is *encoded in the method name*. I don't have to
    remember *a thing*, since the method tells me what it does, and it
    even works when require[_relative] loads from a variable.
    Not without "." in the loadpath it can't:
    PS C:\temp> irbThis is not Ruby's OpenStruct library.
    =3D> truePS C:\temp> cat .\ostruct.rb
    puts "This is not Ruby's OpenStruct library."
    PS C:\temp> ruby -v
    ruby 1.9.2p180 (2011-02-18) [i386-mingw32]
    No, we can't. Look up is still along the path, and something that is
    named identically within the loadpath that gets loaded first still
    blows up in your face.
    Which your system doesn't mitigate against at all. And it cannot, ever
    (nor does Bundler: It is a poor man's version and dependency control).
    Once code is on a machine, it can do whatever it wants. Ruby just
    makes it easier to modify its own classes, but the vector is still
    there: external code executed locally.

    Without making gem signing the default, and have Ruby / RubyGems load
    *only* signed source files, you have no idea who created the code
    you've downloaded. And even then you have to trust the certificate,
    and that the private key with which the code was signed wasn't
    compromised somehow.

    Without auditing code, you have no idea what the code does to your
    machine, and who prevents anyone from claiming "I'm part of Ruby's
    namespace"?


    --=20
    Phillip Gawlowski

    A method of solution is perfect if we can forsee from the start,
    and even prove, that following that method we shall attain our aim.
    =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0-- Leibnitz
     
    Phillip Gawlowski, Jun 11, 2011
    #6
  7. [Note: parts of this message were removed to make it a legal post.]

    Afternoon,

    Fire the project manager or get another job - any bozo that cares about 9
    descriptive characters isn't worth the time.....

    John

    P.S. This now moves into the lead as to the stupidest of Ilias' questions
    thus far. I am surprised that this isn't a barrier to something.
     
    John W Higgins, Jun 12, 2011
    #7
  8. Ilias Lazaridis

    Intransition Guest

     
    Intransition, Jun 12, 2011
    #8
  9. What for?

    And yes, I have to remember the method name. A method name that's much
    more mnemonic than '::whatever'.
    You can't accidentally pollute the namespace if the file doesn't get
    loaded by default. One of the reasons we have "require" and
    "require_relative".
    Please. Then I just define a package, put that someplace first in the
    loadpath, and *boom*, your system blowing up in your face again.
    Every programmer can invent a cypher he, himself, cannot break, as well.

    Unless you wrote your own OS that allows only the execution of
    specifically whitelisted binaries *and* script files (you have to
    prevent arbitrary code execution within a Ruby interpreter, too, after
    all, and just whitelisting the Ruby binary won;t work for that), code
    that is running on your machine, can manipulate your machine.
    How? Since Ruby can execute arbitrary OS-level commands with system()
    or ``, how can Ruby prevent namespace pollution?

    --=20
    Phillip Gawlowski

    A method of solution is perfect if we can forsee from the start,
    and even prove, that following that method we shall attain our aim.
    =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0-- Leibnitz
     
    Phillip Gawlowski, Jun 12, 2011
    #9
  10. Ilias Lazaridis

    Intransition Guest

     
    Intransition, Jun 12, 2011
    #10
  11. See below.
    Since you need to check for a package in different places (user
    specific and global *at the very least*), you have a load path of some
    sort. As long as my package comes first, your system can be broken,
    subverted, by my package.
    Of course it has to do with what is *in* the file. If you execute a
    file that arbitrarily loads code (like a Ruby file, for example, since
    the file's contents get executed on load time already), your system
    can be subverted. So, you do a lot of work to prevent something that
    you *cannot* prevent to begin with. Not without changing how operating
    systems work these days (i.e. instead of executing everything that's
    not blacklisted, only that which is whitelisted gets executed).

    --=20
    Phillip Gawlowski

    A method of solution is perfect if we can forsee from the start,
    and even prove, that following that method we shall attain our aim.
    =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0-- Leibnitz
     
    Phillip Gawlowski, Jun 12, 2011
    #11
  12. Ilias Lazaridis

    Josh Cheek Guest

    [Note: parts of this message were removed to make it a legal post.]

    Back in the blissful days before I understood the `$LOAD_PATH` or the
    difference between `Dir.pwd` and `File.dirname(__FILE__)`, I could `require
    "file"` and it would work (unless I was in another dir). `require_relative`
    isn't universally implemented, and doesn't seem to play well with others.
    It's just generally been unavailable / not worked right for me to the point
    that I prefer to use `File.dirname(__FILE__) + "/file"`

    What if, instead of having CWD in the load path, we had
    `File.dirname(__FILE__)`? Essentially, CWD of the file that the require
    statement is originated through. In the same way that every file has its own
    `__FILE__` variable, what if the `$LOAD_PATH` included the current file's
    dir, for any given file? Then the old interface would work again, it would
    be simpler to think about, security risks of CWD in the load path would be
    addressed, and most importantly, I could write beautiful code again (I die a
    little bit inside each time I write __FILE__).

    Of course, I have no idea if it's even possible, and it's not immediately
    clear to me how it would affect gems. Still, thought I'd put it out there.
     
    Josh Cheek, Jun 12, 2011
    #12
  13. "Locally", because it's an inclusion from the local directories, and
    not from the global library directories.

    Yes, this one sounds good.
    (You will be punished with 37 spam mails)

    ..
     
    Ilias Lazaridis, Jun 12, 2011
    #13
  14. [...] - (changing/extending context)

    But you haven't responded.

    The response would be to suggest a word.
    The process would be:

    * let "require" and "require_relative" work as usual (backwards
    compatibility)
    * define a new keyword for the new load system (e.g. "ensure")
    * engineer this system from scratch
    * including a non-intrusive dynamic OO library-system which builds
    on the strengths of the language (dynamic, oo, etc.)

    The term "engineer" refers to the process.

    But this is really *ways* out of the current topic here.

    As said, just looking for a word, ideally with 7 letters.

    ..
     
    Ilias Lazaridis, Jun 12, 2011
    #14
  15. Ilias Lazaridis

    Intransition Guest

     
    Intransition, Jun 12, 2011
    #15
  16. [Note: parts of this message were removed to make it a legal post.]

    Yep, that just re-introduces the security issue that had us remove . from $:
    in the first place.

    And I wrote a gem that backports require_relative to 1.8, so you can use it
    everywhere. ;) http://rubygems.org/gems/require_relative
     
    Steve Klabnik, Jun 12, 2011
    #16
  17. Ilias Lazaridis

    Intransition Guest

    Hompage link seems to be broken

    Is this in backports (https://github.com/marcandre/backports), btw?

    I'm wondering if I can just start doing 1.9+ only from now on, and if
    the end user wants to use my stuff with 1.8.x they can add RUBYOPT=3D"-
    rbackports", or something along those lines. Could something like that
    do the job?
     
    Intransition, Jun 12, 2011
    #17
  18. Steve Klabnik, Jun 12, 2011
    #18
  19. As there is just one suggestion till now, I'll add two suggestions
    myself, thus we have 3:

    locally 'lib/alter' # locally located file
    require 'alibrary'

    new suggestions:

    include 'lib/alter' # the commonly known "include"
    require 'alibrary'

    uniload 'lib/alter' # universal load
    require 'alibrary'

    ..
     
    Ilias Lazaridis, Jun 12, 2011
    #19
  20. Ilias Lazaridis

    Luc Heinrich Guest

    You do know that 'include' is already used in Ruby. Right?

    Right?!??
     
    Luc Heinrich, Jun 12, 2011
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.