Hi Paul:

This sounds like a great idea. However, I would recommend that when
you do write your module, you include some way of determining which
version is currently in use.

For example, it's difficult to detect which version of File::Spec is
in use, because it's set up so that it does @ISA =
('File::Spec::Unix'); Other classes, including the Win32 one, subclass
the Unix class to get its basic functionality too, so doing:
File::Spec->isa('File::Spec::Unix') doesn't work properly.

For reasons related to module naming, I wouldn't simply do:
File::Spec::$^O. Consider the case where Linux and OS/2 both use the
same class, Unix (as happens with File::Spec). Then simply appending
$^O will mean you need to copy the class for both 'linux' and 'OS2'.

File::Spec handles it internally by using a hash mapping to the
different modules where appropriate. But this might not work in
general (as your class is designed for), since the behaviours of
different operating systems are different. File::Spec does it because
filehandling on OS2 and Linux are similar, but other behaviours may be
different.

So, I guess this is just my long-winded way of saying that you should
include a method of mapping operating systems to class names, but in a
portable manner, so that you can later determine which one is
currently in use. I ran into this problem with one of my modules that
used File::Spec under Win32, where my program was expecting Unix-style
path names. So I needed a way to detect if File::Spec was running
under Unix. If not, then the module was to convert the path stuff to
Unix-like, which obviously isn't necessary if we're already running
under Unix. (This might not be possible under my current understanding
of how your module is supposed to work, since it appears to be as
zero-configuration as possible. Hopefully there is a way to pass
parameters before the call to your module's subclass-finding magic to
tell it about such aliases, since there are lots of $^O strings, that
might not be strictly necessary)

But, getting to what your module should be named, no good ideas really
come to mind. But if you're going to leave out the Magic class names
(personally I don't see anything wrong with it, and think
Class::OSMagic might be appropriate)... Then my next choice would be
Class::ForSystem, since it's not too long and conveys what the module
is designed to do.

Doing stuff like this can get pretty complicated, so I'm glad somebody
is working on something for it :-). Good work

Cheers,

Jonathan
(PAUSE: FREQUENCY)

On Tue, Mar 24, 2009 at 6:30 AM, Paul LeoNerd Evans
<leon...@leonerd.org.uk> wrote:
> I find a number of times, that I've wanted to make some code that
> certain OSes would have better implementations of than others, or just
> plain implement in a different way.
>
> There's some existing examples of code that does this; File::Spec comes
> to mind. It chooses a specific subclass at runtime, based on the OS
> choice ($^O), or falling back on a list of decreasing specificness if
> that isn't found. Another example here would be a Linux-specific
> subclass of File::Tail that can use Inotify rather than polling for
> stat(). I've had further thoughts on things like /proc-scraping, network
> interface information, etc...
>
> What all these have in common is that $^O is used as a key to build a
> list of possible module names, and the code then tries to load and use
> the first one in the list it finds. Perhaps in cases like File::Tail
> where the OS-specific class is simply more optimal, this could be an
> optional installation later on.
>
> I'd like to write a small module for automatically doing this sort of
> magic; I'm just in short of a name for it. I feel it ought to be
> Class-y; something like
>
>   Class::OSMagic
>   Class::OSSpecific
>   Class::MagicOS
>   Class::SystemSpecific
>   Class::ForSystem
>
> As a brief example of code, consider the following hack on File::Tail.
>
> Two-line change to File/Tail.pm:
>
>  use Class::OSMagic;
>
>  # Rename constructor
>  sub __new
>  {
>     ...
>  }
>
> The 'use' line would automatically import a 'sub new' into the caller,
> which just does something like
>
>  sub new
>  {
>     Class::OSMagic::find_best_subclass( shift )->__new( @_ );
>  }
>
> The user of File::Tail need not know the difference; the normal
>
>  my $tailer = File::Tail->new( $path );
>
> constructor is unaffected.
>
> If one day someone writes an Inotify-aware Linux extension, all they
> have to do is provide
>
>  sub File::Tail::linux;  # note lowercase, to match $^O
>
>  use Linux::Inotify;
>
>  sub __new
>  {
>     ...
>  }
>
> Now, any code that tries to use File::Tail objects on a Linux machine
> will automatically find this subclass if it is installed.
>
>
> There's a suggestion that the word 'magic' should be avoided - other
> ideas on the name?
>
> --
> Paul "LeoNerd" Evans
>
> leon...@leonerd.org.uk     |    CPAN ID: PEVANS
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.9 (GNU/Linux)
>
> iD8DBQFJyLYsvLS2TC8cBo0RAig4AJ9AvIGIeEi9KQPUMMZ2hiBxKJJjCwCfXl3O
> vMATzHk4J9g2Dm/drmf1clY=
> =xSGI
> -----END PGP SIGNATURE-----
>
>

Reply via email to