Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

jsmith (3335)

jsmith
  (email not shown publicly)
http://www.jamesgottlieb.com/
Jabber: jgsmith@tamu.edu

I'm a web applications developer trying to bring all things open source to all things humanities at Texas A&M University.

Journal of jsmith (3335)

Wednesday February 25, 2004
01:14 AM

First release of Gestinanna framework

I finally got enough code together to put something out on CPAN. It's not complete, but enough is there to get it running.

The framework maps urls to content. Four content providers are in the base distribution: documents (unparsed), views (parsed by Template Toolkit), portals (documents that can embed other content), and xsm (eXtensible State Machines). The last one, xsm, acts as the controller in an application. Each state can map to a view which has access to the state information.

Sessions are handled automatically. If cookies are not available, then the URL is mangled, though some support work remains for this -- external links don't redirect correctly yet to lose the session id information. Each state machine has its own independent context. If I have time, I want to develop an application that allows help desk people to trace the path a customer took through an application so they can see what the customer might have done wrong or what the customer needs to do next.

Forms automatically fill themselves out based on the context information. The TT2 view doesn't have to track default values. Using the XPath-like expression syntax in XSM makes data management in complex forms simple -- take a look at the wizard creation wizard for an example: we have a wizard that can contain multiple steps, each of which can require multiple pieces of data.

The XML schema for form markup makes embedding one form in another simple. It also means the form elements should be coded based on their logical relationship to one another, not based on how the page should be laid out.

Views are inheritable, for the most part (this may still require a bit of work). I can subclass an existing application and only change those views that require changing. Only change those state transitions that require changing.

I think it's neat. There's too much there to try and cram it all into one post. If you have time and want to just play around with some new code, download the packages and give it a spin. I'd love to hear what you think.

Thursday November 13, 2003
01:03 AM

Transforming programs and XSM

I've been working some more on my eXtensible State Machines --- web applications written using an XML language. Some interesting things are coming out of this. (And I hope to have something released around the end of the month if I can get certain testing done.)

First, there are continuations. I don't have those implemented yet, but I have about half-continuations done. That is, you can suspend the current program and run another, sending views to the client browser and processing the input. Then, when that program is finished, you can drop back to the prior program in the state you left it. You don't yet get dropped back into the code where you called out to the other program and you can't pass data back to the calling program. That would be full continuations.

Second, I borrowed an idea from AxKit/XSP (see ``Taglib TMTOWTDI'') and now support applying XSLTs to the programs written in XML. Makes sense. XSLT is designed to transform XML documents. Now, instead of running program P, I can run a transform of it: f(P), f: XML -> XML. I like the mathematical notions.

This is useful because some (many?) of the little applications we are needing to write consist of a series of pages collecting information and then a final step doing something with that information. If we wanted to support `Prev', `Next', etc., functionality to make a wizard-like flow, we had to code transitions for each one in each state. Now, I can write something like:

<statemachine>
   <wiz:steps>
     <wiz:step>
       <variable id="filename"/>
       <variable id="title"/>
       <variable id="description"/>
     </wiz:step>
     <wiz:step>
       <variable id="states"/>
     </wiz:step>
     <wiz:step>
       <variable id="state.initial"/>
       <variable id="state.transitions"/>
     </wiz:step>
   </wiz:steps>
</statemachine>

You can get the idea. Applying an appropriate XSLT ensures that I can go back and forth through the pages with proper validation and storage of the data without having to duplicate a lot of code by hand. So now, I have XML -> f(XML) -> Perl(f(XML)) -> byte-code(Perl(f(XML))) -> ....

Third thing (second that I did today) is making a form element.

<grid id="things" count="multiple">
   <column id="foo"/>
   <column id="bar"/>
   <row id="red"/>
   <row id="black"/>
</grid>

This produces a 2x2 grid of checkboxes allowing the selection of the values red.foo, red.bar, black.foo, and black.bar. Different values of @count affect whether its a checkbox or radio button, and whether it is constrained by row, by column, or not at all. Now I just need to get the XSM content provider to be able to manage the default values automatically.

Wednesday September 24, 2003
10:55 PM

First Post and eXtensible State Machines

I'm on LiveJournal, but most of the people I know there aren't into Perl. This semester, I've been busy digging into a project that I've been working on for a year or so now. It's finally time to get it done. So, because I'm enthusiastic about it and spending long hours each day on it, I'll let some of that enthusiasm bubble over here.

I've been working on a XPath-like expression language for Perl data structures using Barrie Slaymaker's EventPath grammer which was based on James Clark's XPath grammer. I can now say /this/method::foo(/that)[@can="dance"] and get back any objects returned from the foo method of /this called with /that, and select those returned objects that can('dance'). Eventually I'll factor most of the code out and put it on CPAN as Data::DPath.

The Data::DPath stuff is the expression component of what I am calling eXtensible State Machines. These are like eXtensible Server Pages except they have no Perl (they are pure XML) and define the controller in an MVC application. The View is going to be provided by Template Toolkit (but that's configurable). I haven't decided what XSM will be called when I factor it out for CPAN.

The state machine compiler is borrowed from / based on the XSP compiler in AxKit. At this point, I'm more interested in it working correctly than efficiently. The data in the %EDGES hash is used to create Data::FormValidator objects to help decide which state to transition to. Of course, details are subject to change while in development.

<statemachine xmlns="http://some/url">
  <alias id="_begin" state="start"/>
  <state id="start">
    <transition state="edit">
      <variable id="uin"/>
      <group id="birth">
        <variable id="day"/>
        <variable id="month"/>
        <variable id="year"/>
      </group>
    </transition>
  </state>
  <state id="edit">
    <transition state="confirm">
      <variable id="netid"/>
      <variable id="password1"/>
      <variable id="password2"/>
      <script> <!-- defines the edit_to_confirm subroutine -->
        <assert test="not(string-cmp(/password1,/password2))" state="edit"/>
      </script>
    </transition>
  </state>
  <state id="confirm">
    <transition state="done">
      <variable id="confirm"/>
    </transition>
    <transition state="edit">
      <variable id="edit"/>
    </transition>
  </state>
</statemachine>

is compiled to the following Perl code:

package Gestinanna::Sites::Hinoto::XSM::activate::V1_5;
# line 555 "Perl generated by /usr/local/lib/perl5/site_perl/5.8.0/Gestinanna/XSM.pm"
#initialize sm namespace
sub edit_to_confirm {
    my ($sm) = shift;
    my %data = (
        local => $sm->data('out'),

        #session => $sm -> session,
        context => $sm->data, solar => {}, global => {},
    );

    return "edit" # <assert test="..." state="..."/>
      unless (
        (
         Gestinanna::XSM::Core::xsm_not(
             (
                 (
                     Gestinanna::XSM::Core::xsm_string_cmp(
                         (
                             grep { defined } map {
                                 Gestinanna::XSM::Expression::axis_child($_,
                                                                    "password1" )
                               } $data{"local"}
                         )[0],
                         (
                          grep { defined } map {
                              Gestinanna::XSM::Expression::axis_child($_,
                                                                    "password2" )
                            } $data{"local"}
                           )[0],
                     )
                 )
             )[0],
         )
        )
      );

    return;
} ## end sub edit_to_confirm
use vars qw(@ISA %HASA %VIEWS %ALIASES %EDGES);

@ISA     = ('Gestinanna::XSM::Base');
%HASA    = ();
%VIEWS   = ();
%ALIASES = ('_begin' => 'start');
%EDGES = (
       'confirm' => { 'done' => { 'required' => ['confirm'] },
                      'edit' => { 'required' => ['edit'] }
       },
       'edit' => # required to get from edit to confirm
         { 'confirm' => { 'required' => ['netid', 'password1', 'password2'] } },
       'start' => {
           'edit' => # required to get from start to edit
             { 'required' => ['uin', 'birth.day', 'birth.month', 'birth.year'] }
       }
);