From: Jarmo Pertman on
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: http://gist.github.com/503646

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 Pertman
-----
IT does really matter - http://www.itreallymatters.net
From: David A. Black on
Hi --

On Mon, 2 Aug 2010, Jarmo Pertman wrote:

> 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: 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

From: John Croisant on
On Sun, Aug 1, 2010 at 2:20 PM, Jarmo Pertman <jarmo.p(a)gmail.com> wrote:
> 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: http://gist.github.com/503646
>
> 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 Pertman

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.

From: Jarmo Pertman on
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 Pertman
-----
IT does really matter - http://www.itreallymatters.net



On Aug 2, 1:48 am, John Croisant <jac...(a)gmail.com> wrote:
> On Sun, Aug 1, 2010 at 2:20 PM, Jarmo Pertman <jarm...(a)gmail.com> wrote:
> > 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:http://gist.github.com/503646
>
> > 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 Pertman
>
> 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.

From: Brian Candler on
Jarmo Pertman 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
--
Posted via http://www.ruby-forum.com/.