[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Something like import/package in java?

Christoffer Lernö

6/30/2008 5:09:00 PM

Hi,


I keep feeling frustrated with my ruby project.

My problem is one of organization.

My code looks a bit like this:

lib/
main.rb
comman ds/
logio.rb
create.rb
chat.rb
server/
io/
protocol/
utils/

And I keep writing code like

require 'commands/logio'
require 'commands/create'
require 'commands/chat'

etc.


What is annoying is the disconnect from what actually happens.

With "require 'commands/logio'" I am actually importing the two
classes LogIn and LogOut as well as ensuring a bunch of other files
are included.
"require 'commands/create'" is importing classes CreateNew and
ReturnDead and so on.

To some extent I can fix this by enforcing a strict 1 file - 1 class
policy, but the problem does not quite go away.

In java it's a bit simpler although far from perfect: "import
commands.*" would import all the classes in one sweep, and of course
the strict 1 file - 1 class policy is maintained in java for public
classes.


What I'd love to have is something like this instead of require:

<logio.rb>
package commands

class LogIn
...
end

class LogOut
...
end

end

<main.rb>
import commands.LogIn

where import goes into the commands dir and just loads that single
class.

Is there something like this available? Any ideas?


/C

7 Answers

Michael Morin

6/30/2008 5:19:00 PM

0

Christoffer Lernö wrote:
> Hi,
>
>
> I keep feeling frustrated with my ruby project.
>
> My problem is one of organization.
>
> My code looks a bit like this:
>
> lib/
> main.rb
> comman ds/
> logio.rb
> create.rb
> chat.rb
> server/
> io/
> protocol/
> utils/
>
> And I keep writing code like
>
> require 'commands/logio'
> require 'commands/create'
> require 'commands/chat'
>
> etc.
>
>
> What is annoying is the disconnect from what actually happens.
>
> With "require 'commands/logio'" I am actually importing the two classes
> LogIn and LogOut as well as ensuring a bunch of other files are included.
> "require 'commands/create'" is importing classes CreateNew and
> ReturnDead and so on.
>
> To some extent I can fix this by enforcing a strict 1 file - 1 class
> policy, but the problem does not quite go away.
>
> In java it's a bit simpler although far from perfect: "import
> commands.*" would import all the classes in one sweep, and of course the
> strict 1 file - 1 class policy is maintained in java for public classes.
>
>
> What I'd love to have is something like this instead of require:
>
> <logio.rb>
> package commands
>
> class LogIn
> ...
> end
>
> class LogOut
> ...
> end
>
> end
>
> <main.rb>
> import commands.LogIn
>
> where import goes into the commands dir and just loads that single class.
>
> Is there something like this available? Any ideas?
>
>
> /C
>

Not really. If you're worried about namespace pollution, you can put
everything into a module. Besides including the module and "importing"
everything within it, I don't think there's a way to selectively include
classes or methods from the module.

What exactly are your concerns? Neatness aside.

--
Michael Morin
Guide to Ruby
http://ruby....
Become an About.com Guide: beaguide.about.com
About.com is part of the New York Times Company

Christoffer Lernö

6/30/2008 5:43:00 PM

0

On 30 Jun 2008, at 19:19, Michael Morin wrote:

> Christoffer Lern=F6 wrote:
>> What I'd love to have is something like this instead of require:
>> <logio.rb>
>> package commands
>> class LogIn
>> ...
>> end
>> class LogOut
>> ...
>> end
>> end
>> <main.rb>
>> import commands.LogIn
>> where import goes into the commands dir and just loads that single =20=

>> class.
>> Is there something like this available? Any ideas?
>> /C
>
> Not really. If you're worried about namespace pollution, you can =20
> put everything into a module. Besides including the module and =20
> "importing" everything within it, I don't think there's a way to =20
> selectively include classes or methods from the module.
>
> What exactly are your concerns? Neatness aside.

Readability, clear division of responsibilities, ease of development.

- Even with unit test suites I don't feel secure that the test isn't =20
conditional on files included by other tests.
- If I want to include all classes from a dir, I have to manually scan =20=

through the dir.
- Clear cut organization of files.
- Crystal clear dependencies between files.
- Lots of other small worries I can't quite put my finger on.

There's some breaking point around 20+ files for me (excluding unit =20
tests), when it becomes really important to have a well-defined =20
organization of my classes, and here just heaping classes into =20
different files doesn't quite cut it for me.


/C=

Marc Heiler

6/30/2008 8:29:00 PM

0

"- Clear cut organization of files."

I am not entirely sure where you are heading here. For my latest project
I am using a yaml file which requires about 50 different .rb files,
while this is probably not the best layout, it is easy to add or remove
files to that in one place, and quite clear for me.
--
Posted via http://www.ruby-....

Charles Oliver Nutter

7/1/2008 1:03:00 PM

0

Christoffer Lernö wrote:
> Readability, clear division of responsibilities, ease of development.
>
> - Even with unit test suites I don't feel secure that the test isn't
> conditional on files included by other tests.
> - If I want to include all classes from a dir, I have to manually scan
> through the dir.
> - Clear cut organization of files.
> - Crystal clear dependencies between files.
> - Lots of other small worries I can't quite put my finger on.
>
> There's some breaking point around 20+ files for me (excluding unit
> tests), when it becomes really important to have a well-defined
> organization of my classes, and here just heaping classes into different
> files doesn't quite cut it for me.

Think of require in terms of "load this file" rather than "import
everything defined in this file". All require does is an exactly-once
execution of the file it finds to load, which will in most cases add
methods, modules, or classes to the global namespace.

To namespace your methods modules and classes, you want to embed them
within other modules. The typical convention is that your x/y/z dir
hierarchy will be mirrored in the z.rb file with a nested module X;
module Y; class Z structure.

Coming from Java, the first thing to remember is that Ruby does not
impose (or gift, depending on your perspective) a mandatory file path ==
package structure, so you're free (or required) to do namespacing
however you see fit. If you want a 50-deep dir hierarchy of .rb files to
all dump stuff into the global namespace, you can do so. But you would
typically apply your own namespacing for exactly the reasons you
describe above.

The closest rough equivalent to import would be include, which lets you
pull in a whole module (as a namespace) into a given module or class
(thereby making the former module's namespaced constants available
without full qualification).

- Charlie

Christoffer Lernö

7/2/2008 12:38:00 PM

0

On 1 Jul 2008, at 15:02, Charles Oliver Nutter wrote:

> Christoffer Lern=F6 wrote:
>> Readability, clear division of responsibilities, ease of development.
>> - Even with unit test suites I don't feel secure that the test =20
>> isn't conditional on files included by other tests.
>> - If I want to include all classes from a dir, I have to manually =20
>> scan through the dir.
>> - Clear cut organization of files.
>> - Crystal clear dependencies between files.
>> - Lots of other small worries I can't quite put my finger on.
>> There's some breaking point around 20+ files for me (excluding unit =20=

>> tests), when it becomes really important to have a well-defined =20
>> organization of my classes, and here just heaping classes into =20
>> different files doesn't quite cut it for me.
>
> To namespace your methods modules and classes, you want to embed =20
> them within other modules. The typical convention is that your x/y/z =20=

> dir hierarchy will be mirrored in the z.rb file with a nested module =20=

> X; module Y; class Z structure.
>
> Coming from Java, the first thing to remember is that Ruby does not =20=

> impose (or gift, depending on your perspective) a mandatory file =20
> path =3D=3D package structure, so you're free (or required) to do =20
> namespacing however you see fit. If you want a 50-deep dir hierarchy =20=

> of .rb files to all dump stuff into the global namespace, you can do =20=

> so. But you would typically apply your own namespacing for exactly =20
> the reasons you describe above.

For me it is not so much a namespace-issue. It is rather dependency =20
and include issue. The most frequent use of java imports for me is =20
actually as an indicator of dependencies as I only in very special =20
circumstances would use the fully qualified name of a class.

This means that I can read from the imports the actual dependencies on =20=

external classes. This helps a lot during refactoring and testing.


Perhaps you feel I don't understand your point, and that may be so. I =20=

don't quite see how using namespaces would solve these issues.


I suppose part of my include worries could be solved with something =20
like this:

8<----------------

def package path
relative_path, file_name =3D File.split($PROGRAM_NAME)
top_path =3D File.expand_path(relative_path)
package_path =3D path.split(/\./)
current_path =3D top_path
built_path =3D ""
package_path.reverse.each do |path_part|
current_path, dir =3D File.split(current_path)
built_path +=3D "#{File::SEPARATOR}#{dir}"
raise "Package not in correct directory structure, expected =20
#{package_path.join(File::SEPARATOR)} was #{built_path}" if path_part !=20=

=3D dir
end
$package_top_dir =3D current_path
end

def import path
$package_top_dir ||=3D current_path
import_path_parts =3D path.split(/\./)
file =3D import_path_parts.pop
import_dir =3D Dir.new($package_top_dir + File::SEPARATOR + =20
(file.empty? ? "" : import_path_parts.join(File::SEPARATOR)))
if (file =3D=3D "*")
import_dir.entries.each do |file|
require(import_dir.path + File::SEPARATOR + file) if file =3D~ /=20=

\.rb$/
end
else
require import_dir.path + File::SEPARATOR + file + ".rb"
end
end

8<--------------

If you have this code then the line

package "some_dir.next_dir"
import "some_other_dir.foo"

in file lib/some_dir/next_dir/bar.rb

will require the file lib/some_other_dir/foo.rb regardless from what =20
directory you run the file (excluding playing around with .. and .)

(It would be neater to be able to automatically add the contents of =20
bar.rb to be part of a module named SomeDirNext::NextDir, by default)



/C=

Charles Oliver Nutter

7/2/2008 6:56:00 PM

0

Christoffer Lernö wrote:
> For me it is not so much a namespace-issue. It is rather dependency and
> include issue. The most frequent use of java imports for me is actually
> as an indicator of dependencies as I only in very special circumstances
> would use the fully qualified name of a class.

I think what you're looking for is a static dependency tracking
mechanism in Ruby, a dynamic language. There is not really any simple
way to get such dependency tracking, and certainly nothing built into
Ruby itself. And I don't think this is particularly unusual among
dynamic languages.

- Charlie

Christoffer Lernö

7/8/2008 7:27:00 AM

0

On 2 Jul 2008, at 20:56, Charles Oliver Nutter wrote:

> Christoffer Lern=F6 wrote:
>> For me it is not so much a namespace-issue. It is rather dependency =20=

>> and include issue. The most frequent use of java imports for me is =20=

>> actually as an indicator of dependencies as I only in very special =20=

>> circumstances would use the fully qualified name of a class.
>
> I think what you're looking for is a static dependency tracking =20
> mechanism in Ruby, a dynamic language. There is not really any =20
> simple way to get such dependency tracking, and certainly nothing =20
> built into Ruby itself. And I don't think this is particularly =20
> unusual among dynamic languages.

Static dependency tracking? Yes perhaps sort of that. It doesn't have =20=

to be perfect, just work in most cases. But I am also a simpler way to =20=

include a file when organizing files in a file hierarchy (stuff like =20
require '../somepath/somefile' is rather unclear and will fail if the =20=

file is run from the wrong directory).

/C=