Ruby nested modules as namespaces

I have a nested structure of modules that are used only for name allocation purposes; no mixing in classes etc. So I have a code like this:

module Lib module A def A.foo puts 'Lib::A::foo' end end module B def B.bar puts 'Lib::B::bar' end end end 

Now suppose I want to add another helper method to module A , and I want it to be easily used by both modules. I get the following:

 module Lib module A def A.foo puts 'Lib::A::foo' end def A.helper puts 'Lib::A::helper' end end module B def B.bar puts 'Lib::B::bar' A::helper end end end 

and it seems to work, but it has some flaw that I would like to get rid of:
I don't want to call helper my full name ( A::helper ) all the time from inside B I would rather tell Ruby that this namespace prefix is ​​"default" and calls it just like helper . In C ++, I could just write using A::helper inside the B namespace, and that would solve the problem. But how to do it in Ruby?

I tried adding include A and extend A inside B , but none of them work. It seems that they work only inside classes when these modules are mixed, but not when they are standalone, they are used only for the purpose of placing names.

Are there other ways to make it work the way I want?

Oh and one more thing:
Suppose there is another scenario in which I want A::helper be used only from inside A methods, because it was just some implementation function, where I used some common code used by many functions inside A , but now I don’t want to so that it is visible to the outside world, just by the methods of A How can i do this?

I tried with module_function + to remove the A. prefix from all other functions that should be hidden, but then they are also hidden for other methods in A , because they are instance methods and the modules cannot be created. So, how can I hide the module method from the outside world and still allow it to be used internally by other module methods?

Edit Why downvoting? I tried to be as clear as possible, that I need to default the namespace inside another namespace to completely get rid of the long fully qualified names (and not just impose their alias on something shorter), and that my problem does not concern classes and objects in general, just simple modules used for name purposes only. How else can I explain this?

It’s not my mistake that name management mechanisms do not seem to be fully supported in Ruby initially, like in languages ​​such as C ++, and that this seems like a side effect of using modules and classes to have some true namespace functions ( they sneak like ducks, they have ducks with their beaks, but they are scarves, not ducks, and they cannot be advertised as namespaces, which they apparently do not have, because it only confuses people who come to Ruby from other languages ​​with true namespaces), and that you apparently don’t understand the concepts with other programming languages ​​if they are not possible in Ruby (since I see that you seem to pretend that my problem does not exist and goes back to what you can easily do in Ruby instead, but that’s not what I need) .

And why was the only answer that related to my question was deleted? Not cool;.

+8
oop ruby module namespaces
source share
3 answers

OK, since the only answer that was appropriate for my question was deleted, I will try to answer my own question based on this deleted answer from @sawa (thanks @sawa for hinting me in the right direction), I changed it a bit to better suit my needs and be more elegant. Later I will describe why @sawa's original answer was not what I was looking for.
Ok, so without further ado, here is my own attempt at a solution:

 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 # => Lib::A::foo puts 'Calling Lib::A::helper:' Lib::A::helper # => Lib::A::helper; Lib::A::foo puts 'Calling Lib::B::bar:' Lib::B::bar # => Lib::B::bar; Lib::A::helper; Lib::A::foo 

Here's how it works:
First, he defines all his methods as instance methods of the module class itself ( A in this case). But then, to make them available for external use without creating an instance (which is impossible for modules in the end), I extend module A with myself, which makes these methods also its cool methods. But due to the fact that they are also instances of the method of module A , they can be called from other methods of this module without prefixing them with the name of the module. The same goes for module B , which also extend itself with module A , which makes them their own. Then I can call them inside methods B too, without a prefix, as I wanted.

As you can see, not only can I call the methods of both modules from the outside, as if it were their class methods, and I can call A::helper from B::foo without fully defining its name, but I can also call A::foo from A::helper without qualification. This is exactly what I need and it seems to work the way I expected.

The only problem with this approach may be that their interfaces are mixed. This is not a problem inside B , since this is what I really wanted: to have access to A methods, as if they were methods B , without the need for their prefix with full qualification. So, I have what I deserve. But this can cause the problem from the outside, since it is a part of the implementation of B , which uses the internal methods of A It should not flow into the outside world, but it is. I will try to somehow fix this using access control, perhaps it will be possible.

Edit:. This can be done by inserting the following line immediately after extend A to B :

 private_class_method *A.public_instance_methods 

This method B can call methods A internally, but they are not accessible from the outside world.

Now what happened to @sawa's original solution:

He used the third module only to proxy the interface through it. For me, this was an ugly hack rather than an elegant solution, because it introduces this add-on module, which confuses users of such a library. They will not know whether they should use A or C , and why such a device is used at all. It is not obvious how this works, just looking at it. He needs a more thorough analysis to find out what he is actually doing and why it is built in this way. This is not a clean design.

In my solution, on the other hand, there are only two modules, as was originally developed, and their purpose should be clear to users of this library. There's this weird extend self , but still it looks like a more common idiom in Ruby than distributing proxy modules all over the place.

So thank you guys for your efforts. Next time try to be less arrogant (when you see that someone asks a question, it’s not always like he is noob) and fixates on your favorite One True Language (don’t get me wrong, I like Ruby, it's pretty cool but it also has some drawbacks, like in any language, and it’s better to look for solutions instead of burying your head and pretending that there are no problems, because this is not what the language was designed for).

+8
source share
 module E module A def foo puts 'E::A::foo' end def helper puts 'E::A::helper' end end module B extend A def B.bar puts 'E::B::bar' helper end end end E::B.bar #=> E::B::bar & E::A::helper 
0
source share

I would suggest rethinking your fundamental process. This sentence is a red flag:

I have a nested structure of modules that are used only for name allocation purposes; lack of mixing in classes, etc., only for the purpose of placing names; doesn't mix with classes ...

This is the wrong way to use Modules, and even if you don’t agree right now, you will probably find this with a lot of experience. I suggest exploring Ruby's inheritance more, as well as how modules are used "in the wild." There are TONS of good blogs, guides and materials on the Internet, Google click ...

-3
source share

All Articles