Docendo discimus

$self->explain

  • Calendar

    July 2017
    M T W T F S S
    « Sep    
     12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31  
  • Archives

  • Recent Posts

  • Bling

Posts Tagged ‘Catalyst’

Vedalken: the Magic Librarian

Posted by brunorc on April 5, 2010

Dawn's Reflection

Dawn's Reflection - a simple, one color spell, but it makes your life really colorful!

Finally I decided to get back to my Magic DB and describe the process of creating it here, on my blog. So here we go:

mkdir vedalken
cd vedalken
catalyst.pl Vedalken

Marisi's Twinclaws

Marisi's Twinclaws - Multicolor with a choice; and a double-strike killer

Now I have the skeleton for the Catalyst app, so it can be stored in the git repository. Why? Simply because it’s a good idea to store the code in the repository. I have to get some sleep after being completely killed after the Tangerine Dream concert in Zootermeer, so there’s no time to elaborate on that now. So, while I’m still in ‘vedalken’ – the main directory of my project – I type:

git init

Now the empty Git repository has been created in the current directory. Since it’s empty, I want to add my Catalyst skeleton to it:

git add -A

The -A flag stands for “all”, as we can be told by git help add (every command of git is nicely explained in git help command). All files are now indexed by Git, so it will pay attention to all the changes, introduced to them. Adding a file is also a change; and changes have to be committed – a commit actually stores changes in the Git repository.

Blaze

Blaze - A spell with variable cost

git commit -a -m "Initial commit; created the Catalyst skeleton"

This time is the -a flag which means “all”; the -m flag specifies the commit message. If it was ommitted, the default editor would be launched, since a commit without message is barely useless…

Reaper King

Reaper King - How much for the color?

Now I can use all the power of Git to maintain the project and keep it growing. My plan is to have a list of cards I own, with a list of decks. And since Magic is a collectible card game, a wishlist may be a nice addition…

cd Vedalken
script/vedalken_create.pl controller Card
script/vedalken_create.pl controller Deck

A bunch of views may be useful:

script/vedalken_create.pl view ViewTT TT
script/vedalken_create.pl view ViewJSON JSON

I don’t have a model yet, since I was thinking for quite a long time about the representation of mana cost – without finding any good solution. Mana cost is the amount of mana (magical energy) you have to spend to cast the particular spell. If you take a look at Dawn’s Reflection, you will see that you have to spend one green mana and three mana of any color (you can spend four green mana – it’s also OK) to cast it.

Budoka Gardener

Budoka Gardener - or Dokai, Weaver of Life

That is easy. But then we have something more complicated – Marisi’s Twinclaws.

To summon those kitties you have to pay one green mana, one red or white mana, and two mana of any color. This may be quite important, because the colors of mana define the color of the card. If the spell may “destroy target white creature”, it will smash your Twinclaws, even if you didn’t use white mana to cast it.

Boom or Bust

Boom or Bust - you choose

Another important aspect of mana is the CMC, which means “converted mana cost”. Both Dawn’s Reflection and Marisi’s Twinclaws have CMC equal to 4. But then comes the Blaze.

Surprisingly, the CMC of Blaze is 1, since you *can* actually cast it for one red mana; it just won’t harm anyone, because of dealing 0 damage (there may be a situation, when such move makes sense). But the X cost is important, since it has to be – for instance – graphically rendered on the page.

This way we come to the pinacle of mana representation problems: the Reaper King.

To have Reaper King on your side, you have to spend one mana of each of the five Magic colors. No blue mana? No problem, just pay two mana of any color. That way this card has CMC equal to 10.

I wanted to have a system of storing mana cost in such a way, that would allow me to:

  • represent the “mixed” mana,
  • represent the “one-or-many” mana,
  • filter cards by color,
  • automatically calculate the mana cost.

I’m going to use Moose to achieve it, since Moose classes and attributes allow to hide all the complexity (or gory details) under a nice interface. I hope it will also make it possible to represent the flip cards from Kamigawa block and multi-part cards:

package Vedalken::Mana;
use Moose;

has [ qw/white green red blue black colorless variable/ ] => (
    is => 'rw',
    isa => 'Int',
    default => 0,
);

It may be a little bit overkill (if any visitor has any advice, I’d like to improve this design), but that way Moose will take care of checking all the keys and values on runtime. Also, it makes it easier to specify the list of attributes that share the same attributes. Below I include a commented (using the multiline “=begin/=end” comment) example of another way, based on TypeConstraints.

package Vedalken::Spell;
use Moose;
use Moose::Util::TypeConstraints;

enum 'SpellType' = qw/
    Artifact
    Basic
    Creature
    Enchantment
    Instant
    Land
    Legendary
    Planeswalker
    Plane
    Snow
    Sorcery
    Tribal
    World
/;

enum 'Rarity' = ( qw/
    Rare
    Uncommon
    Common
    Land
    Special
    Promo
/, "Mythic Rare" );

=begin Alternative

my %colors = map { $_ => 1 } qw/
    White
    Red
    Green
    Blue
    Black
    Colorless
    Variable
/;

subtype 'Mana'
    => as 'Hash',
    => where {
        not grep { not exists $colors{$_} } keys %$_
        and
        not grep { $_ !~ /^[0-9]+$/ } values %$_
    };

=end Alternative

has name => (
    is => 'rw',
    isa => 'Str',
);

has mana_cost => (
    is => 'rw',
    isa => 'Array[Vedalken::Mana]', # or 'Array[Mana]'
);

has cmc => (
    is => 'rw',
    isa => 'Int',
);

has types => (
    is => 'rw',
    isa => 'Array[SpellType]',
);

has subtypes => (
    is => 'rw',
    isa => 'Array[SpellSubtype]',
);

has [ qw/text flavor/ ] => (
    is => 'rw',
    isa => 'Str',
);

has [ qw/power toughness/ ] => (
    is => 'rw',
    isa => 'Int',
);

has rarity => (
    is => 'rw',
    isa => 'Rarity',
);

package Vedalken::Card;
use Moose;

has name => (
    is => 'rw',
    isa => 'Str',
);

has spells => (
    is => 'rw',
    isa => 'HashRef[Vedalken::Spell]',
);

has quantity => (
    is => 'rw',
    isa => 'Int',
);

That way one card can have many spells (we shouldn’t need more than two, but it’s Magic, so you never know for sure). Later we can add a method which would tell us if the card includes two completely independent spells, or it’s a flip card (Kamigawa specific).

package Vedalken::Collection;
use Moose;

has items => (
    is => 'rw',
    isa => 'HashRef[CollectionItem]',
);

has quantity => (
    is => 'rw',
    isa => 'Int',
);

The generic Collection can serve as a basis for the Deck object, as well as for the wishlist and the whole collection.

The advantage of using Moose is – again – that you declare in your package all the information about types (which get checked on runtime) and coertion from other types (so you can expect an Object of type Vedalken::Whatever, but still be able to get an ordinary hash and use it, as long as it meets all conditions). Yeah, in Java or C++ you take it for granted. But on the other hand, it’s still Perl, so you can use all its magic and power plus the joys of strong typing. You declare more, but you write less code. Code, which is usually just the reinvented wheel for checking, if the user input is an integer.

Posted in Moose | Tagged: , , , , | Leave a Comment »

Catalyst is easy – using the database

Posted by brunorc on September 19, 2009

There was not too much about doing the Catalyst things recently. I went into some musings about Perl: why it is cool, relevant and blah.

But recently I had a nice conversation with a friend, who works in the same company. He has a strong Java background, but frankly it didn’t turn him into a brainless, corporative ant. It’s quite interesting, but even now, when I work in the Perl-driven company, I find myself having conversations with Java people :-) And those conversations are mostly nice, so maybe that’s why I keep having them. Or maybe just those people are interesting and nice, regardless of their favourite programming language? Nevertheless, this guy also plays Magic – and he’s quite good at this. So there’s at least one thing that really unites us.

Anyway, I like his pragmatic point of view. And this conversation gave me the impulse to once again think about coolness and relevancy. A programming language is cool and relevant, if it helps you in writing programs, that solve your problems. If you can do it in a fast and consistent, elegant manner, then everything is OK. This compels me to cut my musings and go back to the real Perl.

First “useful” application shown here was a non-persistent life counter for a duel of Magic planeswalkers. If someone liked to make it more persistent, he would probably think about the database – you know, those huge things Oracle used to sell before people discovered that SQL must die, because Erlang is cooler. But for the Magic counter we don’t need Oracle, SQLite will be quite enough.

Now let’s go to the application directory – I assume you are able to type in your console:

sqlite3 magicount.db

and get output similar to this one:

SQLite version 3.4.0
Enter ".help" for instructions
sqlite>

which roughly translates to it works! If it doesn’t, go to the link above, download the SQLite for your operating system, install it and try again. If it works for you as well, it is the time to create the database and populate it:

sqlite> CREATE TABLE player ( id INTEGER PRIMARY KEY, name TEXT );
sqlite> INSERT INTO player (name) VALUES ('Bruno');
sqlite> INSERT INTO player (name) VALUES ('Betka');
sqlite> INSERT INTO player (name) VALUES ('Chris');
sqlite> INSERT INTO player (name) VALUES ('Giel');
sqlite> .quit

In SQLite, INTEGER PRIMARY KEY means that field will be autoincremented, so we don’t need to specify the value for id. After quitting we can check if there’s something inside:

sqlite3 magicount.db
SQLite version 3.4.0
Enter ".help" for instructions
sqlite> select * from player;
1|Bruno
2|Betka
3|Chris
4|Giel
sqlite>

Who would expect, eh?

Now it is the time to create the new Model for the database. It is achieved by the following incantation:

script/magicount_create.pl model MyModelName DBIC::Schema MySchemaClass create=static dbi:DB_type:how_to_get_the_DB

MyModelName looks rather obvious – it is the name of the model; it will be used later to access it, so it should be meaningful. MySchemaClass is – sure – the name of the class, representing the DB schema. The create option can have two values: static and dynamic, but since nowadays you can recreate your DB-based classes without losing the code written by yourself, static is the best choice. The last argument is the DSN, used by underlying DBI module – it should include the type of the database (so DBI can use the appropriate driver) and the way to access it (if you want some more elaborated description, check the documentation of the DBIC::Schema helper). So, in the end, everything should look like this:

script/magicount_create.pl model MCDB DBIC::Schema MagiCount::Schema create=static dbi:SQLite:magicount.db

MCDB stands for MagiCount DataBase – not very fancy, but quite short. We use the SQLite driver and give the name of the file, where the database is stored. If everything is OK and you have installed all necessary modules (you can check the list here – usually they will be installed with the most important one, Catalyst::Model::DBIC::Schema, but this list may be handy in case of obstacles), you should get the similar output:

exists "/Users/bruno/devel/MagiCount/script/../lib/MagiCount/Model"
exists "/Users/bruno/devel/MagiCount/script/../t"
Dumping manual schema for MagiCount::Schema to directory /Users/bruno/devel/MagiCount/script/../lib ...
Schema dump completed.
created "/Users/bruno/devel/MagiCount/script/../lib/MagiCount/Model/MCDB.pm"
created "/Users/bruno/devel/MagiCount/script/../t/model_MCDB.t"

Go take a look at the created files – probably the most interesting one will be lib/MagiCount/Schema/Result/Player.pm:

package MagiCount::Schema::Result::Player;

use strict;
use warnings;

use base 'DBIx::Class';

__PACKAGE__->load_components("InflateColumn::DateTime", "Core");
__PACKAGE__->table("player");
__PACKAGE__->add_columns(
  "id",
  {
    data_type => "INTEGER",
    default_value => undef,
    is_nullable => 1,
    size => undef,
  },
  "name",
  {
    data_type => "TEXT",
    default_value => undef,
    is_nullable => 1,
    size => undef,
  },
);
__PACKAGE__->set_primary_key("id");


# Created by DBIx::Class::Schema::Loader v0.04006 @ 2009-09-19 15:06:06
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:R0fDKDbCt11OQ9KmMzHd/Q


# You can replace this text with custom content, and it will be preserved on regeneration
1;

As you can see, it is the Perl representation of the SQL code. Thanks to this Perl is aware of the structure of tables and all fields included. Also, the library that powers this stuff – DBIx::Class – is not only able to create such files from the existing database; you can use it the other way round, shaping your database with the Perl code, as DBIx::Class will create the structure of tables described in modules (check the documentation for DBIC). Also, you can freely add your code below the MD5 sum line and it will be maintained.

This all looks cool, but there’s a lot of stuff behind and around it, so now I will only show how to use it on a very simple example. Instead of writing the names of players in the form, we’re going to use the HTML select elements. In the create.tt2 file we can change:

      <label for="player1">Name of the first player</label>
      <input type="text" name="player1" size="12" /><br />
 

to:

      <label for="player1">Name of the first player</label>
      <select name="player1">
        [% FOREACH player IN c.model('MCDB::Player').all %]
        <option value="[% player.name %]">[% player.name %]</option>
        [% END %]
      </select><br />
 

doing the same for the second player. And if we want to have players ordered alphabetically:

        [% FOREACH player IN c.model('MCDB::Player').all.sort('name') %]
        <option value="[% player.name %]">[% player.name %]</option>
        [% END %]
 

Of course we’re accessing Model from the View and doubling the amount of database calls. But at least our players are persistent! In the next episode: updating the contents of the table.

Posted in Catalyst for intimidated | Tagged: , , , , , , | Leave a Comment »

YAPC::EU 2009 recap

Posted by brunorc on August 9, 2009

Four days packed with Perl, Portuguese food, warm Chartreuse, cold beer and even more Perl! It was really nice to meet Legendary Perl Creatures, see some friends and got to know more Perl people.

But what was even more important, was the content. Everyone was using words like Moose, Catalyst, DBIC or five-dot-ten (well, some well known hackers were also using other words, starting with 0xF), and presentations were full of new ideas. It was not about some magic artefacts, that can explode in your hand if you tamper with them in the wrong way. It was not about CGI. It was not about Perl obfuscation and the (ab)use of some fancy and “meaningful” operators.

Instead I saw Damian Conway talking about Regexp::Grammars. You’ve probably heard about Ruby and maybe even get fed up with the whole DSL stuff. Now you can build the parser and get the abstract tree – all using meaningful regular expressions. Yes, meaningful regular expressions. Thanks to the named captures you don’t have to rely on $1, $2, ... variables. But in Regexp::Grammars you can use named subrules as well, so your parser really doesn’t have to be hairy. Oh, and you can even make it easy to debug, as it is able to notify you about errors. Then you get a nice, minimalistic syntax tree.

Yes, I agree, most of us don’t spend their days writing parsers. But still, there’s a lot of nice things to be discovered. Paul Fenwick went with a talk about awesome things in Perl. Of course he mentioned Moose, but I was really surprised with the autobox and autodie things. Such things show how Perl evolves – in contrary to its critics, apparently, who still find it relevant to point out that you have to manually unroll the @_ list.

Of course you have to, unless you use Moose with MooseX::Declare! Ah, you have to use it… is it a problem? Well, you can write your own solution by hand if you don’t trust this guy. Or you can start to complaint, because it’s not part of the core of Perl. And it should be, since it is so important for oneliners you launch from your command line, isn’t it?

OK, we don’t have to unroll the @_ anymore. Also, we can use threads. And exceptions. And they are not part of the core again. But you know what? The topic of this YAPC was Corporate Perl. And there were people from Cisco, Nagra, Opera, Booking, Sapo – and they went to tell us how they use Perl and want to use it even more, so they would like to hire more Perl developers. And apparently they weren’t worried about exceptions being used from a module. Looks like their main concern is how to get more and more talented, open-minded Perl programmers, because – yes, you guessed it – they are not the part of the core and you still have to unroll them manually.

Oh really? There was a bunch of famous Perl hackers, but there also was an awful lot of people from mailing lists, IRC channels, Perl Mongers communities. And they may be part of the core, as there is a lot of projects that don’t require a rocket-science level, so everyone can participate. Also, they went to YAPC to learn something, to get some books, to discover new things.

I especially liked the Thursday, with the workshop led by two gentlemen from Shadowcat Systems. There were some bits about Catalyst, Moose and DBIx::Class and a lot of Royal Navy spirit, provided by inimitable, faster than a shutter Matt S. Trout, who also signed (as a co-author) a copy of the new book about Catalyst that was sold for some horrible amount of the European currency, but you can get one from Amazon for the regular retail price; no fancy stuff from Matt though, but you can still carry it to the next YAPC in Pisa (get familiar with the city, attend the Italian Perl Workshop in October, it’s really worthy) and ask him to sign it, making him feel like a Tom Jones.

And last but not least – Jose Castro gave a brilliant keynote, ending it with a phrase we somehow felt in the air: Perl is Alive and Kicking, and Stronger than ever!

Posted in Catalyst, Moose, Perl | Tagged: , , , , , , , , , | 1 Comment »