Ever since I got my terminals and mutt all working well with international characters, I've been fascinated by the Chinese spam I get. First of all it looks neat to see in a terminal. But sometimes I throw it into google translate just to see what it is I'm getting spammed about, and every now and then it's mildly interesting. Take this for example:
任可一种管理绩效的产生,首先都是原于一种先进的管理理念。而任何一种先进的管理理念都必须有一种适合它的管理模式作为载体。人们似乎都很乐意去接受先进的理念,并且善于以最惊人的速度去传播。可是人们在践行的过程中得到的结果却是参差不齐。就象丰田的精益理念早就传遍了整个世界一样,而世界却始终未能复制出第二个“丰田”。这究竟是为什么呢?主要原因在于人们虽然已经接受了新的理念,却没有能够找到其精髓的所在。因此也就无法去设计一种适合自身需要的管理模式来作为载体
Which translates (probably very poorly since it is machine translation, but good enough for bloggin') to:
Either a management performance can be produced, first of all are the original in an advanced management concept. The possession of any advanced Management philosophy that it must have a suitable management model as a carrier. People seem very willing to accept advanced ideas And good at the most to spread at an alarming rate. But people in the course of practice the results obtained is mixed. On Like Toyota's lean philosophy had already spread throughout the world as the world has never been able to replicate the second "Toyota." Is this why? Although the main reason is that people have accepted the new idea, but not able to find its essence Lies. Therefore will not be able to design a management model for their own needs as a carrier.
As someone who has been involved with companies who adopt Lean-like philosophies, I couldn't agree more!
(er... Actually I meant to post this sometime back in like February 2010. Oh well!)
I attended the Orlando Perl Workshop 2010 and had a lovely time. The talks I attended were:
And... I got to see aligators! Well... things that looked like them anyway.
(insert photo here)
My whirlwind trip wasn't too stressful, as it turned out. I hung out mostly with Sartak and Miyagawa, and made lots of progress on Continuity::Adapt::PSGI. Lots of side-discussion on all sorts of things too, of course.
It was a good weekend!
I saw some article about HTML::FormHandler, and decided I'd give it a try. I'm probably not really using it as intended... and I'm also not pushing this confluence of tech nearly as far as it can go.
#!/usr/bin/perl
use strict;
use MooseX::Declare;
use KiokuDB;
use Continuity;First we just pull in some libraries. We'll use MooseX::Declare for fun :) . Now let's make a lovely base class for our forms, to set up some good defaults an an updater.
# Base class for all forms
class Form
extends HTML::FormHandler {
has owner => (is => 'rw');
our $form_count = 0;
has '+name' => ( default => sub { return "f-" . $form_count++ } );
has '+html_prefix' => ( default => 1 );
method update {
if($self->validated) {
my $v = $self->value;
foreach my $field (keys %$v) {
eval { # ignore validation issues :)
$self->owner->$field($v->{$field})
if $self->owner->can($field);
}
}
}
}
}That stuff about the form name is so we can display multiple forms on a page, each with it's own unique name. The update method ties my form to my actual object. I ignore errors for now... though really that's losing a big part of what HTML::FormHandler provides.
class BasicPersonForm
extends Form
with HTML::FormHandler::Render::Table {
has '+field_list' => ( default => sub {[
name => 'Text',
birthday => 'Text',
save => { type => 'Submit', value => 'Save' },
]});
}Here I'm building on my Form base, making a form specific for my Person class. This is declaratively specifying which fields to show and in what order, along with a lovely save button. In theory I'll be able to expand this into subforms and compose them and so on.
Though I'm roughly OK with listing inputs for the form, it annoys me to have to specify the types. That, at at least a basic level, should be readable from the fields to which this form is connected. So one thing I'm noodling is using the rendering and validation, but importing the types from the data class. I think the Form::Processor::Model::DBIC does this a bit.
class Person {
use MooseX::Types::DateTimeX qw( DateTime );
has name => ( is => 'rw', default => sub { '' } );
has birthday => ( is => 'rw', isa => DateTime, coerce => 1 );
method basic_form { BasicPersonForm->new( owner => $self, init_object => $self ) }
}My Person class is straightforward. I used the DateTimeX thingie to auto coerce stuff magically. And that basic_form method is just a helper to create a form for a given instance.
sub main {
my $r = shift;
my $db = KiokuDB->connect(
'dbi:SQLite:phone.db',
create => 1
);
my $scope = $db->new_scope;
# This is a new person, pending some data
my $new_person = Person->new;
while(1) {
my @people = $db->grep(sub { ref($_) eq 'Person' })->all;
my @forms = map { $_->basic_form } @people;
foreach my $form (@forms) {
$r->print($form->render);
}
$r->print("<h3>Add person:</h3>");
my $new_person_form = $new_person->basic_form;
$r->print($new_person_form->render);
$r->next;
my $params = { $r->params };
foreach my $form (@forms) {
$form->process( $params );
$form->update;
$db->update( $form->owner );
}
$new_person_form->process( $params );
$new_person_form->update;
if($new_person->name) {
$db->insert( $new_person );
# And now queue up another new one
$new_person = Person->new;
}
}
}This is a little Continuity app, so main gets called and passed $r, which is the request handle. After setting up our KiokuDB (with SQLite backend), I enter an endless loop of showing the forms and the processing the results. Oh, and I create a special Person instance for holding a new person.
In the loop, I grab all the people objects in the DB at once (this is a demo, so I skipped iterator/paging stuff), make a form for each, and then render the forms. I also render the new-person object in case they want to add a new one.
Next I call '$r->next', which waits for the user to submit the forms. This is Continuity magic, which inverts the web app to make it more like an interactive command line prompt. You can kinda think of this line as "$input = <STDIN>". Once that comes back I put the submitted data into a variable and use it to update each of the forms (and updating each back into the database).
Finally I check to see if they submitted data for the New-Person, and if there is anything I insert it into the DB.
# Get things going
Continuity->new->loop;Last but not least, we start the Continuity loop, which starts looking for requests and calling main() for each new session.
So I found this all pretty interesting, and it overlaps with some of my other object-rendering experiments. I could probably add to this for pulling field metadata from objects into forms and organizing subforms and so on. Maybe next time :)
So at work we're switching over to Mercurial (hg), and I'm trying out some of the more advanced features. One which I've been looking forward to for a while is 'bisect' (which git and others have also).
The idea is straightforward. I have a unit test that fails. I know that it worked like a month ago or something. Someone committed something between then and now that made it fail. But what was it? Bisect will systematically help find it -- start in the middle, and if it was good there go back half of the remaining time. If bad, go forward. In just a few chops like this it will narrow down to the exact commit that caused an issue.
This works well in Mercurial (and Git) because it is really really fast to revert to a previous version of your code. By far the longest part of the process in the process was executing the unit test itself!
Here are the steps I went through. I'm using Mercurial 4.3, by the way.
bwilcox@wickedwitch:~/dev-rel172$ hg bisect -rFirst I "reset" the bisect. That just means, let's begin!
bwilcox@wickedwitch:~/dev-rel172$ hg bisect -bNow I marked the current revision as "bad", since my test fails.
bwilcox@wickedwitch:~/dev-rel172$ hg bisect -g 51303
Testing changeset 51497:3f631045f30d (196 changesets remaining, ~7 tests)
124 files updated, 0 files merged, 26 files removed, 0 files unresolvedI looked back at history before I started this and decided that this test definitely passed at revision 51303 -- that was just before our last release and all the tests passed. So here I'm saying that I know for _sure_ that it was "good" at revision 51303.
Now comes the fun part.
bwilcox@wickedwitch:~/dev-rel172$ hg bisect -c 'bin/test_suite.pl bin/t/default/pnr_phase1/14-task_acquisition_approval.t | grep PASS'
Changeset 51497:3f631045f30d: bad
Result: PASS
Changeset 51404:8b0f3381e3f5: good
Changeset 51449:f3b668e05928: bad
Changeset 51415:ebc770d284d3: bad
Result: PASS
Changeset 51409:dfd5706dc765: good
Result: PASS
Changeset 51412:e33660e38ea0: good
Result: PASS
Changeset 51413:d1390b75856f: good
Changeset 51414:d39f58b490ab: bad
The first bad revision is:
changeset: 51414:d39f58b490ab
user: chiggins
date: Tue May 18 21:34:51 2010 +0000
summary: RT: https://rt.liquidation.com/Ticket/Display.html?id=733702In case it isn't clear, the command that I ran is:
hg bisect -c 'bin/test_suite.pl bin/t/default/pnr_phase1/14-task_acquisition_approval.t | grep PASS'This instructs Mercurial to keep going, and use my test_suite.pl command to decide whether a particular revision is "good" or "bad". The "-c" parameter runs what you give it and looks at the exit status to decide if it is good or bad. It just so happens that the "grep" command returns exit status depending on whether it found something :) . So I'm grepping for the "PASS" that comes at the end of a standard perl test suite to indicate that the current revision is good.
And then off it runs! Test... bad. Test... good. Test... bad. And so on, narrowing it down to the exact revision which was the first to fail the test!
From there I took a look at that revision, and immediately saw what the problem was. Easily fixed, and now my test suite passes with a clean bill of health.
Aw hells yes.
META INFORMATION: This is the technical blog and wiki of Brock Wilcox (awwaiid). Entries focus on my current projects, interests, and sometimes life events. If you'd like you can check out the list of All Entries or the RSS Feed. I also have a LiveJournal syndication feed for LJ friends.
2 Comments.
Hmmm, the documentation on mercurials wiki seems to be out of date. http://mercurial.selenic.com/wiki/BisectExtension?action=show
When you run the test through -c is that using a static script from the initial revision or does that test need to be in all the revisions, possibly altering the script if it was changed in a previous revision? I would think it uses a static script, in which case it would mean that you don't necessarily have to have the test in the 'good' revision but can create it after the fact.
-- lungching 2010-06-09 12:32 UTC
In the example I provided, my test case is actually located inside of my repository. Thus each execution is indeed running the version of the test from the currently selected revision. In this case I like that, because the test itself might have broken and I'd like to detect that case.
If, however, you need a static test, you can just point to something outside of your repository and it should work the way you describe.
-- awwaiid 2010-06-09 16:11 UTC
2 Add Comment