How to check if some object is included in some module?

I know that there are methods #kind_of?/#is_a? to check if one object
is a same type or a subclass of another object. But what if i want to
check if one object is in some module? For example:

module MyModule
class MyClass
end
end

m = MyModule::MyClass.new
m.kind_of?(MyModule) # => false

I would be happy if the statement above would return true since
MyClass is in module MyModule. Or why wouldn’t it (except that it
hasn’t meant to with current implementation)?

Anyway, i was hoping to find some other method for this kind of
checks, but was unable to find any from Class, Module, Object, Kernel
classes/modules. So i made one example myself:

I still think that there should be some easier built-in way to perform
this kind of checks. Maybe i have just missed it…

Jarmo P.

Hi –

On Mon, 2 Aug 2010, Jarmo P. wrote:

m.kind_of?(MyModule) # => false

I would be happy if the statement above would return true since
MyClass is in module MyModule. Or why wouldn’t it (except that it
hasn’t meant to with current implementation)?

Anyway, i was hoping to find some other method for this kind of
checks, but was unable to find any from Class, Module, Object, Kernel
classes/modules. So i made one example myself: http://gist.github.com/503646

The nesting of classes and modules is completely different from the
ancestor/descendant relation, though. It’s misleading to combine them.
In your example, MyModule is not an ancestor of MyClass, but your
descendant? method implies that it is.

The ancestor relation (also the basis of kind_of?) is about the method
lookup path. If this is true:

obj.kind_of?(ModuleOrClass)

that means that (unless other arrangements have been made) obj has
access to the instance methods defined in ModuleOrClass. It also implies
this:

obj.class.ancestors.include?(ModuleOrClass)

The question of where ModuleOrClass is defined, and how deeply nested it
is, is a completely separate question.

David


David A. Black, Senior Developer, Cyrus Innovation Inc.

The Ruby training with Black/Brown/McAnally
Compleat Philadelphia, PA, October 1-2, 2010
Rubyist http://www.compleatrubyist.com

On Sun, Aug 1, 2010 at 2:20 PM, Jarmo P. [email protected] wrote:

m.kind_of?(MyModule) # => false
this kind of checks. Maybe i have just missed it…

Jarmo P.

I would do it this way:

MyModule.constants.include?(:MyClass) # note the “:”, it’s a symbol

(It’s also possible to define a general method which takes a class,
gets the class’s name, converts it to a symbol, and then tests whether
the module has that constant. But I’ll leave that an an excercise for
the reader.)

Another possible way to do it would be this:

MyModule.const_get(:MyClass)

This will return MyModule::MyClass if it exists (which will be
considered true in an “if” statement), or raise NameError if it
doesn’t exist. Because it raises an error in the negative case, it’s
not convenient to use it in an “if” statement, which is why I consider
it less desirable than the first way.

HTH,

  • John

P.S. I second David’s advice not to modify Object#descendant?. The
relationship you are testing for is not ancestry/inheritance, so it
doesn’t make much sense for the #descendant? method to do it.

Hello!

But the examples provided by you won’t work since #constants return
only immediate constants and not constants recursively. Thus:
irb(main):003:0> module MyModule
irb(main):004:1> module AnotherModule
irb(main):005:2> class MyClass
irb(main):006:3> end
irb(main):007:2>
irb(main):008:2* class AnotherClass
irb(main):009:3> end
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> MyModule.constants
=> [“AnotherModule”]

John, what do you even mean by “not to modify Object#descendant?”.
Object doesn’t have any methods named like that - it was just method
defined by me. Name of the method didn’t have so much importance for
me, but the solving of the problem itself.

So, both of you think that this solution would be best to do something
like this? Or you’re saying that i should not do something like this
at all?

Again, ignore the name of the method itself.

Jarmo P.

IT does really matter - http://www.itreallymatters.net

Jarmo P. wrote:

Hello!

But the examples provided by you won’t work since #constants return
only immediate constants and not constants recursively. Thus:
irb(main):003:0> module MyModule
irb(main):004:1> module AnotherModule
irb(main):005:2> class MyClass
irb(main):006:3> end
irb(main):007:2>
irb(main):008:2* class AnotherClass
irb(main):009:3> end
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> MyModule.constants
=> [“AnotherModule”]

You can do the following:

module MyModule
module AnotherModule
class MyClass; end
class AnotherClass; end
end
end
=> nil

o = MyModule::AnotherModule::MyClass.new
=> #MyModule::AnotherModule::MyClass:0xb7436be4

o.class.name
=> “MyModule::AnotherModule::MyClass”

puts “Yippee” if o.class.name =~ /\bMyModule\b/
Yippee
=> nil

puts “Yippee” if o.class.name =~ /\bAnotherModule\b/
Yippee
=> nil

So, both of you think that this solution would be best to do something
like this? Or you’re saying that i should not do something like this
at all?

Modules are just namespaces. It seems odd to ask an object what
namespace its class is in. As I’ve shown above, you can do this - but
why would you want to?

The only time I’ve wanted to do anything close to this is dynamic
constant resolution:

module X
class Foo
N=1
def show_n
puts self.class::N
end
end
class Bar < Foo
N=2
end
end
X::Foo.new.show_n # 1
X::Bar.new.show_n # 2

But even then, neither Foo nor Bar cares whether it is inside module X.
You can remove the module X wrapper completely, changing X::Foo.new to
Foo.new, and it will work just the same.

Equally, if it did make a difference whether you were inside module X
or module Y (perhaps because there were different constants or classes
available), then you’d have to write your code differently within those
modules anyway.

module X
N=1
class Foo
def yo; puts N; end
end
end
module Y
M=2
class Bar
def yo; puts M; end
end
end

Yup, regexp would be another possible way to do it.

But still, let me bring an example.

m = MyModule::AnotherModule::MyClass

if m.descendant?(MyModule)

do something

else

do something else

end

let’s say that it’s possible that m would be of type
MyModule::AnotherModule::MyClass,
MyModule::CompletelyAnotherModule::AnotherClass,
AnotherModule::YetAnotherClass.

Yes, it would make sense that if i knew which are all of the possible
types then i could do something like this instead:
if m.kind_of?(MyModule::AnotherModule::MyClass) || m.kind_of?
(MyModule::CompletelyAnotherModule::AnotherClass)

do something

else

do something else

end

but the problem is that i don’t know all the possible types it might
be and it is decided at runtime. I just know that every object, which
is in module (for this example) MyModule should be handled in one way
and all objects which are not within MyModule namespace at all -
another way. So how would you recommend me to handle this kind of case
if you’re saying that i should not do it? I still don’t see any (much)
better solution than provided by me so far.

Jarmo P.

IT does really matter - http://www.itreallymatters.net

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs