Thursday 24 June 2010

File::Spit

John in my office a couple of days ago said we need the function 'spit' for writing to files much like we have 'slurp' in Perl6 (or by using one of my 3 fave cpan module Perl6::Slurp)

Since I have just had a couple of hours, I have just done this. File::Spit exports automatically the symbol 'spit'.


This method takes a file_path, $data and an optional delimiter flag.

From the POD:

spit:

will croak if once it has a file_path and a possible delimiter, it finds no data (note, this is different from an empty string or 0)

delimiter - if the delimiter matches against /\A[\s:=,.\/;]+\z/xms, it will be used, else it will just append to the file
perl false values (undef, q{} or 0) will be classified as though there is no delimiter given

will croak if it fails to write, with value of $EVAL_ERROR

Write to file, killing any previous versions of file (note, no warnings)

eval {
spit ( $FilePath, $data );
} or do {
your error handling here...
};

Append to file, creating if needed, but no delimiter

eval {
spit ( $FilePath, $string, 1 ); # note, it is just a true value, any perl false values will use write and kill previous file
} or do {
your error handling here...
};

Append as above, but with delimiter

eval {
spit ( $FilePath, $string, qq{\n\n} );
} or do {
your error handling here...
};

On success, this returns a true value (1)

This is probably completely unnecessary, or already exists on CPAN. If it doesn't, I'm happy to push to it, but for now, you can get it from github

http://github.com/setitesuk/File--Spit/tree/v0.1

This in theory could work with any type of data, but the tests only check strings.

I'm off on holiday now.

Happy Coding

Andy

Wednesday 16 June 2010

Is there anything wrong with this?

So, we all think reusing other code and not reinventing the wheel is generally a good thing.

And using Moose is generally good.

So, I want to test if something is an object. I am using Moose.

1) Create a large hash to compare keys against, and then do


my $not_object_ref = {
HASH => 1, ARRAY => 1, GLOB => 1,...
};

my $is_object;
if ( my $ref = ref $object ) {
if ( ! $not_object_ref->{$ref} ) {
$is_object++;
}
}

# stuff that uses boolean value of $is_object


2) Use a Moose Attribute and eval


has q{_i_am_an_object} => (
isa => q{Object},
is => q{rw},
);

sub _is_object {
my ( $self, $object ) = @_;
my $is_object = 0;
eval {
$self->_i_am_an_object( $object ); # test if this is an object
$is_object++;
} or do {}; # I like PBP and perl critic :)
return $is_object;
}

my $is_object = $self->_is_object( $object );
# stuff that uses boolean value of $is_object


I don't know if this is a pure abuse of the Moose Attribute system, or if there is a much neater way of doing it, but certainly it has merit over the whole keeping track of what refs are not objects. And certainly, if you want to check against the object type, you change the isa to the class name, and give it a better method name.

It's probably more of an abuse of eval :)

Andy

Thursday 10 June 2010

When not to shift...

I'm not a big fan of 'shift @array'. And I have just sealed why I think that is.

Anyone who has looked at my code will see that my methods always use array assignments
sub my_method {
my ( $self, $arg_refs ) = @_;
}

Even if it is just $self, rather than
sub my_method {
my $self = shift;
}

Today, I further found another bug whilst testing. I'm trying out Test::MockObject, and know that I want to return an arrayref, with 1 element in the array.

The code loops through 8 times, and I expect a result from this array each time, since the webservices I am mocking would provide this.

However, in my tests, I get a result of 1 true, rather than 8.

Why is this?

I check the arrayrefs are the same with some debug (they are). I check the array length each time through. 1st time, 1. All other 7, 0.

The reason is that instead of just assigning
my $ref_seq = $arrayref->[0];

I have shifted
my $ref_seq = shift @{ $arrayref };

So of course, I have within the code removed the element off the array, rather than leave it there, and since $arrayref goes out of scope in the code as soon as $ref_seq is assigned, either works.

This is one time when I would expect the 'real world' to have still been fine, but my 'test environment' can't cope.

Obviously, there are times when shift is most appropriate, i.e. you deliberately need to truncate out the first element because you must not allow that to get somewhere else as the array carries on, but that niggling little voice that keeps telling me never to shift has finally had a reason to give me.

Still, liking Test::MockObject :)