Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>OK, since the only answer which was relevant to my question has been deleted, I'll try to answer my question myself, basing on that deleted answer by @sawa (thanks to @sawa for hinting me in the correct direction). I modified it somewhat to better fit my needs and be more elegant. Later I'll describe why the original @sawa's answer wasn't what I was looking for yet.<br/>OK, so without further ado, here's my own attempt at the solution:</p> <pre><code>module Lib module A extend self def foo puts 'Lib::A::foo' end def helper puts 'Lib::A::helper' foo end end module B extend A def self.bar puts 'Lib::B::bar' helper end end end puts 'Calling Lib::A::foo:' Lib::A::foo # =&gt; Lib::A::foo puts 'Calling Lib::A::helper:' Lib::A::helper # =&gt; Lib::A::helper; Lib::A::foo puts 'Calling Lib::B::bar:' Lib::B::bar # =&gt; Lib::B::bar; Lib::A::helper; Lib::A::foo </code></pre> <p>Here's how it works:<br/> First off, it defines all its methods as instance methods of the particular module class itself (<code>A</code> in this case). But then, to make them available for external use without instantiating (which is impossible for modules after all), I <code>extend</code> the <code>A</code> module with itself, which makes those methods become its class methods too. But thanks to the fact that they're also instance methods of the module <code>A</code>, they can be called from inside other methods of this module without prefixing them with the module name. The same goes for the module <code>B</code>, which also <code>extend</code>s itself with the module <code>A</code>'s methods, making them his own. Then I can call them inside <code>B</code>'s methods too without prefixing, just as I wanted.</p> <p>As you can see, not only I can call both modules' methods from the outside as if they were their class's methods, and I can call <code>A::helper</code> from <code>B::foo</code> without fully qualifying its name, but I can also call <code>A::foo</code> from <code>A::helper</code> without qualifying. This is exactly what I needed and seems to work as I expected.</p> <p>The only problem with this approach could be with the fact that their interfaces are mixing together. This is not much a problem inside <code>B</code>, since that's what I actually wanted: to be able to access <code>A</code>'s methods as if it were <code>B</code>'s methods, without the need for prefixing them with a full qualification. So I've got what I deserved. But this might cause a problem from the outside, because it's an implementation detail of <code>B</code> that it uses <code>A</code>'s methods internally. It shouldn't leak to the outside world, but it does. I'll try to fix it somehow with access control, maybe it'll be possible somehow.</p> <p><strong>Edit:</strong> Yup, it can be done by inserting the following line just after <code>extend A</code> in <code>B</code>:</p> <pre><code>private_class_method *A.public_instance_methods </code></pre> <p>This way <code>B</code> can call <code>A</code>'s methods internally, but they're not accessible from the outside world.</p> <p>Now what was wrong with the original @sawa's solution:</p> <p>It's been using a <em>third</em> module only to proxy the interface through it. For me this was rather an <em>ugly hack</em> than an elegant solution, because it introduces this additional module which will confuse the users of such a library. They will not know whether they should use <code>A</code> or <code>C</code>, and why such a contraption is used at all. It's not obvious how it works by mere looking at it. It needs some more thorough analysis to figure out what it really does and why it is constructed that way. It's not a clean design.</p> <p>In my solution, on the other hand, there are only two modules, as originally designed, and their purpose should be clear for users of this library. There's this strange <code>extend self</code>, but still it appears to be a more common idiom in Ruby than spreading proxy modules all over the place.</p> <p>So thanks guys for your attempts. Next time try to be less arogant (when you see someone asking a question, it's not always the case he's a noob) and fixated on your beloved One True Language (don't get me wrong, I like Ruby language, it's quite cool and clean, but it has some drawbacks too, as any language, and it's better to seek for solving them instead of burying your heads and pretending that there's no problem at all, since it's not something the language was designed for).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload