Best practice? libs and modules

Hello,

another ‘best practice’ question. Example: I have a library which I
think should go into

lib/foo/bar/baz.rb

Should I use 'module … ’ wrappers to reflect the directory structure?
I.e.

module Foo
module Bar
class Baz
end
end
end

I’d like to be a good ruby-citizen. My personal preference though would
be something different:

module Baz
class SomethingElse
end
end

so the scope would be

s=Baz::SomethingElse.new

Patrick

Patrick G. wrote:

Hello,

another ‘best practice’ question. Example: I have a library which I
think should go into

lib/foo/bar/baz.rb

Should I use 'module … ’ wrappers to reflect the directory structure?
I.e.

module Foo
module Bar
class Baz
end
end
end

I’d like to be a good ruby-citizen. My personal preference though would
be something different:

module Baz
class SomethingElse
end
end

so the scope would be

s=Baz::SomethingElse.new

The latter is fine. So long as your top-level namespace is
unique (i.e. the name of your project, hopefully), the
underlying structure is inconsequential.

Patrick

On Sat, 2 Sep 2006, Patrick G. wrote:

Hello,

another ‘best practice’ question. Example: I have a library which I
think should go into

lib/foo/bar/baz.rb

[snip]

s=Baz::SomethingElse.new
How you scope your class has a subjective element. Only you can decide
what the best organization of your class hierarchy is, for your uses.

However, in the general case, yes, definitely put your class under at
least one level of scoping, such as you illustrate above, especially if
you plan to release your library for others to use. Namespace
collisions
are no fun.

Just by way of example, I generally organize classes under a module
namespace that reflects the name of the project. Then, under that, I
will
organize similar classes under further names.

So:

Iowa::KeyValueCoding
Iowa::Caches::LRUCache
Iowa::Pools::DBConnectionPool

etc…

I have even done this with certain Ruby class extensions.

So, for example, I have added some things to String and Hash, but don’t
want to either force my users to use my extensions, or interfere with my
users ability to use their own extensions. So, any place where I am
going
to need one of those extensions, I work with Iowa::String or Iowa::Hash
instead of String and Hash. It’s a little more typing for me, but
better
for my users.

Kirk H.

Hello Eero and Kirk,

thank you for your valuable comments. My “namespace” is very unlikely to
collide with anything else, and yes, I have started a little rubyforge
project, so the library will be released into public.

I appreciate your replies,

Patrick

For structuring my projects, I tend to keep nested modules and classes
as internal objects. That is to say, I have ProjectName::Base but then
any other dependent classes I’ll stick in
ProjectName::Support::Connection or what have you. Of course, if
someone is equally likely to use Base as well as Connection, then I’ll
stick them both just in ProjectName.

Of course, this really is just preference. Either way would be fine.
(And besides, I’m (very) far from being an expert, so take what I say
with a grain of salt.)

M.T.

On Sep 1, 2006, at 8:13 AM, Patrick G. wrote:

module Foo
module Bar
class Baz
end
end
end

If you’re going this way,

class Foo::Bar::Baz

leaves out lots of indentation.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On 9/1/06, Eric H. [email protected] wrote:

If you’re going this way,

class Foo::Bar::Baz

leaves out lots of indentation.

That’s really cool!

However, it only really works if you don’t reference things in the Foo
or Bar modules. E.g.:

class Foo::Bar::Baz
end

class Foo::Bar::Qux
def fetch_me_a_baz
Foo::Bar::Baz.new() # ← need to use explicit namespace here
end
end

Versus the nested case:

module Foo
module Bar
class Baz
end

class Qux
  def fetch_me_a_baz
    Baz.new()               # <- this line is simpler
  end
end

end
end

Well, that was a bit wordier than I expected it to be. I guess it’s a
tradeoff that you can make depending on how many times you need to use
Baz from inside Qux. Nice!

-RYaN

On Sat, 2 Sep 2006, Trans wrote:

So, for example, I have added some things to String and Hash, but don’t
want to either force my users to use my extensions, or interfere with my
users ability to use their own extensions. So, any place where I am going
to need one of those extensions, I work with Iowa::String or Iowa::Hash
instead of String and Hash. It’s a little more typing for me, but better
for my users.

There’s a downside to this though. To take advantage of those
extensions your uses have to use these special subclasses too. As long
as your not changing the behavior of a built-in you’re generally okay.

No, it really doesn’t matter if I am changing the behavior of a built in
or not (which I’m not).

If I just opened String and put my extensions into there, I’d run the
substantial risk that someone might use a core extension from
Rails’ ActiveSupport or Facets that conflicts. And even if there are no
conflicts today, tomorrow there might be.

Or if I just used LRUCache instead of Iowa::Caches::LRUCache, and
someone
decided to use the Facets LRUCache in an app, it would cause bad things
to
happen (I like the Facets LRUCache’s simplicity; I hate that it requires
extending anything that is to be stored in it, BTW).

So yes, if one of my users wants to take advantage of something I have
in one of the extensions, they have to type a few more characters to
create the object. I am quite willing to sacrafice a few characters for
the relative security against namespace collisions, though. The cost is
very small, and the benefit is large.

Kirk H.

[email protected] wrote:

So, for example, I have added some things to String and Hash, but don’t
want to either force my users to use my extensions, or interfere with my
users ability to use their own extensions. So, any place where I am going
to need one of those extensions, I work with Iowa::String or Iowa::Hash
instead of String and Hash. It’s a little more typing for me, but better
for my users.

There’s a downside to this though. To take advantage of those
extensions your uses have to use these special subclasses too. As long
as your not changing the behavior of a built-in you’re generally okay.

T.

[email protected] wrote:

extensions your uses have to use these special subclasses too. As long
Or if I just used LRUCache instead of Iowa::Caches::LRUCache, and someone
decided to use the Facets LRUCache in an app, it would cause bad things to
happen (I like the Facets LRUCache’s simplicity; I hate that it requires
extending anything that is to be stored in it, BTW).

Hmm… If you have a fix for that I’d love to incorporate it.

So yes, if one of my users wants to take advantage of something I have
in one of the extensions, they have to type a few more characters to
create the object. I am quite willing to sacrafice a few characters for
the relative security against namespace collisions, though. The cost is
very small, and the benefit is large.

But then how will I use Kirk’s String extensions and Tom’s string
extensions?

It’s a tade off and what we really need is proper namespaces to fix the
problem.

T.

On Sun, 3 Sep 2006, Trans wrote:

Or if I just used LRUCache instead of Iowa::Caches::LRUCache, and someone
decided to use the Facets LRUCache in an app, it would cause bad things to
happen (I like the Facets LRUCache’s simplicity; I hate that it requires
extending anything that is to be stored in it, BTW).

Hmm… If you have a fix for that I’d love to incorporate it.

Well, let me tell you what I did.

The mixin is used to turn the desired class into something that can be a
linked list node. It’s a neat idea, but I don’t like having to pollute
my
namespace, and it breaks down messily in some instances (try using the
cache to cache fixnums…).

So, I took a couple ideas from the implementation and built a doubly
linked list implementation that doesn’t need the mixin and also provides
fast random access by using a hash in conjunction with the list. So
data
access, modification, inserts, and deletes are all pretty fast, and no
penalty is paid for having large numbers of items in the cache.

I then used this as the basis for an LRU cache implementation. Mine
will
also expire elements based on age. So, for example, a cache with a max
ttl of 1800 seconds will expire elements that haven’t been accessed in
more than half an hour, even if the cache isn’t full. I pay a small
cost
for this capability, though, in terms of speed, so it may not be
something
you would want in your implementation.

The cache should be threadsafe, and I also have a capability in mine for
finalizers – blocks of code that are invoked immediately before
something
is expired from the cache – which also does not come for free.

I can happily make a version of the cache which doesn’t include the TTL
stuff or the finalizers, though, if you want it. Note that the mixin
approach of your current LRU cache definitely makes for the fastest
cache,
though, so I guess it depends on what one is selecting for. I’m using a
modified version of your LRUCache (I added finalizer support) in a place
where I need a basic LRU cache, can live with the mixin, and just want
it
to be as fast as possible.

You might also be able to use the raw linked list?

So yes, if one of my users wants to take advantage of something I have
in one of the extensions, they have to type a few more characters to
create the object. I am quite willing to sacrafice a few characters for
the relative security against namespace collisions, though. The cost is
very small, and the benefit is large.

But then how will I use Kirk’s String extensions and Tom’s string
extensions?

I suppose I could make Iowa::String delegate any method it doesn’t know
down to the original string it was initialized with. That requires that
it keep a reference to that original string, though, which is also a
tradeoff.

Kirk H.

[email protected] wrote:

access, modification, inserts, and deletes are all pretty fast, and no
finalizers – blocks of code that are invoked immediately before something
is expired from the cache – which also does not come for free.

I can happily make a version of the cache which doesn’t include the TTL
stuff or the finalizers, though, if you want it. Note that the mixin
approach of your current LRU cache definitely makes for the fastest cache,
though, so I guess it depends on what one is selecting for. I’m using a
modified version of your LRUCache (I added finalizer support) in a place
where I need a basic LRU cache, can live with the mixin, and just want it
to be as fast as possible.

Well, I think those are useful features. It would be nice if it could
be implemented in such a way that the TTL and finializers were options
–but zero overhead when not used. But even if that’s not reasonable,
then a second type of LRUCache per your implementation is still welcome
in Facets.

You might also be able to use the raw linked list?

Yes!

T.