Get all classes from a list of files

I have a list of ruby files. I would like to create objects from all
classes using eval(classname)

My filelist looks something like:
nl/foo_nl_bar.rb #class NL::FooNLBar
en/bar_en_foo.rb #class EN::BarENFoo

For now my solution is as follows:
File.readlines(rubyfile).find_all{|line|
line.start_with?(“class”)}.collect{|file|
file.split("<")[0].gsub(/class/, “”)}.map(&:strip)

IMHO this is ugly

I tried doing it with Module.constants. It returns the classnames, but
the namespace is missing.
Using String.camelize.constantize returns BarEnFoo. So here the
namespace is also missing and the camelize doesn’t work.

Doe anyone know a cleaner solution?

On Wed, Sep 28, 2011 at 7:33 AM, Jeroen van Ingen
[email protected]wrote:

file.split(“<”)[0].gsub(/class/, “”)}.map(&:strip)

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

If you follow common conventions, you can infer class names from
filenames.

What problem are you trying to solve? What if, instead of scraping files
and
evaling strings, you had the classes register themselves with whatever
needs
these instances? Here is an example:

This class needs to know about all of my interfaces

So when they are defined, they tell the class that they exist

My problem is that when I add a file to the files, it must be
automatically included in the list of classes, so I can create an object
like I said; eval(classname)

Your solution is ugly for me in another way. Let me explain…
All my files are included in the same dir and subdirs. So it’s not
needed to tell every single file that it must register itself. I would
like to it in one place, not in every single file.

sorry but why did you want to use eval?
eval is allways the badest possible code

use Object.const_get(classname).new

or if the classname include “::” do this
classname.split("::").inject(Object,:const_get).new

Jeroen van Ingen wrote in post #1024083:

My problem is that when I add a file to the files, it must be
automatically included in the list of classes, so I can create an object
like I said; eval(classname)

Your solution is ugly for me in another way. Let me explain…
All my files are included in the same dir and subdirs. So it’s not
needed to tell every single file that it must register itself. I would
like to it in one place, not in every single file.

possibly something like this??

http://pastebin.com/fnZkJp3L

@Adam
I’m not talking about inheritance. I just want to get access to all
ruby-classes inside a list of files in a dir and it subdirs.

@Hans
Ah OK, thanks. I thought eval() was the only way to do it.
Can you explain why eval() is always the badest solution?

On Sat, Oct 1, 2011 at 6:56 PM, Phillip G.
[email protected] wrote:

On Sat, Oct 1, 2011 at 6:05 PM, Jeroen van Ingen [email protected] wrote:

Can you explain why eval() is always the badest solution?

eval(‘system “rm -rf /”’) # Where’d my UNIX go?

:slight_smile:

robert

On Sat, Oct 1, 2011 at 9:04 PM, Robert K.
[email protected] wrote:

- YouTube

:slight_smile:

It’s a love/hate relationship for me. Mostly hate. :wink:


Phillip G.

gplus.to/phgaw | twitter.com/phgaw

A method of solution is perfect if we can forsee from the start,
and even prove, that following that method we shall attain our aim.
– Leibniz

On Sat, Oct 1, 2011 at 6:05 PM, Jeroen van Ingen [email protected]
wrote:

Can you explain why eval() is always the badest solution?

eval(‘system “rm -rf /”’) # Where’d my UNIX go?


Phillip G.

gplus.to/phgaw | twitter.com/phgaw

A method of solution is perfect if we can forsee from the start,
and even prove, that following that method we shall attain our aim.
– Leibniz

Jeroen van Ingen wrote in post #1024064:

I have a list of ruby files. I would like to create objects from all
Classes

Does anyone know a cleaner solution?

Module.nesting returns the fully namespaced modules beneath wherever it
was called, so something like this maybe?

mod.module_eval do
Module.nesting.select {|m| m.is_a? Class}
end

Hope this helps,

-Luke

On Sat, Oct 1, 2011 at 11:05 AM, Jeroen van Ingen
[email protected]wrote:

@Adam
I’m not talking about inheritance. I just want to get access to all
ruby-classes inside a list of files in a dir and it subdirs.

This is seriously the wrong approach. It hides what’s actually
happening, is
very difficult to do correctly, and it can easily cause lots of
unrelated
code to break. I will again recommend having the class just tell the
instantiator that it exists and conforms to the expectations of the
instantiator. You could do it the way I showed or the way Adam showed.

There might be other solutions too, this is just how I handled it in the
past. But grepping files to construct a string you can evaluate is
definitely the wrong thing to do:

Problem 1: Due to its indiscriminate instantiation, your code will be

fragile and rigid ##

What happens if you have some code that should go in that directory, but
the
class shouldn’t be instantiated by your code? How will you distinguish?

What if you reopen a class, then it will get instantiated twice! You’ll
have
to go hack on the parsing code to track how many times its instantiated
each
class class MyClass; end; class MyClass; end

What happens if you need to open a class that it shouldn’t instantiate?
class String; end That’s fine to do, but all of a sudden you can’t do
it
because your other code is going to find it.

What if your class needs to use a subclass in order to do its job class Outer; class Inner; end; end Whoops, your code didn’t instantiate Outer
like it was supposed to, it instantiated Inner instead, which it was not
supposed to, and there is no way to fix it other than go hack on or add
special rules to the instantiator, which might in turn break its
behaviour
with the other files it reads.

What happens if you need to put the code somewhere else, but it should
be
instantiated by your instantiator?

What happens when your coworker is reading the code going “now how the
fuck
did this class become part of that list?” (in Python terms: explicit is
better than implicit)

Problem 2: You need to write a Ruby parser and traverse ASTs to do

this
right ##

What happens if you need to define a class like this MyClass = Class.new?
Will your parser be smart enough to see it?

What about like this Object.const_set 'MyClass', Class.new

What about like this my_class = Class.new you won’t even be able to
access
that class, how will you instantiate it?

What about like this class << obj; end