The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

OP::Class - Root-level "Class" class

VERSION

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

SYNOPSIS

Class Allocation

  #
  # File: OP/Example.pm
  #

  use OP qw| create true false |;

  create "OP::Example" => {
    #
    # This is an empty class prototype
    #
  };

Class Consumer

  #
  # File: testscript.pl
  #

  use strict;
  use warnings;

  use OP::Example;

  my $exa = OP::Example->new();

  $exa->setName("My First OP Object");

  $exa->save("This is a checkin comment");

  say "Saved object:";

  $exa->print();

DESCRIPTION

OP::Class is the root-level parent class in OP, and also provides the class prototyping function create().

METHODS

Public Class Methods

  • get(OP::Class $class: Str $key)

    Get the named class variable

      my $class = "OP::Example";
    
      my $scalar = $class->get($key);
    
      my @array = $class->get($key);
    
      my %hash = $class->get($key);
  • set(OP::Class $class: Str $key, *@value)

    Set the named class variable to the received value

      my $class = "OP::Example";
    
      $class->set($key, $scalar);
    
      $class->set($key, @array);
    
      $class->set($key, %hash);
  • pretty(OP::Class $class: Str $key)

    Transform camelCase to Not Camel Case

      my $class = "OP::Example";
    
      my $uglyStr = "betterGetThatLookedAt";
    
      my $prettyStr = $class->pretty($uglyStr);
  • members(OP::Class $class:)

    Class introspection method.

    Return an array ref of all messages supported by this class.

    Does not include messages from superclasses.

      my $members = OP::Example->members();
  • membersHash(OP::Class $class:)

    Class introspection method.

    Return a hash ref of all messages supported by this class.

    Does not include messages from superclasses.

      my $membersHash = OP::Example->membersHash();

Private Class Methods

  • init(OP::Class $class:)

    Abstract callback method invoked immediately after a new class is allocated via create().

    Override in subclass with additional logic, if necessary.

  • __checkVarName(OP::Class $class: Str $varName)

    Checks the "safeness" of a class variable name before eval'ing it.

PROTOTYPE COMPONENTS

Class (Package) Name

The name of the class being created is the first argument sent to create().

  use OP qw| create |;

  #
  # The class name will be "OP::Example":
  #
  create "OP::Example" => {

  };

Class Prototype

A class prototype is a hash describing all fundamental characteristics of an object class. It's the second argument sent to create().

  create "OP::Example" => {
    #
    # This is an empty prototype (perfectly valid)
    #
  };

Instance Variables

Instance variables are declared with the assert class method:

  create "YourApp::Example" => {
    favoriteNumber => OP::Int->assert(
      ::optional
    ),

    favoriteColor  => OP::Str->assert(
      qw| red green blue |,
      ::optional
    ),
  };

Instance Methods

Instance methods are declared as keys in the class prototype. The name of the method is the key, and its value in the prototype is a Perl 5 sub{}.

  create "OP::Example" => {
    #
    # Add a public instance method, $self->handleFoo()
    #
    handleFoo => sub {
      my $self = shift;

      printf 'The value of foo is %s', $self->foo();
      print "\n";

      return true;
    }
  }

  my $exa = OP::Example->new();

  $exa->setFoo("Bar");

  $exa->handleFoo();

  #
  # Expected output:
  #
  # The value of foo is Bar
  #

The OP convention for private or protected instance methods is to prefix them with a single underscore.

  create "OP::Example" => {
    #
    # private instance method
    #
    _handleFoo => sub {
      my $self = shift;

      say "The value of foo is $self->{foo}";
    }
  };

Class Variables

Class variables are declared as keys in the class prototype. They should be prepended with double underscores (__). The value in the prototype is the literal value to be used for the class variable.

  use OP qw| create true false |;

  create "OP::Example" => {
    #
    # Override a few class variables
    #
    __useYaml => false,
    __dbiType => OP::DBIType::MySQL
  };

OP class variables are just Perl package variables, scoped in a list using our.

  package OP::Example;

  use OP qw| true false |;

  use base qw| OP::Node |;

  our @__useYaml = false;
  our @__dbiType = OP::DBIType::MySQL;

  true;

Class Methods

Class methods are declared in the same manner as instance methods. The only difference is that the class will be the receiver.

  create "OP::Example" => {
    #
    # Add a public class method
    #
    loadXml => sub {
      my $class = shift;
      my $xml = shift;

      # ...
    }
  };

The OP convention for private or protected class methods is to prefix them with double underscores.

  create "OP::Example" => {
    #
    # Override a private class method
    #
    __basePath => sub {
      my $class = shift;

      return join('/', '/tmp', $class);
    }
  };

Inheritance

By default, classes created with create() inherit from OP::Node. To override this, include a __BASE__ attribute, specifying the parent class name.

  create "OP::Example" => {
    #
    # Override parent class
    #
    __BASE__ => "Acme::CustomClass"
  };

OPTIONAL EXPORTS

Constants

  • true, false

    Constants provided by OP::Enum::Bool

      use OP qw| true false |;

Functions

  • create(Str $class: Hash $prototype)

      use OP qw| create |;

    Allocate a new OP-derived class.

    Objects instantiated from classes allocated with create() have built-in runtime assertions-- simple but powerful rules in the class prototype which define runtime and schema attributes. See the OP::Type module for more about assertions.

    OP classes are regular old Perl packages. create() is just a wrapper to the package keyword, with some shortcuts thrown in.

      use OP qw| create true false |;
    
      create "OP::Example" => {
        __someClassVar => true,
    
        someInstanceVar => OP::Str->assert(),
    
        anotherInstanceVar => OP::Str->assert(),
    
        publicInstanceMethod => sub {
          my $self = shift;
    
          # ...
        },
    
        _privateInstanceMethod => sub {
          my $self = shift;
    
          # ...
        },
    
        publicClassMethod => sub {
          my $class = shift;
    
          # ...
        },
    
        __privateClassMethod => sub {
          my $class = shift;
    
          # ...
        },
      };

DIAGNOSTICS

XXX TODO Figure out what to put in this section.

CONFIGURATION AND ENVIRONMENT

OP looks for the .oprc configuration file under the location specified by $OP_HOME. See OP::Constants for details.

OP under mod_perl/mod_perl2

OP classes should be precompiled under mod_perl by referencing them in the Apache instance's startup.pl script. OP_HOME must be set in a BEGIN block.

  #
  # File: startup.pl
  #
  BEGIN {
    $ENV{OP_HOME} = '/home/user/op'; # Directory with the .oprc
  }

  #
  # Load any OP-derived packages at startup:
  #
  use MyApp::Component;
  use MyApp::OtherComponent;

  1;

OP under HTML::Mason

OP classes should be preloaded by startup.pl, as in the above example.

If (and only if) you are not using a startup.pl: Mason loads packages outside the context of package main, but OP must currently be bootstrapped from package main, so one must explicitly drop back into main before consuming OP-derived classes. Do this in a do block.

  <%init>

    do {
      package main;

      use MyApp::Component;
    }

  </%init>
  <%perl>

    $m->print( MyApp::Component->sayHello() );

  </%perl>

It is highly recommended that startup.pl be used in production environments, so the initial requests to the webserver are not delayed by the lengthy source filtering and compilation steps.

  #
  # File: httpd.conf
  #
  PerlModule HTML::Mason::ApacheHandler
  PerlRequire /opt/op/bin/startup.pl

  <LocationMatch "/.*\.html$">
    SetHandler perl-script

    PerlHandler HTML::Mason::ApacheHandler
  </LocationMatch>

DEPENDENCIES

OP's dependencies are numerous, and subject to change while the API is ironed out. See the Makefile.PL which accompanied this distribution for a current list of prerequisites.

INCOMPATIBILITIES

Probably.

BUGS AND LIMITATIONS

Likely.

Test suite is currently incomplete.

SEE ALSO

OP::Type, OP::Subtype

This file is part of OP.