- Code generation and cut and paste: unconstrained modifications
- Inheritance and passing callbacks: modifications only at the method granularity
- Normal libraries: no modification of existing algorithms - only composing them into larger constructions
Tuesday, February 17, 2009
Hierarchy of code reuse
Thursday, January 29, 2009
Reading "Design Principles and Design Patterns"
I think the real takeaway is "Stable packages should be abstract packages" - where stable for the author means 'many other packages depend on that one'. The problem with translating that to dynamic languages is that the most abstract (in the OO sense) packages, the pure interfaces don't need to be written down in code at all. Duck typing gives us a great flexibility - but it also means that there is no requirement to write down the abstract interfaces - and if there is no additional pressure then they will not be defined by the programmers.
Another problem with translating the ideas into dynamic languages is the meaning of the word 'depend'. With static typing it can be clearly defined by the need to recompile the package if there is some change in the package it depends on. For dynamic typing this needs to be defined in some more subtle ways - basing it on the type of the coupling between the packages.
Tuesday, December 02, 2008
Open Source fragmentation and cognitive biases
This made me thinking. Wouldn't that explain the fragmentation of Open Source libraries (and CPAN in particular)? Would that not explain why one author values the miniature efficiency gains of his reinvented wheel over the robustness of time-tested code?
Maybe once we know how this mechanis works, we could design better Open Source library repositories, limitting the power of that fragmentation drive? Maybe by being more explicite about our choices we can become more rational?
Thursday, October 23, 2008
Catalyst helpers - plugins for Module::Starter?
I've learned about Module::Starter plugins from Recursive development that leads nowhere.
Thursday, October 16, 2008
Progress
Thursday, August 28, 2008
One gotcha less!
Friday, June 13, 2008
DBIx::Class gotchas
DBIC is a complex beast - and it has it's rather obscure corners where it can burn the inexperienced. Here are two of those, comments with others are welcome.
Don't use $rs->update_or_create(...) (or $rs->find_or_create) on a table with autoincrement primary key
The ->find method requires that all the columns comprising the key used for the search are present in the query or in the resultsource conditions. Otherwise it will return some random record (and emit a warning). This is because currently there is no way to determine if all the needed columns are present. To do this you would have to parse the arbitrary SQL::Abstract query that can be in the resultsource condition and check how the columns are used there. Think for example about:$new_rs = $cd_rs->search( { -and => [ id => [1, 2], id => { '>' => 1 } ] } )
and then $new_rs->update_or_create( { artist => 1 } ).
But for autoincrement primary keys the ->create method requires that the primary key is not present in the query. If you provide { pk => 'undef' } to ->create, this would generate a query like: INSERT INTO cd ( pk, ...) VALUES ( NULL, ... ) - some databases would accept that but others (PostgreSQL for example) not.
So in summary, for tables with autoincrement primary keys ->find requires that you provide the primary key in the query, and ->create requires that you don't - this means that you cannot pass the same query hash to both methods and this is what ->update_or_create does.
Update: Looks like the 4773 revision fixes the problem described below. That's why I moved this point to the end of the post. I did not check it too deeply though.
Don't call $row->some_relation when the $row has not loaded the columns required to resolve some_relation
Column values in DBIC are kept in a hash - this means that a column can have some defined value, have undefined value or can be completely non-existent - and DBIC interprets all of those states differently. When $row->some_relation is called and ->some_relation uses a foreign key column that is non-existent then the result is currently random (and in the future most probably an exception will be raised).
When this can happen? When you create a row and don't provide the value for the column (or if you retrieve the row from the database and explicitelly omit the column). For example if you do $cd = $cd_rs->create( { name => "Cisza" } )
(or $cd = $cd_rs->new...). Now the 'artist' column in $cd is non-existent and when you try to call $cd->artist it blows up.
In a library where you don't know how a record was created you need to check first if the relevant columns are loaded before you call a relation on the record.
I thought that a good remedy would be also to always provide undef in the ->create and ->new calls for all the columns that we don't have values for, but allegedly this is not a good strategy (don't ask me why).
Tuesday, May 27, 2008
Installing Test::WWW::Mechanize::Catalyst
It seems that there is some incompatibility between the latest LWP version (5.812) and Test::WWW::Mechanize::Catalyst. The tests die with an:
HTTP::Message content must be bytes at lib/Test/WWW/Mechanize/Catalyst.pm line 88
error message. After downgrading LWP to 5.808 Test::WWW::Mechanize::Catalyst (version 41 - which looks better than 42 at CPAN Testers: Reports for Test-WWW-Mechanize-Catalyst) worked. Looks like this change is the culprit: "Don't allow HTTP::Message content to be set to Unicode strings".
confound - thanks for the hint.
Sunday, May 25, 2008
Interesting articles from the Ruby community
As a side-note - I cannot comment there (even though I have javascript turned on) - do you get the same problem?
Monday, April 21, 2008
Tuesday, March 04, 2008
Writing Facebook apps in Catalyst
Wednesday, January 30, 2008
Refreshing a row from the DB - another note to myself
So here it is:
$row->discard_changes;
It comes from DBIx::Class::PK (and not from DBIx::Class::Row where I usually start the serach).
Update: The core devs say that the new version of documentation will mention discard_changes in DBIx::Class::Row POD. Thanks.
Tuesday, January 29, 2008
Automatic DBIC schema creation from a database
So here is the magic invocation for DBIx::Class::Schema::Loader which do create the relationships (if you use the right switch):
perl -MDBIx::Class::Schema::Loader=make_schema_at,dump_to_dir:./lib -e make_schema_at("New::Schema::Name", { relationships => 1 }, [ "dbi:Pg:dbname=foo","postgres" ])’
Saturday, January 12, 2008
A free implementation of Amazon SimpleDB
For Amazon it would not mean much less income - since as I've said the fee for the development use of the services is rather small - but it would mean many more customers. Perhaps it would also mean some competition - but this would only validate the whole model and make it more suitable for big business which does not like so much dependence on one provider.
Sunday, December 16, 2007
Update to 'Tags and search and DBIx::Class'
I think it is a nice technique.
Saturday, December 08, 2007
Have you ever forgotten where some subroutine comes from?
Until discovering Pod::POM::Web I did not know that what I need is actually a full text search over all the Pod documents - you cut and paste the unknown method name into the search box press Enter and voila you have list of modules that document that method. And if you know that it comes from one of the DBIx::Class submodules you just add DBIx::Class to the search criteria - and don't get all the Class::DBI documentation pages. No problem with too long index lists. Someone should hack it to run against a full CPAN mirror and beat the other CPAN search websites.
Wednesday, September 12, 2007
Catalyst::Example::InstantCRUD updated to newer versions of underlying libraries
Saturday, September 08, 2007
Comment spam
Monday, July 02, 2007
Fat Model
After moving parameter validation and transactions into the Model it looks OK. I think it can lead to something enough abstracted to become a CPAN module - but for now I am sure that it'll not be as simple as DBIx::Class::Validation.
Monday, April 23, 2007
Catalyst::Controller::PathArgs
There is still need for the PathPart parameter - for the case when you have paths like "/book/$book_id/edition/$edition_id" and "/book/$book_id/edition", i.e. two paths that differ only in the number of parameters taken by the actions. Since you can have only one "edition" subroutine in the "Book" controller you need to alias a subroutine with a different name to act as if it has the name "edition" - this is what you can do with the PathPart attribute. I am tempted to also rename that one to Alias too - so that it would be more mnemonic.
Anyway the source can be downloaded from it's subdir in the Cat repository. Below is the POD for the Catalyst::Controller::PathArgs controller. And I am waiting for comments before I submit it to CPAN.
NAME
Catalyst::Controller::PathArgs - syntactic sugar for the Catalyst::DispatchType::Chained manpage.
SYNOPSIS
package MyApp::Controller::Root;
use base 'Catalyst::Controller::PathArgs';
__PACKAGE__->config->{namespace} = '';
sub pathargsroot : PathArgs(1) {}
use Catalyst::Controller::PathArgs;
package TestApp::Controller::Pathargsroot; use base 'Catalyst::Controller::PathArgs';
sub pathargsend : PathArgs(1) EndPoint { }
DESCRIPTION
This Catalyst Controller base adds two new action attributes: PathArgs (taking one numerical argument) and EndPoint. This is entirely syntactic sugar over the the Catalyst::DispatchType::Chained manpage full machinery for paths like '/book/$book_id/edition/$edition_id/view' - with PathArgs you can chain the 'book', 'edition' and 'view' methods and declare how many parameters they take. EndPoint is needed to declare an ation as the end of the chain (in theory this should be computable - but for now I don't see any easy way to do that).
This package uses the Class::C3 manpage this means that you cannot use NEXT in classes based on it - but C3 looks like a good replacement for NEXT.
To declare that the book subroutine is the root chained action with one argument you need to declare it in the Root controller with:
sub book : PathArgs(1) { If we had a non chained path with /book/edition - the edition sub would be declared in the 'Book' controller - and this is the same case here - you just add PathArgs(1) to indicate that it is indeed chained and that it takes one parameter. So in the Book controller you add:
sub edition : PathArgs(1) { For the last action in the chain you need to add EndPoint. So in the Book::Edition controller you would need:
sub view : PathArgs(0) EndPoint { You can also mix PathArgs with PathPart (new in Catalyst 5.7007). For example if you wanted to have an action responding for the address ``/book/$book_id/edition'' you would need a subroutine called 'edition' in the Book controller, but there is already one routine called 'edition' in that controller. What you can do in that case is make a sub with a different name and declare that from the outside it's name should be really 'edition':
sub edition_mascarade: PathPart('edition') PathArgs(0) EndPoint { yeah - you need to add EndPoint there as well.
An example is included in the example directory of this distribution.
Internally PathArgs and EndPoint are converted to 'Chained(.)' and appriopriate CaptureArgs or Args attributes. For more sophisticated chaining you might need to use the Catalyst::DispatchType::Chained manpage directly.
create_action
This is the overriden method from Catalyst::Controller used here to compute the new attributes.
BUGS
SUPPORT
AUTHOR
Zbigniew Lukasiak
CPAN ID: ZBY
http://perlalchemy.blogspot.com/
COPYRIGHT
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the LICENSE file included with this module.