Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
SPOPS::Manual::CodeGenUseriContributed Perl DoSPOPS::Manual::CodeGeneration(3)

NAME
       SPOPS::Manual::CodeGeneration - How SPOPS builds	classes

SYNOPSIS
       This part of the	SPOPS manual describes how SPOPS generates the class
       code and	how you	can customize the process.

DESCRIPTION
       So with configuration, we would create a	number of slots	into which
       classes could install behaviors.	The slots are:

       manipulate_configuration
       id_method
       read_code
       fetch_by
       has_a (relationship)
       links_to	(relationship)
       add_rule

       They're described in more detail	below.

       A class in the hierarchy	for an object (or in the 'rules_from' list)
       could install a behavior	in none	or all of the slots. So	for instance,
       "SPOPS::Configure::DBI" has been	replaced by SPOPS::ClassFactory::DBI,
       which reads the configuration for SPOPS::DBI-derived objects and
       installs	DBI-specific "links_to"	behaviors.

       Multiple	behaviors can be installed in each slot, with the idea that
       order shouldn't matter. Since we	do a depth-first inheritance walk we
       should be ok -- more specific classes will execute their	behaviors
       before the more general ones.

       The processing of each slot uses	a form of the 'Chain of
       Responsibility' pattern -- a behavior can decide	to perform or not
       perform any action and continue ("OK"), to perform an action, to
       declare the slot	finished ("DONE"), to stop the process entirely
       ("ERROR") or that the behavior has made changes which necessitates
       refreshing the behavior listing ("RESTART").

       As a simple example of a	behavior, say we wanted	to ensure that all of
       our objects are using a particular SPOPS::DBI subclass:

	 1: package My::UseMyDBIClass; # -*-perl-*-
	 2:
	 3: use	strict;
	 4:
	 5: my $USE_CLASS = 'SPOPS::DBI::Pg';
	 6:
	 7: sub	behavior_factory {
	 8:   my ( $class ) = @_;
	 9:   return { manipulate_configuration	=> \&check_spops_subclass };
	10: }
	11:
	12: sub	check_spops_subclass {
	13:	my ( $config ) = @_;
	14:	foreach	( @{ $config->{isa} } )	{
	15:	    s/^SPOPS::DBI::.*$/$USE_CLASS/;
	16:	}
	17:	return ( SPOPS::ClassFactory::RESTART, undef );
	18: }

       We would	just put this method in	a common parent	to all our objects and
       install the behavior in the 'manipulate_configuration' slot. When the
       class is	configured the rule would be executed and we would never have
       to worry	about our objects using	the wrong DBI class again. (This is
       common in OpenInteract when you install new packages and	forget to run
       'oi_manage change_spops_driver'.)

       And that's it! The system enables very focused and flexible behaviors.
       For instance, we	could create one "links_to" behavior for DBI to	handle
       the current configuration style and another to handle the proposed (and
       more robust) "SPOPS::Inheritable" configuration style. The first	could
       step through the	'links_to' configuration items and process only	those
       it can, while the second	could do the same. And neither has to know
       about the other.

       We could	also do	wacky stuff, like install a 'read_code'	behavior to
       use LWP to grab a module	and checksums off a code repository somewhere.
       If the checksum and code	match up, we can bring the code	into the SPOPS
       class.

SLOTS
       We use the term 'slots' to refer	to the different steps we walk through
       to create, configure and	auto-generate methods for an SPOPS class. Each
       'slot' can have multiple	behaviors attached to it.

   Finding Slot	Behaviors
       Slot behaviors can come from any	of the classes in the @ISA for the
       generated class,	or from	any of the classes listed in the 'rules_from'
       configuration key.

       The differences between the 'isa' and the 'rules_from' class lists are:

       o   The classes listed in 'rules_from' are used by themselves. The
	   'isa' classes we use	Class::ISA to find the inheritance tree	of our
	   generated SPOPS class so we can look	into each of them for relevant
	   behaviors.

       o   The 'rules_from' classes are	not used by anything once the class
	   has been generated, while 'isa' classes are used in the normal Perl
	   manner for inheritance.

   Slot	Listing
       Here are	the current slots and a	description of each. Note that they
       might change -- in particular, the 'links_to' and 'has_a' slots might
       be merged into a	single 'relationship' slot.

       o   manipulate_configuration: Modify the	configuration as necessary.
	   SPOPS comes with one	method to transform arrayrefs (for easy
	   typing) into	hashref	(for easy lookup). Other options might be to
	   set application-specific information	accessible from	all your
	   objects, futz around	with the @ISA, etc.

       o   id_method: Very focused: generate an	"id( [ $new_id ] )" method.
	   SPOPS uses these to ensure it can get the crucial information from
	   every object	-- class and ID	-- without having to know what the ID
	   field is.

	   SPOPS comes with a default method for this that will	probably work
	   fine	for you	-- see SPOPS::ClassFactory::DefaultBehavior.

       o   read_code: Reads in code from another class to the class being
	   created/configured. SPOPS comes with	a method to read the value(s)
	   from	the configuration key 'code_class', find them from @INC	and
	   read	them in.

	   But you can perform any action you need here	-- you could even
	   issue a SOAP	request	to read	Perl code (along with checksums) off
	   the net, check the code then	read it	in.

       o   fetch_by: Process the 'fetch_by' configuration key. SPOPS comes
	   with	autogenerated methods to do this, but you can modify it	and
	   implement your own.

       o   has_a: Process the 'has_a' configuration key. Usually this is
	   implementation-specific and involves	auto-generating	methods. SPOPS
	   comes with a	default	for this, but an implementation	class can
	   elect to not	use it by returning the	'DONE' constant.

       o   links_to: Process the 'links_to' configuration key. Usually this is
	   implementation-specific and involves	auto-generating	methods.

       o   add_rule: You will probably never need to create a behavior here:
	   SPOPS has one that performs the same	duties as
	   "SPOPS::Configure::Ruleset" used to -- it scans the @ISA of a
	   class, finds	the ruleset generation methods from all	the parents
	   and installs	these coderefs to the class.

BEHAVIOR GENERATOR
       The behavior generator is called	'behavior_factory' (the	name can be
       imported	in the constant	'FACTORY_METHOD') and it takes a single
       argument, the name of the class for which the behaviors are being
       generated. It should return a hashref with the slot names as keys. A
       value should either be a	coderef	(for a single behavior)	or an arrayref
       of coderefs (for	multiple behaviors).

       Here is an example, directly from from "SPOPS":

	sub behavior_factory {
	    my ( $class	) = @_;
	    $log->is_info &&
		$log->info( "Installing	SPOPS default behaviors	for ($class)" );
	    return { manipulate_configuration =>
			   \&SPOPS::ClassFactory::DefaultBehavior::conf_modify_config,
		    read_code		     =>
			   \&SPOPS::ClassFactory::DefaultBehavior::conf_read_code,
		    id_method		     =>
			   \&SPOPS::ClassFactory::DefaultBehavior::conf_id_method,
		    has_a		     =>
			   \&SPOPS::ClassFactory::DefaultBehavior::conf_relate_hasa,
		    fetch_by		     =>
			   \&SPOPS::ClassFactory::DefaultBehavior::conf_relate_fetchby,
		    add_rule		     =>
			   \&SPOPS::ClassFactory::DefaultBehavior::conf_add_rules, };
	}

       So with this we're installing one behavior each into the	slots
       'manipulate_configuration', 'read_code',	'id_method', 'has_a',
       'fetch_by' and 'add_rule'. Here's an example that installs multiple
       behaviors in a single slot:

	sub behavior_factory {
	    my ( $class	) = @_;
	    return { links_to => [ \&simple_linking, \&complex_linking ] };
	}

	sub simple_linking { ... }
	sub complex_linking { ... }

BEHAVIOR DESCRIPTION
       Behaviors can be	simple or complicated, depending on what you need them
       to do. The simple behavior we showed above does a single, simple	task
       and then	exits. This is probably	the best strategy for most behavior
       uses -- focus each one one a single task	so you it's easy to follow and
       debug. The fact that we run the behaviors only once, when the class is
       being generated,	means that you don't have to worry so much about
       efficiency.

       Every behavior returns a	two-item list. The first is the	status of the
       behavior, the second is an optional message.

       The potential status return values are all constants that can be
       imported	from SPOPS::ClassFactory:

       o   OK: The behavior executed without errors and	that additional
	   behaviors can execute.

       o   DONE: The behavior executed without errors and that additional
	   behaviors in	this slot should not execute.

       o   RESTART: The	behavior executed without errors but modified some
	   aspect of the class or its configuration such that it is necessary
	   to revisit the behavior map and see if there	are any	additional
	   ones. The most common cause of this is adding one or	more classes
	   to 'isa' or 'rules_from'.

       o   NOTIFY: The behavior	executed with errors, but the errors will be
	   written (via	"warn")	to STDERR rather than halting the process.

       o   ERROR: The behavior executed	with errors, and that the entire
	   process should immediately stop.

COPYRIGHT
       Copyright (c) 2001-2004 Chris Winters. All rights reserved.

       See SPOPS::Manual for license.

AUTHORS
       Chris Winters <chris@cwinters.com>

perl v5.32.1			  2004-06-02  SPOPS::Manual::CodeGeneration(3)

NAME | SYNOPSIS | DESCRIPTION | SLOTS | BEHAVIOR GENERATOR | BEHAVIOR DESCRIPTION | COPYRIGHT | AUTHORS

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=SPOPS::Manual::CodeGeneration&sektion=3&manpath=FreeBSD+13.0-RELEASE+and+Ports>

home | help