Help: Get list of modules which are included in the class

Hi

I want to get a list of modules which are included directly in the class
in ruby. Example: Suppose below are two modules and a class defined in
ruby script.

module M1
…
end
module M2
…
end
class MyClass
include M1
include M2
…
end

How can I get list of modules which are included directly in the class?
Here in above example, M1 and M2 are only included in class MyClass so I
only want a list which contains modules M1 and M2 for MyClass. If we
call “MyClass.ancestors” which returns all the modules which are include
directly or indirectly in this class and all parent class hierarchy that
exactly I don’t want to get.

Regards
Chirag

On 7/25/07, Chirag M. [email protected] wrote:


call “MyClass.ancestors” which returns all the modules which are include
directly or indirectly in this class and all parent class hierarchy that
exactly I don’t want to get.

Regards
Chirag

Posted via http://www.ruby-forum.com/.

Maybe my friend irb can help :wink:
irb(main):001:0> module M1; end
=> nil
irb(main):002:0> class C1; include M1 end
=> C1
irb(main):003:0> module M2; end
=> nil
irb(main):004:0> class C2 < C1; include M2 end
=> C2
irb(main):017:0> class Module
irb(main):018:1> def included_modules
irb(main):019:2> ancestors.select{|x|x.class==Module}
irb(main):020:2> end
irb(main):021:1> end
irb(main):022:0> C1.included_modules
=> [M1, Kernel]
irb(main):023:0> C2.included_modules
=> [M2, M1, Kernel]

You can get of Kernel of course if you do not want it to show up at the
party.
HTH
Robert

On Behalf Of Chirag M.:

only want a list which contains modules M1 and M2 for MyClass. If we

call “MyClass.ancestors” which returns all the modules which

are include directly or indirectly in this class and all parent class

how about subtracting fr there =)

something like,

irb(main):026:0> C2.ancestors - (Class.new.ancestors + [C2])
=> [M2, M1]

sorry if my answer sound stupid.

kind regards -botp

On 7/25/07, Peña, Botp [email protected] wrote:

=> [M2, M1]

sorry if my answer sound stupid.

kind regards -botp

not stupid at all, you just overlooked a little detail, parent classes.

module M1; end
module M2; end
class C1; include M1 end
class C2 < C1; include M2 end

p C2.ancestors - (Class.new.ancestors + [C2])

Robert

On 7/25/07, [email protected] [email protected] wrote:


How can I get list of modules which are included directly in the class?

irb(main):018:1> def included_modules
Robert
irb(main):121:1> end
=> [M2, M1, Kernel]

I think that Chirag wanted to get only M2 and as you can see we get M1
as well.
What!!! Do I have to read the post in oder to answer now???

My bad you are right indeed.

I personally think that there is no way to solve this. As far
as I know Ruby holds its ancestors internally in a plain list and
doesn’t remember the hierarchy. Can someone tell more on this matter?
That is indeed more challenging :slight_smile:

On Jul 25, 11:21 am, “Robert D.” [email protected] wrote:

end
Here in above example, M1 and M2 are only included in class MyClass so I
Maybe my friend irb can help :wink:
irb(main):019:2> ancestors.select{|x|x.class==Module}


I always knew that one day Smalltalk would replace Java.
I just didn’t know it would be called Ruby
– Kent Beck

I don’t think that it answers the question. Look at the following
example:

irb(main):120:0> module M1
irb(main):121:1> end
=> nil
irb(main):122:0> module M2
irb(main):123:1> include M1
irb(main):124:1> end
=> M2
irb(main):125:0> class C1
irb(main):126:1> include M2
irb(main):127:1> end
=> C1
irb(main):128:0> C1.ancestors.select{|x|x.class==Module}
=> [M2, M1, Kernel]

I think that Chirag wanted to get only M2 and as you can see we get M1
as well. I personally think that there is no way to solve this. As far
as I know Ruby holds its ancestors internally in a plain list and
doesn’t remember the hierarchy. Can someone tell more on this matter?

FireAphis

Peña, Botp wrote:

From: Robert D. [mailto:[email protected]]

p C2.ancestors - (Class.new.ancestors + [C2])

Hi

Thanks for the reply. I have looked all the solution but all above
solution also includes modules which are included indirectly. I wants
list of modules which are included directly. See below example.

E.g.

module IN
end

module M1
include IN
end

module M2
include IN
end

class C
include M1
include M2

end

 If we try above solution then I will get M1, M2, IN and Kernel. But 

I want list which contains M1 and M2 only because these both are
included directly in class C.

Regards
Chirag

From: Robert D. [mailto:[email protected]]

p C2.ancestors - (Class.new.ancestors + [C2])

yap, your scheme is more straightforward

(C.ancestors-[Kernel]).select{|x| x.class == Module}

From: Chirag M. [mailto:[email protected]]

Peña, Botp wrote:

> From: Robert D. [mailto:[email protected]]

> # p C2.ancestors - (Class.new.ancestors + [C2])

E.g.

----

module IN

end

module M1

include IN

end

module M2

include IN

end

class C

include M1

include M2

end

----

If we try above solution then I will get M1, M2, IN and

Kernel. But

I want list which contains M1 and M2 only because these both are

included directly in class C.

again, you can do fred’s technique or

you can do plain subtraction. get the included modules of each and
subtract it from the main…

something like,

irb(main):059:0* M1.included_modules
=> [IN]
irb(main):060:0> M2.included_modules
=> [IN]
irb(main):061:0> IN.included_modules
=> []


irb(main):055:0> mymodules = C.included_modules - [Kernel]
=> [M2, M1, IN]
irb(main):056:0> mymodules.each {|m| mymodules -= m.included_modules}
=> [M2, M1, IN]
irb(main):057:0> mymodules
=> [M2, M1]

kind regards -botp

Le mercredi 01 août 2007 à 05:44 +0900, Wayne E. Seguin a écrit :

end

=>[Module1]
Actually, I also allow for filtering out of other modules than Kernel
class Class2 < Class1; include Module2 end


Wayne E. Seguin
Sr. Systems Architect & Systems Admin
[email protected]

There is a problem (him ! again ! Arrrrrrg (Monthy Python dixit (yeah
for Monthy Ruby !!! (sorry, I’ll try to stop lisp-mod ;)))))
You should try this :

module Module1; end
class Class1; include Module1 end
module Module2; end
class Class2 < Class1; include Module1 ; include Module2 end

Class1.included_modules
Class2.included_modules

Class1.directly_included_modules
Class2.directly_included_modules # see this result

Class1.inherited_modules
Class2.inherited_modules

Chirag,

This is how I handle it in my applications:

lib/ruby_extensions.rb

=======================================
class Module
def included_modules
( ancestors - [ Kernel ] ).select { | x | x.class == Module &&
x != Kernel }
end

def directly_included_modules
ancestors - superclass.ancestors - [self]
end

def inherited_modules
superclass.included_modules - self.directly_included_modules
end
end

=======================================
irb:

module Module1; end
=>nil

class Class1; include Module1 end
=>Class1

module Module2; end
=>nil

class Class2 < Class1; include Module2 end
=>Class2

Class1.included_modules
=>[Module1]

Class2.included_modules
=>[Module2, Module1]

Class1.directly_included_modules
=>[Module1]

Class2.directly_included_modules
=>[Module2]

Class1.inherited_modules
=>[]

Class2.inherited_modules
=>[Module1]

Actually, I also allow for filtering out of other modules than Kernel
but that’s not relevant here.

I sincerely hope this helps.

=======================================
(easy irb example paste:)

module Module1; end
class Class1; include Module1 end
module Module2; end
class Class2 < Class1; include Module2 end

Class1.included_modules
Class2.included_modules

Class1.directly_included_modules
Class2.directly_included_modules

Class1.inherited_modules
Class2.inherited_modules

On Aug 01, 2007, at 08:56 , dohzya wrote:


Etienne Vallette d’Osia

Etienne,

Thank you very much for this feedback. After thinking about it, here
is my take on this:

We include Module1 in Class1 and so from inheritence this implies
that Class2 does not actually include Module1 directly, since it has
already been included. Hence including Module1 in Class2 is
effectively a no-op.

This makes semantic sense, also: “directly_included_modules” should
be the modules that self includes which the superclass does not. In
this light Module1 is not directly included so my code does what is
expected.

(Also, for the record, Module already has an included_modules method,
but I am overwriting because I don’t want Kernel listed for my purposes)

(Thanks to Mark Josef for helping me with this idea)

On Aug 01, 2007, at 08:56 , dohzya wrote:

Class2.included_modules

Class1.directly_included_modules
Class2.directly_included_modules # see this result

Class1.inherited_modules
Class2.inherited_modules


Etienne Vallette d’Osia

Etienne,

Good point. Any ideas on a better way?
Although if you’re including twice like that the design is most
likely flawed and needs a re-factoring?

This makes semantic sense, also: “directly_included_modules” should
Wayne E. Seguin
Sr. Systems Architect & Systems Admin
[email protected]

Thanks :blush:
Indeed, it’s comparable with the difference between ‘define’ and
‘overload’ (it isn’t?)… moreover it’s an overloading with same
method(s) :slight_smile:
(I’m sorry if I’m repeating anyone, it’s hard for me to express myself
and understand correctly in English… I’m working in this way)

On 7/25/07, dohzya [email protected] wrote:

How about (C2.ancestors - [C2] - C2.superclass.ancestors) ?
You got it, indeed it was not so chellanging after all :frowning:

Cheers
Robert

How about (C2.ancestors - [C2] - C2.superclass.ancestors) ?

Le mercredi 25 juillet 2007 à 17:54 +0900, Peña, Botp a écrit :

From: Peña, Botp [mailto:[email protected]]

From: Robert D. [mailto:[email protected]]

# p C2.ancestors - (Class.new.ancestors + [C2])

yap, your scheme is more straightforward

(C.ancestors-[Kernel]).select{|x| x.class == Module}

i forgot one,

irb(main):044:0> C.included_modules
=> [M2, M1, Kernel]
irb(main):046:0> C3.included_modules - [Kernel]
=> [M2, M1]

Le 25 juillet à 08:44, [email protected] a écrit :

I think that Chirag wanted to get only M2 and as you can see we get M1
as well. I personally think that there is no way to solve this. As far
as I know Ruby holds its ancestors internally in a plain list and
doesn’t remember the hierarchy. Can someone tell more on this matter?

You can always build the list yourself :

#! /usr/local/bin/ruby

class Module
attr_accessor :children
def included©
@children ||= []
@children << c
end
end

module M1
end

module M2
include M1
end

class C1
include M2
end

class C2 < C1
include M2
end

C1.ancestors.each { |x| puts “#{x} : #{x.children.inspect}” }

p C1.ancestors.select { |x| x.instance_of?(Module) && x.children &&
x.children.include?(C1) }

Gives :

C1 : nil
M2 : [C1, C2]
M1 : [M2]
Object : nil
Kernel : nil
[M2]

(Not very much tested, but the idea is there, I think.)

Fred

Le mercredi 25 juillet 2007 à 18:24 +0900, Robert D. a écrit :

On 7/25/07, dohzya [email protected] wrote:

How about (C2.ancestors - [C2] - C2.superclass.ancestors) ?
You got it, indeed it was not so chellanging after all :frowning:

Cheers
Robert

There is a problem :

module M1 ; end
module M2 ; end
class C1 ; include M1 ; end
class C2 < C1 ; include M1 ; include M2 ; end

p (C2.ancestors - [C2] - C2.superclass.ancestors) # => [M2]

I don’t know if it is a severe problem…

On 7/25/07, dohzya [email protected] wrote:

There is a problem :

module M1 ; end
module M2 ; end
class C1 ; include M1 ; end
class C2 < C1 ; include M1 ; include M2 ; end

p (C2.ancestors - [C2] - C2.superclass.ancestors) # => [M2]

I don’t know if it is a severe problem…
We have to ask OP, if he really wants to have M1 in this list I am
afraid that Fred’s metaprogramming track by using Module#included is
the only way,
maybe it would be nice if OP could tell us what this is for.


Etienne Vallette d’Osia

Cheers
Robert