NAME

OP - Objective Perl 5 (Overpowered)

VERSION

This documentation is for version 0.20 of OP.

$Id: //depotit/tools/source/snitchd-0.20/lib/OP.pm#30 $

STATUS

The usual pre-1.0 warnings apply. Consider this alpha code. It does what we currently ask of it, and maybe a little more, but it is a work in progress.

SYNOPSIS

use OP;

Using the OP module initializes all built-in object types, and causes strict, diagnostics, OP::Class, OP::Type, Perl6::Subs, and Error to be imported by the caller. These may alternately be imported individually.

DESCRIPTION

Compact and concise class prototyping, with object persistence.

OP is a Perl 5 dialect for deriving object classes and database schemas. Apps developed and executed under OP have a greater degree of formality and consistency than one may be accustomed to seeing in Perl.

This document covers the high-level concepts implemented in OP.

GETTING STARTED

Subclassing instructions are provided in the "Subclassing" section of this document, and also outlined in OP::Class.

Instance variable assertions are outlined in OP::Type and OP::Subtype.

See Perl6::Subs for an overview of the Perl 6-style methods used by OP.

See Error for an overview of exception handling in Perl 5.

PARTIAL FEATURE LIST

Assertions

Strict and straight-forward control of attribute types (OP::Type), subtypes (OP::Subtype), and duck-types.

Prototyping

Inspired by Prototype.js in the JavaScript world, OP::Class provides the create function, enabling developers to craft database-backed Perl 5 classes in a compact and concise manner. Complex schemas may be quickly modeled in code and put to use.

Persistence

After a class has been prototyped, saving its instantiated objects to a SQL backing store is as easy as $object->save().

Exceptions

Exception handling is brought in from the Error module. try, throw, and catch are first-class citizens in the OP runtime.

Formal Methods

Perl 6-style method support is provided by the Perl6::Subs source filter, and is used extensively throughout OP source and its examples. OP also implements a generalized subset of Perl 6-derived object types.

Async Programming

OP provides first-class support for Coro and POE. See OP::Recur and OP::Persistence::Async.

FRAMEWORK ASSUMPTIONS

When using OP, a number of things "just happen" by design. Trying to go against the flow of any of these base assumptions is not recommended.

Default Modules

strict, warnings, Error, and Perl6::Subs are on by default.

Persistent Objects Extend OP::Node

Classes allocated with create will receive an InnoDB backing store, by virtue of being a subclass of OP::Node. This can be overridden if needed, see "Inheritance" in OP::Class for details.

Various backing store options are covered in the OP::Persistence module.

Default Base Attributes

Unless overridden in __baseAsserts, OP::Node subclasses have the following baseline attributes:

  • id => OP::ID

    id is the primary key at the database table level.

    Objects will use a GUID (globally unique identifier) for their id, unless this behavior is overridden in the instance method _newId(), and __baseAsserts() overridden to use a non-GUID data type such as OP::Int.

    id is automatically set when saving an object to its backing store for the time. Modifying id manually is not recommended.

  • name => OP::Name

    OP uses "named objects". By default, name is a human-readable unique secondary key. It's the name of the object being saved. Like all attributes, name must be defined when saved, unless asserted as ::optional (see "undef Requires Assertion").

    The value for name may be changed (as opposed to id, which should not be tinkered with), as long as the new name does not conflict with any objects in the same class when saved.

    name may be may be keyed in combination with multiple attributes via the ::unique OP::Subtype argument, which adds InnoDB reference options to the schema.

    create "My::Class" => {
      #
      # Don't require named objects:
      #
      name => OP::Name->assert(::optional),
    
      # ...
    };
  • ctime => OP::DateTime

    ctime is the Unix timestamp representing the object's creation time. OP sets this when saving an object for the first time.

  • mtime => OP::DateTime

    mtime is the Unix timestamp representing the object's last modified time. OP updates this each time an object is saved.

undef Requires Assertion

Instance variables may not be undef, unless asserted as ::optional.

Object instances in OP may not normally be undef. Generally, if a value is not defined, OP currently returns undef rather than an undefined object instance. This may change at some point.

Namespace Matters

OP's core packages live under the OP:: namespace. Your classes should live in their own top-level namespace, e.g. "MyApp::".

OBJECT TYPES

OP implements the same object class types referred to in Perl6::Subs, several others which are specific to dealing with a SQL backing store (e.g. Double, ExtId), as well as datatypes commonly used in network operations (e.g. EmailAddr, IPv4Addr, URI).

Usage

OP object types are used when asserting attributes within a class, and are also suitable for instantiation or subclassing in a self-standing manner.

The usage of these types is not mandatory outside the context of creating a new class-- OP always returns data in object form, but these object types are not a replacement for Perl's native data types in general usage, unless you want them to be.

These modes of usage are shown below, and covered in greater detail in specific object class docs.

Subclassing

use OP;

create "MyApp::Example" => {
  __BASE__ => "OP::Hash",

};

or

package My::Example;

use strict;
use warnings;

use base qw| OP::Hash |;

1;

Object Types as Attributes

When defining the allowed instance variables for a class, the assert() method is used:

#
# File: Example.pm
#
use OP;

create "MyApp::Example" => {
  someString => OP::Str->assert(),
  someInt    => OP::Int->assert(),

};

As Objects

When instantiating, the class method new() is used, typically with a prototype object for its argument.

#
# File: somecaller.pl
#
use strict;
use warnings;

use MyApp::Example;

my $example = MyApp::Example->new(
  name       => "Hello",
  someString => "foo",
  someInt    => 12345,
);

$example->save("Saving my first object");

$example->print();

In Method Args

To ensure method arguments are always of the appropriate type, specify the desired type(s) in a Perl6::Subs prototype.

You may specify OP object types or their more general Perl6::Subs counterparts (with the type names not prefixed by OP::), depending on how "picky" you want the receiver to be. If a specific OP object type is specified, the received arg must be of that object type or a subclass (ie, it must pass the UNIVERSAL::isa() test). The Perl6::Subs equivalent pseudo-types are designed around Perl 5's native data types, and are suitable for testing non-objects.

As an academic example, here are less-picky and more-picky subs:

#
# Less-picky, duck-typey sub:
#
sub doSomethingWithHash(Hash $hash) {
  say $hash ? "I'm happy with $hash" : "I got nothin'";
}

#
# Pickier sub:
#
sub pickyHashSub(OP::Hash $hash) {
  doSomethingWithHash($hash);
}

Here is code to test the less-picky version:

#
# This says "I'm happy with OP::Hash=HASH(0xDEADBEEF)"
#
doSomethingWithHash(OP::Hash->new());

#
# This says "I'm happy with HASH(0xDEADBEEF)"
#
doSomethingWithHash({ });

And code to test its pickier counterpart:

#
# This says "I'm happy with OP::Hash=HASH(0xDEADBEEF)":
#
pickyHashSub(OP::Hash->new());

#
# But this will throw an exception like:
#
# - Unhandled OP::InvalidArgument Exception:
#   Parameter $hash is not an OP::Hash in call to main::pickyHashSub ...
#
pickyHashSub({ });

Note that constructors and setter methods accept both native Perl 5 data types and their OP object class equivalents. The setters will automatically handle any necessary conversion, or throw an exception if the received arg doesn't quack like a duck.

Native types are OK for constructors:

my $example = MyApp::Example->new(
  someString => "foo",
  someInt    => 123,
);

#
# someStr became a string object:
#
say $example->someString()->class();
# "OP::Str"

say $example->someString()->size();
# "3"

say $example->someString();
# "foo"

#
# someInt became an integer object:
#
say $example->someInt()->class();
# "OP::Int"

say $example->someInt()->sqrt();
# 11.0905365064094

Native types are OK for setters:

$example->setSomeInt(456);

say $example->someInt()->class();
# "OP::Int"

ABSTRACT CLASSES & MIX-INS

OP::Class

Abstract "Class" class

Base package for OP object classes, and lexical prototyping wrapper.

OP::Class::Dumper

Inspect attributes and methods

Introspection mix-in for classes and objects

OP::Object

Abstract object class

Extends OP::Class with constructor, getters, setters, asserts.

OP::Persistence

Object storage and retrieval

Mix-in for providing backing store support to objects

Specific DBI-type mix-ins are OP::Persistence::MySQL and OP::Persistence::SQLite. Asynchronous DB access is provided by the OP::Persistence::Async mix-in.

OP::Node

Abstract stored object class

Extends OP::Hash and OP::Persistence to form the abstract base storable object class in OP.

OP::Type

Instance variable typing

Extends OP::Class. Used by OP::Object subclasses to "assert" parameters for instance variables and database table columns.

OP::Subtype

Instance variable subtyping

Extends OP::Class. Used in OP::Type instances to define subtype restrictions for instance variables and database table columns.

The OP::Subtype module lists the available rule types.

OBJECT TYPES

These Perl 5 classes represent a generalization of their Perl 6 counterparts, at best, also introducing several object types specific to dealing with a SQL backing store. OP is not intended to be a Perl 6 implementation at all; there are inconsistencies and cut corners in the usage of these classes, compared to what Perl 6 will look like. OP borrows many of these class names for consistency with Perl6::Subs, and to have less things to remember when coding.

The basic types listed here may be instantiated as objects, or asserted as inline attributes.

OP::Any

Overloaded, any value

Extends OP::Scalar. Generally treats the value in a string-like manner, but may be any Perl 5 value.

OP::Array

List

Extends OP::Object with Ruby-esque collectors and other array methods.

OP::Bool

Overloaded binary boolean

Extends OP::Scalar. Implements methods around OP::Enum::Bool in a transparent manner, where true = 1 and false = 0.

OP::Code

Any CODE reference

Extends OP::Ref

Differs from the Perl 6 spec, in that it is more of an envelope for any CODE ref than a base for other classes of executable code.

OP::DateTime

Overloaded time object class

Extends OP::Array, Time::Piece. Overloaded for numeric comparisons, stringifies as unix timestamp unless overridden.

OP::Domain

Overloaded domain name object class

Extends OP::Str. Uses Data::Validate::Domain to verify input.

OP::Double

Overloaded double-precision number

Extends OP::Float. Perl 5 number. Use bignum to control runtime precision. This datatype is specific to OP, and is used when asserting a double-precision database table column. It is otherwise just a scalar value.

OP::EmailAddr

Overloaded RFC 2822 email address object class

Extends Email::Address, OP::Array. Uses Data::Validate::Email to verify input.

OP::ExtID

Overloaded foreign GUID value

Extends OP::ID. Scalar GUID object. This datatype is specific to OP, and represents the ID of a foreign object. When asserting a property backed by an InnoDB table, ExtID sets up foreign key constraints.

OP::Float

Overloaded floating point number

Extends OP::Num and Data::Float

OP::Hash

Hash reference

Extends OP::Object with Ruby-esque collectors and other hashtable methods.

OP::ID

Overloaded primary GUID value

Extends OP::Scalar and Data::GUID. Represents the primary key in an object.

OP::Int

Overloaded integer

Extends OP::Num and Data::Integer

OP::IPv4Addr

Overloaded IPv4 address object class

Extends OP::Str. Uses Data::Validate::IP to verify input.

OP::Name

Human-readable secondary key

Extends OP::Str. Represents the secondary key within a class.

OP::Num

Overloaded, any number

Extends OP::Scalar and Scalar::Number. Implements instance methods around Perl 5's built-in math functions.

OP::Ref

Any reference value

Extends OP::Any

OP::Rule

Regex reference (qr/ /)

Extends OP::Ref

OP::Scalar

Any Perl 5 scalar

Extends OP::Object. Overloaded with overload.

OP::Str

Overloaded unicode string

Extends OP::Scalar, Mime::Base64, and Unicode::String. Implements instance methods around Perl 5's built-in string functions.

OP::TimeSpan

Overloaded time range object class

Extends OP::Scalar, Time::Seconds. Represents a number of seconds.

OP::URI

Overloaded URI object class

Extends URI, OP::Str. Uses Data::Validate::URI to verify input.

CONSTANTS & ENUMERATIONS

OP::Constants

"dot rc" values as constants

Exposes values from the .oprc file as Perl 5 constants

OP::Enum

C-style enumerated types as constants

Enumerations are groups of hard-coded constants used internally by OP.

HELPER MODULES

OP::Utility

System functions required globally by OP

OP::Exceptions

Exceptions are subclasses of Error which may be thrown by OP

EXPERIMENTAL*: INFOMATICS

Experimental classes are subject to radical upheaval, questionable documentation, and unexplained disappearances. They represent proof of concept in their respective areas, and may move out of experimental status at some point.

OP::Log

OP::RRNode factory class

Generates and loads OP::RRNode subclasses on the fly.

OP::RRNode

Round Robin Database Table

Objects live in a FIFO table of fixed length.

OP::Series

Cooked OP::RRNode Series Data

Consolidate OP::RRNode data for easy plotting.

EXPERIMENTAL: SCHEDULING

OP::Recur

Recurring time specification

Experimental class for describing recurring points in time.

EXPERIMENTAL: FOREIGN DB ACCESS

OP::ForeignTable

Any Non-OP Database Table

Experimental class for using an arbitrary table as a backing store.

EXPERMENTAL: INTERACTIVE SHELL

OP::Shell

Interactive Perl Shell

Interactive shell with ReadLine support and lexical persistence.

SEE ALSO

Perl6::Subs, OP::Class, OP::Type

Object Types from perl6 Synopsis 2: - http://dev.perl.org/perl6/doc/design/syn/S02.html

AUTHOR

Alex Ayars <pause@nodekit.org>

COPYRIGHT

 File: OP.pm

 Copyright (c) 2009 TiVo Inc.

 All rights reserved. This program and the accompanying materials
 are made available under the terms of the Common Public License v1.0
 which accompanies this distribution, and is available at
 http://opensource.org/licenses/cpl1.0.txt