From: root Date: Sun, 19 Apr 2009 15:51:39 +0000 (-0400) Subject: import moose website X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2Fmoose-website.git;a=commitdiff_plain;h=720accfe768c0af3dfbe188975e79a925f68f995 import moose website --- 720accfe768c0af3dfbe188975e79a925f68f995 diff --git a/Moose.pdf b/Moose.pdf new file mode 100644 index 0000000..358b420 Binary files /dev/null and b/Moose.pdf differ diff --git a/Moose_YAPC_Asia_2008/.practical_moose.s5.swp b/Moose_YAPC_Asia_2008/.practical_moose.s5.swp new file mode 100644 index 0000000..a0430c8 Binary files /dev/null and b/Moose_YAPC_Asia_2008/.practical_moose.s5.swp differ diff --git a/Moose_YAPC_Asia_2008/practical_moose.html b/Moose_YAPC_Asia_2008/practical_moose.html new file mode 100644 index 0000000..cec8138 --- /dev/null +++ b/Moose_YAPC_Asia_2008/practical_moose.html @@ -0,0 +1,1275 @@ + + + + + + +Moose + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+
+
+
+ +
+ +
+

Moose

+

+

Yuval Kogman

+

+
+ + +
+

Moose Is Not

+ +
    +
  • Experimental
  • +
  • A toy
  • +
  • Just another accessor builder
  • +
  • A source filter
  • +
  • Perl black magic
  • +
  • Perl 6 in Perl 5
  • +
+ +
+ +
+

Moose Is

+ +
    +
  • A complete modern object framework for Perl
  • +
+ +
+ +
+

Moose Is

+ +
    +
  • Syntactic Sugar for Class::MOP
  • +
  • Rich ancestry +
      +
    • CLOS (Common Lisp Object System)
    • +
    • Smalltalk
    • +
    • Alces latifrons
    • +
    • Perl 6
    • +
    • …
    • +
  • +
  • Stable & Production ready
  • +
  • Polite, incremental
  • +
+ +
+ +
+

A Simple Example

+ +

+package Person;
+
+use strict;
+use warnings;
+
+sub new {
+    my ( $class, @args ) = @_;
+
+    @args = %{$args[0]} if @args == 1;
+
+    return bless {
+        @args,
+    }, $class;
+}
+
+sub name {
+    my ($self, @args) = @_;
+    $self->{name} = $args[0] if @args;
+    return $self->{name};
+}
+
+sub age {
+    my ($self, @args) = @_;
+    $self->{age} = $args[0] if @args;
+    return $self->{age}; 
+}
+
+1;
+
+ +
+ +
+

A Simple Moose Example

+ +

+package Person;
+use Moose;
+
+has name => (is => 'rw');
+has age  => (is => 'rw');
+
+1;
+
+ +
+ +
+

A Simple Moose Example (cont.)

+ +
    +
  • use Moose; +
      +
    • imports keywords
    • +
    • use strict; use warnings;
    • +
    • @ISA = qw(Moose::Object) unless @ISA
    • +
  • +
+ +
+ +
+

A Simple Moose Example (cont.)

+ +
    +
  • has declares attributes

    + +
      +
    • generates accessors
    • +
    • is => 'rw' → read/write accessor
    • +
    • is => 'ro' → read only accessor
    • +
    • writer, reader
    • +
  • +
  • new inherited from Moose::Object

  • +
+ +
+

Now we’re going to discuss more features of the attributes

+
+
+ +
+

Variations on a Moose Example

+ +

+package Manager;
+use Moose;
+
+has name => (
+    is  => 'rw',
+    isa => 'Str',
+    default => 'Bob'
+);
+
+has staff => (
+    is      => 'ro',
+    isa     => 'ArrayRef',
+    lazy    => 1,
+    default => sub { [qw(Bob Alice Tim)] },
+);
+
+ +
+

Adds default, isa

+
+
+ +
+

Variations on a Moose Example (cont.)

+ +
    +
  • default is a

    + +
      +
    • code reference
    • +
    • or non-reference (numbers, strings)
    • +
    • used when no parameter is given to new
    • +
  • +
  • lazy delays default

    + +
      +
    • called on first usage of $object->staff
    • +
    • not inside new
    • +
  • +
+ +
+

discusses default

+ +

non refs make accidental sharing hard

+
+
+ +
+

Variations on a Moose Example (cont.)

+ +
    +
  • isa specifies a type +
      +
    • Moose::Util::TypeConstraints +
        +
      • Any, Item, Bool, Undef, Defined, Value, Num, Int, Str, Ref, ScalarRef, ArrayRef, HashRef, CodeRef, RegexpRef, GlobRef, FileHandle, Object and Role
      • +
    • +
    • Types don’t need to exist
    • +
  • +
+ +

+            has 'date' => (isa => 'DateTime'); # DWIM
+
+ +
+

isa, type constraints

+
+
+ +
+

Typical Family

+ +
    +
  • Types have a hierarchy +
      +
    • Item ⊃ Defined ⊃ Ref ⊃ Object
    • +
  • +
+ +

+        subtype 'Ref'
+            => as 'Defined'
+            => where {  ref($_) };
+
+        subtype 'Object'
+            => as 'Ref'
+            => where { blessed($_) }
+
+ +
+

type hierarchy

+
+
+ +
+

Conventional Delegates

+ +

+package Employee;
+use Moose;
+extends qw(Person);
+
+has manager =>  (
+    is  => 'ro',
+    isa => 'Manager',
+    handles => {
+        manager_name => 'name',
+        coworkers    => 'staff',
+    }
+);
+
+ +
    +
  • manager handles certain methods for Employee +
      +
    • $emp->coworkers == $emp->manager->staff
    • +
  • +
+ +
+ +
+

Conventional Delegates (cont.)

+ +

+has phone => (
+    ...
+    handles => [qw(number extension)],
+);
+
+ +
+ +
+

Conventional Delegates (cont.)

+ +

+has phone => (
+    ...
+    isa     => "Phone",
+    handles => qr/^[a-z]w+$/,
+);
+
+ +
+ +
+

Conventional Delegates (cont.)

+ +

+has phone => (
+    ...
+    handles => "Dialing", # a role
+);
+
+ +
+ +
+

UnConventional Delegates

+ +

+package Company;
+use Moose;
+use MooseX::AttributeHelpers;
+
+has employees => (
+    metaclass => 'Collection::Array',
+    isa => 'ArrayRef[Employees]',
+    is  => 'rw',
+    provides => {
+        push  => 'add_employee',
+        pop   => 'remove_employee',
+        count => 'number_of_employees',
+        empty => 'any_employees',
+    },
+);
+
+ +
+ +
+

Modified Methods

+ +

+before 'employees' => sub { warn 'calling employees' };
+
+after 'employees' => sub { warn 'finished calling employees' };
+
+ +
    +
  • Pre/Post hooks +
      +
    • Get a copy of @_
    • +
    • Return value is ignored
    • +
  • +
+ +
+ +
+

Modified Methods (cont.)

+ +

+around 'employees' => sub { 
+    my ($next, $self, @args) = @_;
+    ...
+    my @return = $self->$next(@args);
+    ...
+    return @return;
+};
+
+ +
+ +
+

Modified Methods (cont.)

+ +

+package Employee;
+use Moose;
+
+sub do_work {
+    my $self = shift;
+
+    $self->punch_in;
+
+    inner(); # call subclass here
+
+    $self->punch_out;
+}
+
+ +
+ +
+

Modified Methods (cont.)

+ +

+package Employee::Chef;
+use Moose;
+
+extends qw(Employee);
+
+augment do_work => sub {
+    my $self = shift;
+
+    while ( @burgers ) {
+        $self->flip_burger(shift @burgers);
+    }
+};
+
+$chef->do_work; # punch in, flip burgers, punch out
+
+ +
+ +
+

Some Type of Coercion

+ +

+package Employee;
+use Moose;
+use Moose::Util::TypeConstraints;
+extends qw(Person);
+
+class_type 'Manager';
+
+coerce 'Manager' => (
+    from 'Str' => via { Manager->new( name => $_ ) },
+);
+
+has manager => (
+    is => 'ro',
+    isa => 'Manager',
+    required => 1, 
+    coerce => 1,
+);
+
+ +
+ +
+

Some Type of Coercion (cont.)

+ +

+# import type constraint keywords
+use Moose::Util::TypeConstraints;
+
+
+# define Manager, a subtype of Object
+class_type "Manager";
+
+
+# define the conversion
+... via { Manager->new( name => $_ ) }
+
+
+# enable it per attribute
+has manager => (
+    ...
+    coerce => 1,
+);
+
+ +
+

breakdown of the example

+ +

class types are automatically created for all Moose classes

+
+
+ +
+

Some Type of Digression

+ +

+has employees => (
+    is => 'rw',
+    isa => 'ArrayRef[Employee]',
+);
+
+has shopping_carts => (
+    is => 'rw',
+    isa => 'ArrayRef[ArrayRef[ShinyBead]]'
+);
+
+ +
+

Going to go into features of the type system for a bit

+ +

Parametrized types

+
+
+ +
+

Some Type of Digression (cont.)

+ +

+has language => (
+    is => 'rw',
+    isa => 'English | Welsh | Scots | Gaelic',
+);  
+
+has member => (
+    is => 'rw',
+    isa => 'Employee | ArrayRef[ Employee | Group ]',
+);
+
+ +
+

Union types

+
+
+ +
+

Some Type of Digression (cont.)

+ +

+package Foo;
+use Moose;
+use Moose::Util::TypeConstraints;
+
+use Test::Deep qw(eq_deeply ...);
+
+type 'SomethingTricky' => where {
+    eq_deeply( $_, ... );
+};
+
+has 'bar' => (
+    is  => 'rw',
+    isa => 'SomethingTricky',
+);
+
+ +
+

Test::Deep custom validator

+ +

Can use any validation from the CPAN

+
+
+ +
+

Some Parametrized Type of Coercion

+ +

+use Moose::Util::TypeConstraints;
+
+subtype 'ArrayRef[Employee]' => as 'ArrayRef';
+
+coerce 'ArrayRef[Employee]' => (
+    from 'ArrayRef[Str]' via {
+        [ map { Employee->new( name => $_ ) } @$_ ]
+    },
+);
+
+has staff => (
+    isa    => 'ArrayRef[Employee]',
+    coerce => 1,
+);
+
+ +
+

coerce parametrized ArrayRef[Employee] from ArrayRef[Str]

+
+
+ +
+

Role of the Moose

+ +
    +
  • A role is like a… +
      +
    • Java Interface: safe
    • +
    • mixin: useful
    • +
  • +
  • A role is for small reusable behaviors +
      +
    • better than using a multiple inheritence
    • +
  • +
+ +
+ +
+

Role of the Moose (cont.)

+ +
    +
  • Roles on the CPAN: +
      +
    • MooseX::Clone - Flexible clone method
    • +
    • MooseX::Storage - Flexible serialization
    • +
    • MooseX::Getopt - @ARGV aware constructor
    • +
    • MooseX::LogDispatch - $self->logger->info("something happenned")
    • +
    • MooseX::Param - param method like CGI.pm’s,
    • +
  • +
+ +
+

Some examples of small reusable behaviors

+ +

Param is good for interacting with e.g. CGI::Expand or similar modules

+
+
+ +
+

Role of the Moose (cont.)

+ +

+package Minion;
+use Moose;
+
+extends qw(Employee);
+
+with qw(Salaried::Hourly);
+
+
+package Boss;
+use Moose;
+
+extends qw(Employee);
+
+with qw(Salaried::Monthly);
+
+
+ +
    +
  • with adds roles into your class +
      +
    • Salaried::Hourly was added to Minion
    • +
  • +
+ +
+ +
+

Role of the Moose (cont.)

+ +

+package Salaried;
+use Moose::Role;
+
+requires 'paycheck_amount';
+
+ +
    +
  • Just an interface
  • +
+ +
+ +
+

Role of the Moose (cont.)

+ +

+package Salaried::Hourly;
+use Moose::Role;
+
+with qw(Salaried);
+
+has hourly_rate => (
+    isa => "Num",
+    is  => "rw",
+    required => 1,
+);
+
+has logged_hours => (
+    isa => "Num",
+    is  => "rw",
+    default => 0,
+);
+
+# satisfy the Salaried interface:
+sub paycheck_amount {
+    my $self = shift;
+    $self->logged_hours * $self->hourly_rate;
+}
+
+
+ +
    +
  • More than an interface
  • +
+ +
+ +
+

Role of the Moose (cont.)

+ +
    +
  • More than Java Interfaces +
      +
    • Interfaces are behavior “contracts”
    • +
    • Roles can also have code
    • +
  • +
+ +
+

roles can have attributes and methods +roles provide behavior, not just interface

+
+
+ +
+

Role of the Moose (cont.)

+ +
    +
  • Role Composition +
      +
    • Not inheritence
    • +
    • Symmetric
    • +
    • Unordered
    • +
  • +
+ +
+ +
+

Role of the Moose (cont.)

+ +
    +
  • Role Composition +
      +
    • Less ambiguity
    • +
    • Compile time errors
    • +
    • …And ways to fix them
    • +
  • +
+ +
+

symmetric composition means no precedence - if two roles try to define the same thing you get a compile time error that needs to be resolved +multiple inheritence silently assumes you want the first class

+ +

roles cause errors at compile time, unlike multiple inheritence

+ +

roles also provide easy ways to fix the errors

+
+
+ +
+

Role of the Moose (cont.)

+ +

+package Ballet;
+use Moose::Role;
+
+sub dance {
+    pirouette();
+}
+
+package Punk;
+use Moose::Role
+
+sub dance {
+    MOSH!!!11one();
+}
+
+package Foo;
+use Moose;
+
+# KABOOM:
+with qw(
+    Punk
+    Ballet
+);
+
+ +
+

conflicts

+
+
+ +
+

Role of the Moose (cont.)

+ +

+package Ent::Puppy;
+use Moose;
+
+with (
+    Tree => {
+        alias => {
+            bark => "tree_bark",
+        },
+    },
+    Dog => {
+        alias => {
+            bark => "bark_sound",
+        }
+    },
+);
+
+sub bark {
+    my $self = shift;
+
+    if ( $condition ) {
+        $self->tree_bark;
+    } else {
+        $self->bark_sound;
+    }
+}
+
+ +
    +
  • Not that common in practice
  • +
+ +
+

Composition parameters +Easier conflict resolution +Finer grained control

+
+
+ +
+

MOPs Mean Cleanliness

+ +
    +
  • Moose is based on Class::MOP +
      +
    • Metaobject Protocol for Perl 5
    • +
    • “makes an object for everything”
    • +
  • +
+ +

+my $class = $obj->meta;       # $obj's metaclass
+my $meta  = MyApp->meta;      # MyApp's metaclass
+my $emo   = $obj->meta->meta; # even more meta!
+
+warn  $obj->meta->name;
+
+ +
+ +
+

Looking in From the Inside

+ +

+my $metaclass = $self->meta; 
+
+$metaclass->superclasses;
+
+$metaclass->linearized_isa;
+
+$metaclass->has_method("foo");
+
+$metaclass->compute_all_applicable_attributes;
+
+# … lots more
+
+ +
+

simple introspection

+
+
+ +
+

Looking in From the Inside (cont.)

+ +

+Moose::Meta::Class->create( Bar =>
+      version      => '0.01',
+      superclasses => [ 'Foo' ],
+      attributes => [
+          Moose::Meta::Attribute->new( bar => ... ),
+          Moose::Meta::Attribute->new( baz => ... ),
+      ],
+      methods => {
+          calculate_bar => sub { ... },
+          construct_baz => sub { ... }
+      },
+);
+
+my $anon_meta = Moose::Meta::Class->create_anon_class( ... );
+
+ +
+

Classes can be created programmatically

+
+
+ +
+

Looking in From the Inside (cont.)

+ +

+has foo => ( is => "rw" );
+
+__PACKAGE__->meta->add_attribute(
+    "foo",  
+    is => "rw",
+);
+
+ +
    +
  • Moose is just sugar +
      +
    • The MOP does the hard work
    • +
  • +
+ +
+ +
+

The Metaclass Tango

+ +
    +
  • Metaclassses control class behavior
  • +
+ +

+has employees => (
+    metaclass => 'Collection::Array',
+    ...
+);
+
+ +
    +
  • custom attribute metaclasses +
      +
    • change how attributes work
    • +
  • +
  • Many customizable parts +
      +
    • Moose::Meta::Class, Moose::Meta::Attribute,Moose::Meta::Method, Moose::Meta::Method::Accessor Moose::Meta::Instance, Moose::Meta::Role, Moose::Meta::TypeConstraint, …,
    • +
  • +
+ +
+ +
+

Working in the Meta Frame

+ +
    +
  • $work project:
  • +
  • CMS for a flash website
  • +
  • Content is in XML
  • +
+ +
+ +
+

Working in the Meta Frame (cont.)

+ +
    +
  • Step 1. use Moose
  • +
  • Step 2. ???
  • +
  • Step 3. Profit!
  • +
+ +
+ +
+

Working in the Meta Frame (cont.)

+ +
    +
  • Step 2.1. Client’s XML schemas → Moose classes +
      +
    • Automatic class definitions
    • +
    • High level objects in runtime
    • +
    • XML storage backed +
        +
      • SAX → Moose
      • +
      • Moose → SAX
      • +
    • +
  • +
+ +
+ +
+

Working in the Meta Frame (cont.)

+ +
    +
  • Step 2.2. Meta descriptions +
      +
    • Extend the metaclasses
    • +
    • Embed additional information +
        +
      • field types
      • +
      • access control
      • +
    • +
  • +
+ +
+ +
+

Working in the Meta Frame (cont.)

+ +
    +
  • Step 2.3 Introspection goodness +
      +
    • Generic web frontend
    • +
    • Object introspection based +
        +
      • HTML view
      • +
      • Editing widgets
      • +
    • +
    • Clean, extensible
    • +
  • +
+ +
+ +
+

Drawbacks of Moose

+ +
    +
  • Load time +
      +
    • MooseX::Compile is in the works
    • +
  • +
  • Some features are slow +
      +
    • but you only pay for what you use
    • +
  • +
  • Extending non-Hash based classes is tricky. +
      +
    • but possible: MooseX::GlobRef::Object
    • +
  • +
+ +
+ +
+

Benefits of Moose

+ +
    +
  • Less boilerplate +
      +
    • attribute storage/access
    • +
    • construction
    • +
    • destruction
    • +
    • verification
    • +
    • …
    • +
  • +
+ +
+ +
+

Benefits of Moose (cont.)

+ +
    +
  • Shorter +
      +
    • less reading
    • +
    • less writing
    • +
    • less code means fewer bugs
    • +
  • +
+ +
+ +
+

Benefits of Moose (cont.)

+ +
    +
  • Less testing +
      +
    • Moose is very well tested +
        +
      • no need to check accessor behavior, etc
      • +
    • +
    • focus on your code’s purpose +
        +
      • not that it is “assembled” correctly
      • +
      • http://c2.com/cgi/wiki?IntentionNotAlgorithm
      • +
    • +
  • +
+ +
+ +
+

Benefits of Moose (cont.)

+ +
    +
  • More readable +
      +
    • declarative style is self documenting
    • +
    • good signal to noise ratio
    • +
  • +
+ +
+ +
+

Benefits of Moose (cont.)

+ +
    +
  • Meta object protocol +
      +
    • Cleans up Perl’s OO
    • +
    • Provides introspection
    • +
    • Enables powerful abstractions
    • +
  • +
+ +
+ +
+

Benefits of Moose (cont.)

+ +
    +
  • It’s the new black +
      +
    • All the cool kids hang out on #moose
    • +
    • Smart sounding buzzwords
    • +
    • Chicks dig antlers
    • +
    • Ruby is so 2007
    • +
  • +
+ +
+ +
+

Bonus Material

+ +
+ +
+

Autobox

+ +

+package Units::Bytes;
+use Moose::Role;
+use Moose::Autobox;
+
+sub bytes     { $_[0]                   }
+sub kilobytes { $_[0] * 1024            }
+sub megabytes { $_[0] * 1024->kilobytes }
+sub gigabytes { $_[0] * 1024->megabytes }
+sub terabytes { $_[0] * 1024->gigabytes }
+
+Moose::Autobox->mixin_additional_role(
+    SCALAR => 'Units::Bytes',
+);
+
+ +
+ +
+

Autobox (cont.)

+ +

+use Units::Bytes;
+use Moose::Autobox; # autoboxing is lexical
+
+is(5->bytes,     5,             '... got 5 bytes');
+is(5->kilobytes, 5120,          '... got 5 kilobytes');
+is(2->megabytes, 2097152,       '... got 2 megabytes');
+is(1->gigabytes, 1073741824,    '... got 1 gigabyte');
+is(2->terabytes, 2199023255552, '... got 2 terabytes');
+
+ +
+ +
+

perl -Moose

+ +
    +
  • Moose One Liners with oose.pm
  • +
+ +

+perl -Moose -e 'has foo => ( is=> "rw" ); Class->new( foo => 1 )'
+
+ +
    +
  • Useful for testing if something works
  • +
  • Helpful on IRC
  • +
  • Devel::REPL is cooler though ;-)
  • +
+ +
+ +
+

MooseX::POE

+ +

+package Counter;
+use MooseX::POE;
+use MooseX::AttributeHelpers;
+
+has count => (
+    traits => [qw(Counter)],
+    provides => { inc => "increment_count" },
+);
+
+sub START {
+    shift->yield('increment');
+}
+
+event increment => sub {
+    my $self = shift;
+
+    warn "Count is now " . $self->count;
+
+    $self->increment_count;
+    $self->yield('increment') unless $self->count > 3;
+};
+
+Counter->new( count => 0 );
+POE::Kernel->run();
+
+ +
    +
  • PoCos made easy
  • +
  • Every object has a POE::Session
  • +
  • event declares POE object states
  • +
+ +
+ +
+

Fin

+ +
    +
  • Slides written by:

    + +
      +
    • Chris Prather
    • +
    • Stevan Little
    • +
    • Robert Boone
    • +
  • +
  • Slides deleted by:

    + +
      +
    • Yuval Kogman
    • +
  • +
+ +
+ + +
+ + + diff --git a/Moose_YAPC_Asia_2008/practical_moose.s5 b/Moose_YAPC_Asia_2008/practical_moose.s5 new file mode 100644 index 0000000..df65e4d --- /dev/null +++ b/Moose_YAPC_Asia_2008/practical_moose.s5 @@ -0,0 +1,1057 @@ +Title: Moose +Location: YAPC::Asia::2008 +Presenter: Yuval Kogman +Date: 2008 +Theme: moose + +Moose Is Not +============ + +* Experimental +* A toy +* Just another accessor builder +* A source filter +* Perl black magic +* Perl 6 in Perl 5 + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Moose Is +======== + +* A complete modern object framework for Perl + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Moose Is +======== + +* Syntactic Sugar for `Class::MOP` +* Rich ancestry + * CLOS (Common Lisp Object System) + * Smalltalk + * Alces latifrons + * Perl 6 + * … +* Stable & Production ready +* Polite, incremental + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +A Simple Example +================ + +

+package Person;
+
+use strict;
+use warnings;
+
+sub new {
+    my ( $class, @args ) = @_;
+
+    @args = %{$args[0]} if @args == 1;
+
+    return bless {
+        @args,
+    }, $class;
+}
+
+sub name {
+    my ($self, @args) = @_;
+    $self->{name} = $args[0] if @args;
+    return $self->{name};
+}
+
+sub age {
+    my ($self, @args) = @_;
+    $self->{age} = $args[0] if @args;
+    return $self->{age}; 
+}
+
+1;
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +A Simple Moose Example +====================== + +

+package Person;
+use Moose;
+
+has name => (is => 'rw');
+has age  => (is => 'rw');
+
+1;
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +A Simple Moose Example (cont.) +============================== + +* `use Moose;` + * imports keywords + * `use strict; use warnings;` + * `@ISA = qw(Moose::Object) unless @ISA` + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +A Simple Moose Example (cont.) +============================== + +* `has` declares attributes + * generates accessors + * `is => 'rw'` → read/write accessor + * `is => 'ro'` → read only accessor + * `writer`, `reader` + +* `new` inherited from `Moose::Object` + + +########## + +Now we're going to discuss more features of the attributes + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Variations on a Moose Example +============================= + +

+package Manager;
+use Moose;
+
+has name => (
+    is  => 'rw',
+    isa => 'Str',
+    default => 'Bob'
+);
+
+has staff => (
+    is      => 'ro',
+    isa     => 'ArrayRef',
+    lazy    => 1,
+    default => sub { [qw(Bob Alice Tim)] },
+);
+
+########## + +Adds default, isa + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Variations on a Moose Example (cont.) +===================================== + +* `default` is a + * code reference + * or non-reference (numbers, strings) + * used when no parameter is given to `new` + +* `lazy` delays `default` + * called on first usage of `$object->staff` + * not inside `new` + +########## +discusses default + +non refs make accidental sharing hard + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Variations on a Moose Example (cont.) +===================================== + +* `isa` specifies a type + * `Moose::Util::TypeConstraints` + * `Any, Item, Bool, Undef, Defined, Value, Num, Int, Str, Ref, ScalarRef, ArrayRef, HashRef, CodeRef, RegexpRef, GlobRef, FileHandle, Object and Role` + * Types don't need to exist +

+            has 'date' => (isa => 'DateTime'); # DWIM
+
+########## + +isa, type constraints + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Typical Family +============== + +* Types have a hierarchy + * `Item` ⊃ `Defined` ⊃ `Ref` ⊃ `Object` + +

+        subtype 'Ref'
+            => as 'Defined'
+            => where {  ref($_) };
+
+        subtype 'Object'
+            => as 'Ref'
+            => where { blessed($_) }
+
+########## + +type hierarchy + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Conventional Delegates +====================== + +

+package Employee;
+use Moose;
+extends qw(Person);
+    
+has manager =>  (
+    is  => 'ro',
+    isa => 'Manager',
+    handles => {
+        manager_name => 'name',
+        coworkers    => 'staff',
+    }
+);
+
+ +* manager `handles` certain methods for `Employee` + * `$emp->coworkers` == `$emp->manager->staff ` + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Conventional Delegates (cont.) +============================== + +

+has phone => (
+    ...
+    handles => [qw(number extension)],
+);
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Conventional Delegates (cont.) +============================== + +

+has phone => (
+    ...
+    isa     => "Phone",
+    handles => qr/^[a-z]\w+$/,
+);
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Conventional Delegates (cont.) +============================== + +

+has phone => (
+    ...
+    handles => "Dialing", # a role
+);
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +UnConventional Delegates +======================== + +

+package Company;
+use Moose;
+use MooseX::AttributeHelpers;
+   
+has employees => (
+    metaclass => 'Collection::Array',
+    isa => 'ArrayRef[Employees]',
+    is  => 'rw',
+    provides => {
+        push  => 'add_employee',
+        pop   => 'remove_employee',
+        count => 'number_of_employees',
+        empty => 'any_employees',
+    },
+);
+
+✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Modified Methods +================ + +

+before 'employees' => sub { warn 'calling employees' };
+
+after 'employees' => sub { warn 'finished calling employees' };
+
+ +* Pre/Post hooks + * Get a copy of `@_` + * Return value is ignored + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Modified Methods (cont.) +======================== + +

+around 'employees' => sub { 
+    my ($next, $self, @args) = @_;
+    ...
+    my @return = $self->$next(@args);
+    ...
+    return @return;
+};
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Modified Methods (cont.) +======================== + +

+package Employee;
+use Moose;
+
+sub do_work {
+    my $self = shift;
+    
+    $self->punch_in;
+    
+    inner(); # call subclass here
+    
+    $self->punch_out;
+}
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Modified Methods (cont.) +======================== + +

+package Employee::Chef;
+use Moose;
+
+extends qw(Employee);
+
+augment do_work => sub {
+    my $self = shift;
+    
+    while ( @burgers ) {
+        $self->flip_burger(shift @burgers);
+    }
+};
+
+$chef->do_work; # punch in, flip burgers, punch out
+
+✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Some Type of Coercion +===================== + +

+package Employee;
+use Moose;
+use Moose::Util::TypeConstraints;
+extends qw(Person);
+
+class_type 'Manager';
+
+coerce 'Manager' => (
+    from 'Str' => via { Manager->new( name => $_ ) },
+);
+
+has manager => (
+    is => 'ro',
+    isa => 'Manager',
+    required => 1, 
+    coerce => 1,
+);
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Some Type of Coercion (cont.) +============================= + +

+# import type constraint keywords
+use Moose::Util::TypeConstraints;
+
+
+# define Manager, a subtype of Object
+class_type "Manager";
+
+
+# define the conversion
+... via { Manager->new( name => $_ ) }
+
+
+# enable it per attribute
+has manager => (
+    ...
+    coerce => 1,
+);
+
+ +########## + +breakdown of the example + +class types are automatically created for all Moose classes + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Some Type of Digression +======================= + +

+has employees => (
+    is => 'rw',
+    isa => 'ArrayRef[Employee]',
+);
+
+has shopping_carts => (
+    is => 'rw',
+    isa => 'ArrayRef[ArrayRef[ShinyBead]]'
+);
+
+ +########## + +Going to go into features of the type system for a bit + +Parametrized types + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ +Some Type of Digression (cont.) +=============================== + +

+has language => (
+    is => 'rw',
+    isa => 'English | Welsh | Scots | Gaelic',
+);  
+
+has member => (
+    is => 'rw',
+    isa => 'Employee | ArrayRef[ Employee | Group ]',
+);
+
+ +########## + +Union types + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Some Type of Digression (cont.) +=============================== + +

+package Foo;
+use Moose;
+use Moose::Util::TypeConstraints;
+
+use Test::Deep qw(eq_deeply ...);
+
+type 'SomethingTricky' => where {
+    eq_deeply( $_, ... );
+};
+
+has 'bar' => (
+    is  => 'rw',
+    isa => 'SomethingTricky',
+);
+
+ +########## + +Test::Deep custom validator + +Can use any validation from the CPAN + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Some Parametrized Type of Coercion +================================== + +

+use Moose::Util::TypeConstraints;
+
+subtype 'ArrayRef[Employee]' => as 'ArrayRef';
+
+coerce 'ArrayRef[Employee]' => (
+    from 'ArrayRef[Str]' via {
+        [ map { Employee->new( name => $_ ) } @$_ ]
+    },
+);
+
+has staff => (
+    isa    => 'ArrayRef[Employee]',
+    coerce => 1,
+);
+
+ +########## + +coerce parametrized ArrayRef[Employee] from ArrayRef[Str] + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose +================= + +* A role is like a… + * Java Interface: safe + * mixin: useful +* A role is for small reusable behaviors + * better than using a multiple inheritence + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +* Roles on the CPAN: + * `MooseX::Clone` - Flexible `clone` method + * `MooseX::Storage` - Flexible serialization + * `MooseX::Getopt` - `@ARGV` aware constructor + * `MooseX::LogDispatch` - `$self->logger->info("something happenned")` + * `MooseX::Param` - `param` method like `CGI.pm`'s, + +########## + +Some examples of small reusable behaviors + +Param is good for interacting with e.g. CGI::Expand or similar modules + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +

+package Minion;
+use Moose;
+
+extends qw(Employee);
+
+with qw(Salaried::Hourly);
+
+
+package Boss;
+use Moose;
+
+extends qw(Employee);
+
+with qw(Salaried::Monthly);
+
+
+ +* `with` adds roles into your class + * `Salaried::Hourly` was added to `Minion` + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +

+package Salaried;
+use Moose::Role;
+
+requires 'paycheck_amount';
+
+ +* Just an interface + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +

+package Salaried::Hourly;
+use Moose::Role;
+
+with qw(Salaried);
+
+has hourly_rate => (
+    isa => "Num",
+    is  => "rw",
+    required => 1,
+);
+
+has logged_hours => (
+    isa => "Num",
+    is  => "rw",
+    default => 0,
+);
+
+# satisfy the Salaried interface:
+sub paycheck_amount {
+    my $self = shift;
+    $self->logged_hours * $self->hourly_rate;
+}
+
+
+ +* More than an interface + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +* More than Java Interfaces + * Interfaces are behavior "contracts" + * Roles can also have code + +########## +roles can have attributes and methods +roles provide behavior, not just interface + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +* Role Composition + * Not inheritence + * Symmetric + * Unordered + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +* Role Composition + * Less ambiguity + * Compile time errors + * …And ways to fix them + +########## +symmetric composition means no precedence - if two roles try to define the same thing you get a compile time error that needs to be resolved +multiple inheritence silently assumes you want the first class + +roles cause errors at compile time, unlike multiple inheritence + +roles also provide easy ways to fix the errors + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +

+package Ballet;
+use Moose::Role;
+
+sub dance {
+    pirouette();
+}
+
+package Punk;
+use Moose::Role
+
+sub dance {
+    MOSH!!!11one();
+}
+
+package Foo;
+use Moose;
+
+# KABOOM:
+with qw(
+    Punk
+    Ballet
+);
+
+ +########## + +conflicts + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Role of the Moose (cont.) +========================= + +

+package Ent::Puppy;
+use Moose;
+
+with (
+    Tree => {
+        alias => {
+            bark => "tree_bark",
+        },
+    },
+    Dog => {
+        alias => {
+            bark => "bark_sound",
+        }
+    },
+);
+
+sub bark {
+    my $self = shift;
+    
+    if ( $condition ) {
+        $self->tree_bark;
+    } else {
+        $self->bark_sound;
+    }
+}
+
+ +* Not that common in practice + +########## + +Composition parameters +Easier conflict resolution +Finer grained control + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +MOPs Mean Cleanliness +===================== + +* Moose is based on `Class::MOP` + * Metaobject Protocol for Perl 5 + * "makes an object for everything" + +

+my $class = $obj->meta;       # $obj's metaclass
+my $meta  = MyApp->meta;      # MyApp's metaclass
+my $emo   = $obj->meta->meta; # even more meta!
+
+warn  $obj->meta->name;
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Looking in From the Inside +=========================== + +

+my $metaclass = $self->meta; 
+
+$metaclass->superclasses;
+
+$metaclass->linearized_isa;
+
+$metaclass->has_method("foo");
+
+$metaclass->compute_all_applicable_attributes;
+
+# … lots more
+
+########## + +simple introspection + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Looking in From the Inside (cont.) +================================== + +

+Moose::Meta::Class->create( Bar =>
+      version      => '0.01',
+      superclasses => [ 'Foo' ],
+      attributes => [
+          Moose::Meta::Attribute->new( bar => ... ),
+          Moose::Meta::Attribute->new( baz => ... ),
+      ],
+      methods => {
+          calculate_bar => sub { ... },
+          construct_baz => sub { ... }
+      },
+);
+
+my $anon_meta = Moose::Meta::Class->create_anon_class( ... );
+
+ +########## + +Classes can be created programmatically +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Looking in From the Inside (cont.) +================================== + +

+has foo => ( is => "rw" );
+
+__PACKAGE__->meta->add_attribute(
+    "foo",  
+    is => "rw",
+);
+
+ +* Moose is just sugar + * The MOP does the hard work + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +The Metaclass Tango +=================== + +* Metaclassses control class behavior + +

+has employees => (
+    metaclass => 'Collection::Array',
+    ...
+);
+
+ +* custom attribute metaclasses + * change how attributes work +* Many customizable parts + * `Moose::Meta::Class`, `Moose::Meta::Attribute, ``Moose::Meta::Method`, `Moose::Meta::Method::Accessor` `Moose::Meta::Instance`, `Moose::Meta::Role`, `Moose::Meta::TypeConstraint`, …, + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Working in the Meta Frame +========================= + +* `$work` project: +* CMS for a flash website +* Content is in XML + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Working in the Meta Frame (cont.) +================================= + +* Step 1. use Moose +* Step 2. ??? +* Step 3. Profit! + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Working in the Meta Frame (cont.) +================================= + +* Step 2.1. Client's XML schemas → Moose classes + * Automatic class definitions + * High level objects in runtime + * XML storage backed + * SAX → Moose + * Moose → SAX + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Working in the Meta Frame (cont.) +================================= + +* Step 2.2. Meta descriptions + * Extend the metaclasses + * Embed additional information + * field types + * access control + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Working in the Meta Frame (cont.) +================================= + +* Step 2.3 Introspection goodness + * Generic web frontend + * Object introspection based + * HTML view + * Editing widgets + * Clean, extensible + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Drawbacks of Moose +================== + +* Load time + * `MooseX::Compile` is in the works +* Some features are slow + * but you only pay for what you use +* Extending non-Hash based classes is tricky. + * but possible: `MooseX::GlobRef::Object` + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Benefits of Moose +================= + +* Less boilerplate + * attribute storage/access + * construction + * destruction + * verification + * … + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Benefits of Moose (cont.) +========================= + +* Shorter + * less reading + * less writing + * less code means fewer bugs + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Benefits of Moose (cont.) +========================= + +* Less testing + * Moose is very well tested + * no need to check accessor behavior, etc + * focus on your code's purpose + * not that it is "assembled" correctly + * http://c2.com/cgi/wiki?IntentionNotAlgorithm + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Benefits of Moose (cont.) +========================= + +* More readable + * declarative style is self documenting + * good signal to noise ratio + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Benefits of Moose (cont.) +========================= + +* Meta object protocol + * Cleans up Perl's OO + * Provides introspection + * Enables powerful abstractions + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Benefits of Moose (cont.) +========================= + +* It's the new black + * All the cool kids hang out on #moose + * Smart sounding buzzwords + * Chicks dig antlers + * Ruby is so 2007 + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Bonus Material +============== + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Autobox +======= + +

+package Units::Bytes;
+use Moose::Role;
+use Moose::Autobox;
+
+sub bytes     { $_[0]                   }
+sub kilobytes { $_[0] * 1024            }
+sub megabytes { $_[0] * 1024->kilobytes }
+sub gigabytes { $_[0] * 1024->megabytes }
+sub terabytes { $_[0] * 1024->gigabytes }
+
+Moose::Autobox->mixin_additional_role(
+    SCALAR => 'Units::Bytes',
+);
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Autobox (cont.) +=============== + +

+use Units::Bytes;
+use Moose::Autobox; # autoboxing is lexical
+
+is(5->bytes,     5,             '... got 5 bytes');
+is(5->kilobytes, 5120,          '... got 5 kilobytes');
+is(2->megabytes, 2097152,       '... got 2 megabytes');
+is(1->gigabytes, 1073741824,    '... got 1 gigabyte');
+is(2->terabytes, 2199023255552, '... got 2 terabytes');
+
+ +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +perl -Moose +=========== + +* Moose One Liners with `oose.pm` + +

+perl -Moose -e 'has foo => ( is=> "rw" ); Class->new( foo => 1 )'
+
+ +* Useful for testing if something works +* Helpful on IRC +* `Devel::REPL` is cooler though ;-) + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +MooseX::POE +=========== + +

+package Counter;
+use MooseX::POE;
+use MooseX::AttributeHelpers;
+
+has count => (
+    traits => [qw(Counter)],
+    provides => { inc => "increment_count" },
+);
+
+sub START {
+    shift->yield('increment');
+}
+
+event increment => sub {
+    my $self = shift;
+
+    warn "Count is now " . $self->count;
+
+    $self->increment_count;
+    $self->yield('increment') unless $self->count > 3;
+};
+
+Counter->new( count => 0 );
+POE::Kernel->run();
+
+ +* PoCos made easy +* Every object has a `POE::Session` +* `event` declares POE object states + +✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ + +Fin +=== + +* Slides written by: + * Chris Prather + * Stevan Little + * Robert Boone + +* Slides deleted by: + * Yuval Kogman diff --git a/Moose_YAPC_Asia_2008/ui/default/blank.gif b/Moose_YAPC_Asia_2008/ui/default/blank.gif new file mode 100644 index 0000000..75b945d Binary files /dev/null and b/Moose_YAPC_Asia_2008/ui/default/blank.gif differ diff --git a/Moose_YAPC_Asia_2008/ui/default/bodybg.gif b/Moose_YAPC_Asia_2008/ui/default/bodybg.gif new file mode 100755 index 0000000..5f448a1 Binary files /dev/null and b/Moose_YAPC_Asia_2008/ui/default/bodybg.gif differ diff --git a/Moose_YAPC_Asia_2008/ui/default/framing.css b/Moose_YAPC_Asia_2008/ui/default/framing.css new file mode 100644 index 0000000..2a27daf --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/framing.css @@ -0,0 +1,22 @@ +/* The following styles size, place, and layer the slide components. + Edit these if you want to change the overall slide layout. + The commented lines can be uncommented (and modified, if necessary) + to help you with the rearrangement process. */ + +/* target = 1024x768 */ + +div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} +div#header {top: 0; height: 3em; z-index: 1;} +div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;} +.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;} +div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} +div#controls form {text-align: right; width: 100%; margin: 0;} +#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z-index: 10;} +html>body #currentSlide {position: fixed;} + +/* +div#header {background: #FCC;} +div#footer {background: #CCF;} +div#controls {background: #BBD;} +div#currentSlide {background: #FFC;} +*/ diff --git a/Moose_YAPC_Asia_2008/ui/default/iepngfix.htc b/Moose_YAPC_Asia_2008/ui/default/iepngfix.htc new file mode 100644 index 0000000..bba2db7 --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/iepngfix.htc @@ -0,0 +1,42 @@ + + + + + \ No newline at end of file diff --git a/Moose_YAPC_Asia_2008/ui/default/notes.css b/Moose_YAPC_Asia_2008/ui/default/notes.css new file mode 100644 index 0000000..5858cf2 --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/notes.css @@ -0,0 +1,122 @@ +/* Following are the note styles -- edit away! */ + +body { + margin: 0; + padding: 1.0em; + background: #333; + color: #FFF; + font: 2em/1.4em 'Lucida Grande', Verdana, sans-serif; +} + +div.timers { + background: #FFF; + color: #333; + border: 0.08em solid #222; + border-top-width: 1px; + border-left-width: 1px; + float: left; + padding: 0.2em; + margin: 0 0 0.5em; + position: relative; +} + +div.timers h1 { + text-align: left; + font-size: 0.6em; + line-height: 1.4em; + background-color: #FF9; + padding: 0 0.75em; + margin: 0.25em 0 0; + border: 1px solid #EE8; +} + +div.timers div.controls { + position: absolute; + right: 0.25em; + top: 0.1em; + line-height: 1em; +} + +div.timers h1 a { + text-decoration: none; + color: #000; +} + +div.timers div.controls a { + font-size: 0.5em; + padding: 0; + color: #330; +} + +div.timers a.control { + position: absolute; + text-decoration: none; + padding: 0 0.25em; + color: #AAA; + outline: 0; +} + +#minus { + left: 0.25em; +} + +#plus { + right: 0.25em; +} + +.overtime { + background: yellow; + color: red; + border: 3px solid; + padding: 0.1em 0.25em; + font-weight: bold; +} + +div.timers h2 { + font-size: 0.6em; + line-height: 1.0em; + font-weight: normal; + margin: 0 0 -0.25em; + padding-top: 0.5em; + color: #666; +} + +div.timers p {margin: 0; padding: 0 0.5em;} +div.timers form {margin: 0;} + +div.timers span.clock { + font-family: monospace; +} + +div.timers ul {margin: 0; padding: 0; list-style: none;} +div.timers li {float: left; width: 5em; margin: 0; padding: 0 0.5em; + text-align: center;} + +div#elapsed {width: 12.1em;} +div#remaining {clear: left; width: 12.1em;} +div#remaining p {text-align: center;} + +#slide, +#next, +#notes, +#nextnotes { + font-size: 0.75em; + line-height: 1.4em; + clear: left; +/* max-width: 30.0em; */ + text-shadow: 0.1em 0.1em 0.1em #111; +} + +#next {margin-top: 2.5em;} +#next, #nextnotes { + color: #999; + font-size: 0.66em; +} + +em.disclaimer { + color: #666; +} + +div.collapsed h1 {display: block; font-size: 0.33em;} +div.collapsed h1 a {display: inline;} +div.collapsed * {display: none;} diff --git a/Moose_YAPC_Asia_2008/ui/default/opera.css b/Moose_YAPC_Asia_2008/ui/default/opera.css new file mode 100644 index 0000000..9e9d2a3 --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/opera.css @@ -0,0 +1,7 @@ +/* DO NOT CHANGE THESE unless you really want to break Opera Show */ +.slide { + visibility: visible !important; + position: static !important; + page-break-before: always; +} +#slide0 {page-break-before: avoid;} diff --git a/Moose_YAPC_Asia_2008/ui/default/outline.css b/Moose_YAPC_Asia_2008/ui/default/outline.css new file mode 100644 index 0000000..62db519 --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/outline.css @@ -0,0 +1,15 @@ +/* don't change this unless you want the layout stuff to show up in the outline view! */ + +.layout div, #footer *, #controlForm * {display: none;} +#footer, #controls, #controlForm, #navLinks, #toggle { + display: block; visibility: visible; margin: 0; padding: 0;} +#toggle {float: right; padding: 0.5em;} +html>body #toggle {position: fixed; top: 0; right: 0;} + +/* making the outline look pretty-ish */ + +#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} +#slide0 h1 {padding-top: 1.5em;} +.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em; + border-top: 1px solid #888; border-bottom: 1px solid #AAA;} +#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} diff --git a/Moose_YAPC_Asia_2008/ui/default/pretty.css b/Moose_YAPC_Asia_2008/ui/default/pretty.css new file mode 100644 index 0000000..838a7cf --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/pretty.css @@ -0,0 +1,82 @@ +/* Following are the presentation styles -- edit away! */ + +body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2.25em;} +:link, :visited {text-decoration: none; color: #00C;} +#controls :active {color: #88A !important;} +#controls :focus {outline: 1px dotted #227;} +h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} +ul, pre {margin: 0; line-height: 1em;} +html, body {margin: 0; padding: 0;} + +blockquote, q {font-style: italic;} +blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;} +blockquote p {margin: 0;} +blockquote i {font-style: normal;} +blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;} +blockquote b i {font-style: italic;} + +kbd {font-weight: bold; font-size: 1em;} +sup {font-size: smaller; line-height: 1px;} + +.slide code {padding: 2px 0.25em; font-weight: bold; color: #533;} +.slide code.bad, code del {color: red;} +.slide code.old {color: silver;} +.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;} +.slide pre code {display: block;} +.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;} +.slide li {margin-top: 0.75em; margin-right: 0;} +.slide ul ul {line-height: 1;} +.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;} +.slide img.leader {display: block; margin: 0 auto;} + +div#header, div#footer {background: #005; color: #AAB; + font-family: Verdana, Helvetica, sans-serif;} +div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat; + line-height: 1px;} +div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;} +#footer h1, #footer h2 {display: block; padding: 0 1em;} +#footer h2 {font-style: italic;} + +div.long {font-size: 0.75em;} +.slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1; + margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap; + font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize; + color: #DDE; background: #005;} +.slide h3 {font-size: 130%;} +h1 abbr {font-variant: small-caps;} + +div#controls {position: absolute; left: 60%; bottom: 0; + width: 40%; + text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;} +html>body div#controls {position: fixed; padding: 0; top: auto;} +#controls #navLinks a {padding: 0; margin: 0 0.5em; + background: #005; border: none; color: #779; + cursor: pointer;} +#controls #navList #jumplist {background: #DDD; color: #227;} + +#currentSlide {text-align: center; font-size: 0.5em; color: #449;} + +#slide0 {padding-top: 3.5em; font-size: 90%;} +#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; + font: bold 2em Helvetica, sans-serif; white-space: normal; + color: #000; background: transparent;} +#slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;} +#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} +#slide0 h4 {margin-top: 0; font-size: 1em;} + +ul.urls {list-style: none; display: inline; margin: 0;} +.urls li {display: inline; margin: 0;} +.note {display: none;} +.external {border-bottom: 1px dotted gray;} +html>body .external {border-bottom: none;} +.external:after {content: " \274F"; font-size: smaller; color: #77B;} + +.incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;} +img.incremental {visibility: hidden;} +.slide .current {color: #B02;} + + +/* diagnostics + +li:after {content: " [" attr(class) "]"; color: #F88;} + */ \ No newline at end of file diff --git a/Moose_YAPC_Asia_2008/ui/default/pretty.css~ b/Moose_YAPC_Asia_2008/ui/default/pretty.css~ new file mode 100644 index 0000000..d0d1aa3 --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/pretty.css~ @@ -0,0 +1,86 @@ +/* Following are the presentation styles -- edit away! */ + +body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2.25em;} +:link, :visited {text-decoration: none; color: #00C;} +#controls :active {color: #88A !important;} +#controls :focus {outline: 1px dotted #227;} +h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} +ul, pre {margin: 0; line-height: 1em;} +html, body {margin: 0; padding: 0;} + +blockquote, q {font-style: italic;} +blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;} +blockquote p {margin: 0;} +blockquote i {font-style: normal;} +blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;} +blockquote b i {font-style: italic;} + +kbd {font-weight: bold; font-size: 1em;} +sup {font-size: smaller; line-height: 1px;} + +.slide code {padding: 2px 0.25em; font-weight: bold; color: #533;} +.slide code.bad, code del {color: red;} +.slide code.old {color: silver;} +.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;} +.slide pre code {display: block;} +.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;} +.slide li {margin-top: 0.75em; margin-right: 0;} +.slide ul ul {line-height: 1;} +.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;} +.slide img.leader {display: block; margin: 0 auto;} + +div#header, div#footer {background: #005; color: #AAB; + font-family: Verdana, Helvetica, sans-serif;} +div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat; + line-height: 1px;} +div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;} +#footer h1, #footer h2 {display: block; padding: 0 1em;} +#footer h2 {font-style: italic;} + +div.long {font-size: 0.75em;} +.slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1; + margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap; + font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize; + color: #DDE; background: #005;} +.slide h2 {position: absolute; top: 1.7em; left: 87px; z-index: 1; + margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap; + font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize; + color: #DDE; background: #005;} +.slide h3 {font-size: 130%;} +h1 abbr {font-variant: small-caps;} + +div#controls {position: absolute; left: 60%; bottom: 0; + width: 40%; + text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;} +html>body div#controls {position: fixed; padding: 0; top: auto;} +#controls #navLinks a {padding: 0; margin: 0 0.5em; + background: #005; border: none; color: #779; + cursor: pointer;} +#controls #navList #jumplist {background: #DDD; color: #227;} + +#currentSlide {text-align: center; font-size: 0.5em; color: #449;} + +#slide0 {padding-top: 3.5em; font-size: 90%;} +#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; + font: bold 2em Helvetica, sans-serif; white-space: normal; + color: #000; background: transparent;} +#slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;} +#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} +#slide0 h4 {margin-top: 0; font-size: 1em;} + +ul.urls {list-style: none; display: inline; margin: 0;} +.urls li {display: inline; margin: 0;} +.note {display: none;} +.external {border-bottom: 1px dotted gray;} +html>body .external {border-bottom: none;} +.external:after {content: " \274F"; font-size: smaller; color: #77B;} + +.incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;} +img.incremental {visibility: hidden;} +.slide .current {color: #B02;} + + +/* diagnostics + +li:after {content: " [" attr(class) "]"; color: #F88;} + */ diff --git a/Moose_YAPC_Asia_2008/ui/default/print.css b/Moose_YAPC_Asia_2008/ui/default/print.css new file mode 100644 index 0000000..e7a71d1 --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/print.css @@ -0,0 +1 @@ +/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ .slide, ul {page-break-inside: avoid; visibility: visible !important;} h1 {page-break-after: avoid;} body {font-size: 12pt; background: white;} * {color: black;} #slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} #slide0 h3 {margin: 0; padding: 0;} #slide0 h4 {margin: 0 0 0.5em; padding: 0;} #slide0 {margin-bottom: 3em;} h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;} .extra {background: transparent !important;} div.extra, pre.extra, .example {font-size: 10pt; color: #333;} ul.extra a {font-weight: bold;} p.example {display: none;} #header {display: none;} #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;} #footer h2, #controls {display: none;} /* The following rule keeps the layout stuff out of print. Remove at your own risk! */ .layout, .layout * {display: none !important;} \ No newline at end of file diff --git a/Moose_YAPC_Asia_2008/ui/default/s5-core.css b/Moose_YAPC_Asia_2008/ui/default/s5-core.css new file mode 100644 index 0000000..ad1530b --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/s5-core.css @@ -0,0 +1,9 @@ +/* Do not edit or override these styles! The system will likely break if you do. */ + +div#header, div#footer, div#controls, .slide {position: absolute;} +html>body div#header, html>body div#footer, + html>body div#controls, html>body .slide {position: fixed;} +.handout, .notes {display: none;} +.layout {display: block;} +.slide, .hideme, .incremental {visibility: hidden;} +#slide0 {visibility: visible;} diff --git a/Moose_YAPC_Asia_2008/ui/default/slides.css b/Moose_YAPC_Asia_2008/ui/default/slides.css new file mode 100644 index 0000000..0786d7d --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/slides.css @@ -0,0 +1,3 @@ +@import url(s5-core.css); /* required to make the slide show run at all */ +@import url(framing.css); /* sets basic placement and size of slide components */ +@import url(pretty.css); /* stuff that makes the slides look better than blah */ \ No newline at end of file diff --git a/Moose_YAPC_Asia_2008/ui/default/slides.js b/Moose_YAPC_Asia_2008/ui/default/slides.js new file mode 100644 index 0000000..ab2a4b2 --- /dev/null +++ b/Moose_YAPC_Asia_2008/ui/default/slides.js @@ -0,0 +1,764 @@ +// S5 v1.2a1 slides.js -- released into the Public Domain +// +// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information +// about all the wonderful and talented contributors to this code! + +var undef; +var slideCSS = ''; +var snum = 0; +var smax = 1; +var incpos = 0; +var number = undef; +var s5mode = true; +var defaultView = 'slideshow'; +var controlVis = 'visible'; + +var s5NotesWindow; +var s5NotesWindowLoaded = false; +var previousSlide = 0; +var presentationStart = new Date(); +var slideStart = new Date(); + +var countdown = { + timer: 0, + state: 'pause', + start: new Date(), + end: 0, + remaining: 0 +}; + + +var isIE = navigator.appName == 'Microsoft Internet Explorer' && navigator.userAgent.indexOf('Opera') < 1 ? 1 : 0; +var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; +var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0; + +function hasClass(object, className) { + if (!object.className) return false; + return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1); +} + +function hasValue(object, value) { + if (!object) return false; + return (object.search('(^|\\s)' + value + '(\\s|$)') != -1); +} + +function removeClass(object,className) { + if (!object || !hasClass(object,className)) return; + object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2); +} + +function addClass(object,className) { + if (!object || hasClass(object, className)) return; + if (object.className) { + object.className += ' '+className; + } else { + object.className = className; + } +} + +function GetElementsWithClassName(elementName,className) { + var allElements = document.getElementsByTagName(elementName); + var elemColl = new Array(); + for (var i = 0; i< allElements.length; i++) { + if (hasClass(allElements[i], className)) { + elemColl[elemColl.length] = allElements[i]; + } + } + return elemColl; +} + +function isParentOrSelf(element, id) { + if (element == null || element.nodeName=='BODY') return false; + else if (element.id == id) return true; + else return isParentOrSelf(element.parentNode, id); +} + +function nodeValue(node) { + var result = ""; + if (node.nodeType == 1) { + var children = node.childNodes; + for (var i = 0; i < children.length; ++i) { + result += nodeValue(children[i]); + } + } + else if (node.nodeType == 3) { + result = node.nodeValue; + } + return(result); +} + +function slideLabel() { + var slideColl = GetElementsWithClassName('*','slide'); + var list = document.getElementById('jumplist'); + smax = slideColl.length; + for (var n = 0; n < smax; n++) { + var obj = slideColl[n]; + + var did = 'slide' + n.toString(); + obj.setAttribute('id',did); + +// if (isOp) continue; // Opera fix (hallvord) + + var otext = ''; + var menu = obj.firstChild; + if (!menu) continue; // to cope with empty slides + while (menu && menu.nodeType == 3) { + menu = menu.nextSibling; + } + if (!menu) continue; // to cope with slides with only text nodes + + var menunodes = menu.childNodes; + for (var o = 0; o < menunodes.length; o++) { + otext += nodeValue(menunodes[o]); + } + list.options[list.length] = new Option(n + ' : ' + otext, n); + } +} + +function currentSlide() { + var cs; + if (document.getElementById) { + cs = document.getElementById('currentSlide'); + } else { + cs = document.currentSlide; + } + cs.innerHTML = '' + + '' + snum + '<\/span> ' + + '\/<\/span> ' + + '' + (smax-1) + '<\/span>' + + '<\/a>' + ; + if (snum == 0) { + cs.style.visibility = 'hidden'; + } else { + cs.style.visibility = 'visible'; + } +} + +function go(step) { + if (document.getElementById('slideProj').disabled || step == 0) return; + var jl = document.getElementById('jumplist'); + var cid = 'slide' + snum; + var ce = document.getElementById(cid); + if (incrementals[snum].length > 0) { + for (var i = 0; i < incrementals[snum].length; i++) { + removeClass(incrementals[snum][i], 'current'); + removeClass(incrementals[snum][i], 'incremental'); + } + } + if (step != 'j') { + snum += step; + lmax = smax - 1; + if (snum > lmax) snum = lmax; + if (snum < 0) snum = 0; + } else + snum = parseInt(jl.value); + var nid = 'slide' + snum; + var ne = document.getElementById(nid); + if (!ne) { + ne = document.getElementById('slide0'); + snum = 0; + } + if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;} + if (incrementals[snum].length > 0 && incpos == 0) { + for (var i = 0; i < incrementals[snum].length; i++) { + if (hasClass(incrementals[snum][i], 'current')) + incpos = i + 1; + else + addClass(incrementals[snum][i], 'incremental'); + } + } + if (incrementals[snum].length > 0 && incpos > 0) + addClass(incrementals[snum][incpos - 1], 'current'); + if (isOp) { //hallvord + location.hash = nid; + } else { + ce.style.visibility = 'hidden'; + ne.style.visibility = 'visible'; + } // /hallvord + jl.selectedIndex = snum; + currentSlide(); + loadNote(); + permaLink(); + number = undef; +} + +function goTo(target) { + if (target >= smax || target == snum) return; + go(target - snum); +} + +function subgo(step) { + if (step > 0) { + removeClass(incrementals[snum][incpos - 1],'current'); + removeClass(incrementals[snum][incpos], 'incremental'); + addClass(incrementals[snum][incpos],'current'); + incpos++; + } else { + incpos--; + removeClass(incrementals[snum][incpos],'current'); + addClass(incrementals[snum][incpos], 'incremental'); + addClass(incrementals[snum][incpos - 1],'current'); + } + loadNote(); +} + +function toggle() { + var slideColl = GetElementsWithClassName('*','slide'); + var slides = document.getElementById('slideProj'); + var outline = document.getElementById('outlineStyle'); + if (!slides.disabled) { + slides.disabled = true; + outline.disabled = false; + s5mode = false; + fontSize('1em'); + for (var n = 0; n < smax; n++) { + var slide = slideColl[n]; + slide.style.visibility = 'visible'; + } + } else { + slides.disabled = false; + outline.disabled = true; + s5mode = true; + fontScale(); + for (var n = 0; n < smax; n++) { + var slide = slideColl[n]; + slide.style.visibility = 'hidden'; + } + slideColl[snum].style.visibility = 'visible'; + } +} + +function showHide(action) { + var obj = GetElementsWithClassName('*','hideme')[0]; + switch (action) { + case 's': obj.style.visibility = 'visible'; break; + case 'h': obj.style.visibility = 'hidden'; break; + case 'k': + if (obj.style.visibility != 'visible') { + obj.style.visibility = 'visible'; + } else { + obj.style.visibility = 'hidden'; + } + break; + } +} + +// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/) +function keys(key) { + if (!key) { + key = event; + key.which = key.keyCode; + } + if (key.which == 84) { + toggle(); + return; + } + if (s5mode) { + switch (key.which) { + case 10: // return + case 13: // enter + if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; + if (key.target && isParentOrSelf(key.target, 'controls')) return; + if(number != undef) { + goTo(number); + break; + } + case 32: // spacebar + case 34: // page down + case 39: // rightkey + case 40: // downkey + if(number != undef) { + go(number); + } else if (!incrementals[snum] || incpos >= incrementals[snum].length) { + go(1); + } else { + subgo(1); + } + break; + case 33: // page up + case 37: // leftkey + case 38: // upkey + if(number != undef) { + go(-1 * number); + } else if (!incrementals[snum] || incpos <= 0) { + go(-1); + } else { + subgo(-1); + } + break; + case 36: // home + goTo(0); + break; + case 35: // end + goTo(smax-1); + break; + case 67: // c + showHide('k'); + break; + case 78: // n + createNotesWindow(); + break; + } + if (key.which < 48 || key.which > 57) { + number = undef; + } else { + if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; + if (key.target && isParentOrSelf(key.target, 'controls')) return; + number = (((number != undef) ? number : 0) * 10) + (key.which - 48); + } + } + return false; +} + +function clicker(e) { + number = undef; + var target; + if (window.event) { + target = window.event.srcElement; + e = window.event; + } else target = e.target; + if (target.href != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true; + if (!e.which || e.which == 1) { + if (!incrementals[snum] || incpos >= incrementals[snum].length) { + go(1); + } else { + subgo(1); + } + } +} + +function findSlide(hash) { + var target = null; + var slides = GetElementsWithClassName('*','slide'); + for (var i = 0; i < slides.length; i++) { + var targetSlide = slides[i]; + if ( (targetSlide.name && targetSlide.name == hash) + || (targetSlide.id && targetSlide.id == hash) ) { + target = targetSlide; + break; + } + } + while(target != null && target.nodeName != 'BODY') { + if (hasClass(target, 'slide')) { + return parseInt(target.id.slice(5)); + } + target = target.parentNode; + } + return null; +} + +function slideJump() { + if (window.location.hash == null) return; + var sregex = /^#slide(\d+)$/; + var matches = sregex.exec(window.location.hash); + var dest = null; + if (matches != null) { + dest = parseInt(matches[1]); + } else { + dest = findSlide(window.location.hash.slice(1)); + } + if (dest != null) + go(dest - snum); +} + +function fixLinks() { + var thisUri = window.location.href; + thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length); + var aelements = document.getElementsByTagName('A'); + for (var i = 0; i < aelements.length; i++) { + var a = aelements[i].href; + var slideID = a.match('\#slide[0-9]{1,2}'); + if ((slideID) && (slideID[0].slice(0,1) == '#')) { + var dest = findSlide(slideID[0].slice(1)); + if (dest != null) { + if (aelements[i].addEventListener) { + aelements[i].addEventListener("click", new Function("e", + "if (document.getElementById('slideProj').disabled) return;" + + "go("+dest+" - snum); " + + "if (e.preventDefault) e.preventDefault();"), true); + } else if (aelements[i].attachEvent) { + aelements[i].attachEvent("onclick", new Function("", + "if (document.getElementById('slideProj').disabled) return;" + + "go("+dest+" - snum); " + + "event.returnValue = false;")); + } + } + } + } +} + +function externalLinks() { + if (!document.getElementsByTagName) return; + var anchors = document.getElementsByTagName('a'); + for (var i=0; i' + + '