From: "shioyama (Chris Salzberg) via ruby-core" Date: 2023-02-08T03:41:53+00:00 Subject: [ruby-core:112273] [Ruby master Feature#17753] Add Module#namespace Issue #17753 has been updated by shioyama (Chris Salzberg). This has been quiet for a while, but despite the reservations expressed I'd really like to see it implemented. I don't personally really like `namespace` as a name either, because of its usage in other places. It's been mentioned, but what exactly is wrong with `module_parents`, the same method ActiveSupport uses? @fxn > Yes, c.name is "X::C", but as I said above, that is just a string. It's a string, yes, but it also includes some rules about _what_ to return _when_ that I think are relevant to your concerns about edge cases. I think any implementation of this method should be fully consistent with `Module#name`. That means also encompassing names that are temporary (where the root is anonymous). Just so we're all on the same page: ```ruby mod = Module.new mod.name #=> nil mod::Foo = Module.new mod::Foo.name #=> "#::Foo" ``` `"#::Foo"` is `mod::Foo`'s "temporary name". We can assign another module under an anonymous root to it and it will not change: ```ruby other_mod = Module.new other_mod::Bar = mod::Foo other_mod::Bar #=> "#::Foo" ``` So temporary names are "sticky" as long as the module doesn't have a permanent name. Once it has a permanent name, that name does not change regardless of assignment to other toplevel-rooted constants. So we have some rules for how `Module#name` can and cannot change: 1. A module's permanent name, once assigned, cannot be re-assigned. So although you can nest the same constant in many places in many ways, the `name`, once attached to a permanent root, will not change. 2. A module's temporary name, once assigned, cannot be re-assigned except to a permanent name. So you can assign another name from an anonymous namespace, the module's original temporary name sticks and only changes when/if it gets a permanent name. I think these rules give us everything we need to define a method that returns the set of module objects in `name` as an array, and I think this would be a very useful method to have. Extended to anonymous roots, I would expect this (I'm using `namespace` here because that's the current name we're talking about, I don't love it but just to avoid confusion): ```ruby mod = Module.new mod::Foo = Module.new mod::Foo.name #=> "#::Foo" mod::Foo.namespace #=> [::Foo, ] other_mod = Module.new other_mod::Bar = mod::Foo other_mod::Bar.namespace #=> [::Foo, ] Bar = mod mod::Foo.namespace #=> [Bar::Foo, Foo] Baz = mod Baz::Foo.namespace #=> [Bar::Foo, Foo] ``` This is entirely consistent with how `name` works, and I think is in fact a very natural complement to it. Since conventions are exactly the same, there is no need for any additional "rules" to cover the edge cases above. As an implementation, this is fully determined, consistent with an existing pattern (`Module#name`) and works as expected for most common use cases. @mame > the use case is not clear to him It's been mentioned above, but [ActiveSupport](https://github.com/rails/rails/blob/dcd8f37bc63d46f28aa55e6891b03a0b0b73e497/activesupport/lib/active_support/core_ext/module/introspection.rb#L39-L62) and other libraries use `mod.name.split("::")` all over the place to go from something they can _see_ (`Module#name`) to something they can _use_ (actual module objects). This has always seemed extremely clumsy to me; Ruby generated the `name` from the module objects, but it will only give you the "trace" of them, not the actual living things. Personally, I've been recently working with anonymous-rooted namespaces (like `mod` and `mod::Foo` above) and the inability to get the root of a module is yet more problematic, because `name.split("::")` and `constantize` don't work in that context. I'd love to see this happen, under any name that seems appropriate. ---------------------------------------- Feature #17753: Add Module#namespace https://bugs.ruby-lang.org/issues/17753#change-101703 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Priority: Normal ---------------------------------------- Given code like this: ```ruby module A module B class C; end class D; end end end ``` We can get from `C` to `B` like `C.outer_scope`, or to `A` like `C.outer_scope.outer_scope`. I want to use this in cases where I don't know the outer scope, but I want to find constants that are "siblings" of a constant. For example, I can do `A::B::C.outer_scope.constants` to find the list of "sibling" constants to `C`. I want to use this feature when walking objects and introspecting. For example: ```ruby ObjectSpace.each_object(Class) do |k| p siblings: k.outer_scope.constants end ``` I've attached a patch that implements this feature, and there is a pull request on GitHub [here](https://github.com/ruby/ruby/pull/4326). ---Files-------------------------------- 0001-Add-Module-outer_scope.patch (5.93 KB) 0001-Add-Module-namespace.patch (5.89 KB) -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/