1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu Embedding Perl in HTML with Mason Chapter 5: Advanced Features-P1 doc

23 375 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Advanced Features-P1
Thể loại Chapter
Định dạng
Số trang 23
Dung lượng 46,3 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

You'll learn how to define multiple components in the same text file, how to create components on the fly from Perl strings, how to manage multiple component root directories, and finall

Trang 1

Chapter 5: Advanced Features-P1

In the previous chapters you have been introduced to the basic features of Mason, and you should have a fairly good idea by now of how you might actually go about constructing a dynamic web site from Mason components You have seen a few of Mason's unique features, such as the autohandler mechanism, the dhandler mechanism, and the ability to pass arbitrary data between components

In this chapter we'll go beyond the basics and learn more about advanced ways to use Mason components to design large dynamic sites You'll learn how to define multiple components in the same text file, how to create

components on the fly from Perl strings, how to manage multiple component root directories, and (finally!) how to use all of Mason's object-oriented features

subcomponent , and it is visible only to the component within which it

resides: component A may not access component B's subcomponents

directly

The subcomponent may use any of the standard Mason component

directives, such as <%args>, <%init>, %-lines, and so on The only

exceptions are that you may not use <%def> or <%method> blocks within

Trang 2

subcomponents nor may you use "global" blocks like <%once> or

<%shared>

Subcomponents are most useful when you have some piece of processing to repeat several times that is used only in a certain specific situation and doesn't merit its own separate component file

Here is an example of defining and calling a subcomponent Note that the component is assigned a name inside the <%def> tag (the name often starts with a period, purely by convention) and that you use the regular

component-calling mechanisms ($m->comp() or a <& &> tag) to invoke

Trang 4

</%def>

Since a subcomponent is visible only to the component that defines, and because it has all the capabilities that regular components have, you may think of subcomponents as roughly analogous to privately scoped

anonymous subroutine references in Perl

Creating Components on the Fly

You may encounter situations in which you want to use Mason's templating features and data management tools, but you don't want to create a full-blown component root hierarchy on disk to house your components Perhaps you want to create a component from an isolated file or directly from a string containing the component text

For these situations, the Mason interpreter provides the

make_component() method It accepts a comp_file or

comp_source parameter (letting you create a component from a file or a string, respectively) and returns a Component object

# Creating a component from scratch

Trang 5

$interp->exec($comp, planet => 'Neptune');

And here is a component that creates another component at runtime:

<& $comp &>

Trang 6

If the compiler encounters syntax errors when attempting to compile the component, a fatal exception will be thrown inside the

make_component() method If you want to trap these errors, you may wrap the make_component() method in Perl's eval {} block, and check $@ after the method call

Sharing Data Among Component Sections

By default, the scope of variables created within an <%init> block, a Perl line, or any other Mason markup sections is the entire component This is tremendously convenient, because it lets you initialize variables in the

<%init> block, then use their values across the rest of the component So most of the time, the techniques discussed in this section won't be needed There is one limitation to variables created within the <%init> section, however: their values won't be seen by any subcomponents you might

define This is true for two reasons First, the subcomponents may

themselves contain an <%init> section, so the relevance of the main

component's <%init> section isn't necessarily clear Second, a

subcomponent may actually be a method (more on this later), in which case

it is accessible to the outside world without first calling the main component,

so the <%init> section never has a chance to run

Sometimes you need to share data between a component and its

subcomponents, however, and for these situations Mason provides the

<%shared>

and <%once> blocks A <%shared> block runs before the main

component or any of its methods or subcomponents and may run

initialization code Any variables created here will be visible to the entire

Trang 7

main component and any of its subcomponents, including the main

component's <%init> section, if any The <%once> block is similar the only difference is that code in the <%once> block won't run every time the component is called It will run only when the component itself is loaded The initialized values will remain intact for the lifetime of the component object, which may be until you make changes to the component source file and Mason reloads it or until the web server child expires and gets replaced

by a new one

A <%shared> section is great when a component and its subcomponents have a tight relationship and may make complicated use of shared data In contrast, <%once> sections are useful for caching values that change

infrequently but may take a long time to compute See Example 5-1

Trang 8

A similar example, but using a <%once> section, is shown in Example 5-2

A cautionary note about the <%shared> and <%once> sections: they do

not let you transparently share data among Apache children (this would

require actual shared memory segments and can be done with modules like IPC::Shareable ), or among multiple components (this can easily be done with global variables) It is also unwise to use variables created in a

<%once> section for saving state information that you intend to change, since the next time the component is loaded your changes will be lost

You should also remember that variables defined via an <%args> block are not visible in a <%shared> block, meaning that the only access to

Trang 9

arguments inside a shared block is via the %ARGS hash or one of the request object methods such as request_args

Methods and Attributes

The ability to use Mason's component-level object-oriented methods and attributes can give you powerful techniques for managing your site

As explained in Chapter 3, one of the major benefits of object-oriented techniques is that they help you reduce redundancy in your site Site

redundancy is a much bigger problem than most people realize How many times have you forgone a site revision because performing the revision would be "too intrusive," and you can't afford the downtime? How many Internet web sites have you seen that look promising at first, but fail to fix problems and don't adapt to usage patterns over the long run? Nobody likes

to be stuck with an unmaintainable site, and the only way to avoid it is to design the site to be adaptable and extensible in the first place Eliminating redundancy goes a long way toward this goal

Methods

Methods in Mason are actually quite simple A method is just like a

subcomponent, but instead of defining it with a <%def> section, you use a

<%method> section:

<%method my_method>

Any regular component syntax here

</%method>

Trang 10

The difference between subcomponents and methods is primarily in how they can be invoked from other components A method can only be invoked using special method syntax We present three ways of doing this here: # Fetch the bottommost child of the current

# Same thing, using <& &> syntax

<& SELF:.my_method &>

Let's think about what happens when you invoke a method Suppose there is

a component called /staff/flintoff.mas, whose parent is /staff/autohandler,

whose parent is in turn /autohandler While any of these components are

executing (which might be when a top-level request comes in for

/staff/flintoff.mas or when /staff/flintoff.mas is called from another

component), calling $m->base_comp from within any of these three components will return a component object representing /staff/flintoff.mas

In the example, that component object is stored in $self Invoking

call_method('.my_method') will search $self and its hierarchy

of parents for a method called my_method, starting the search at $self and proceeding upward If such a method is found, it gets executed If no

Trang 11

such method is found, a fatal error occurs You may want to call

$self->method_exists('.my_method') first if you're not sure whether the method exists

Remember that methods are full-blown subcomponents, so you may also pass them arguments when you invoke them Example 5-3 and Example 5-4

demonstrate a more sophisticated example of method invocation

<body onLoad="prepare_images( )" bgcolor="<%

$bgcolor %>" text="<% $textcolor %>">

Trang 12

<& SELF:.body_tag, bgcolor=>'blue',

including the call to the JavaScript function prepare_images()

Incidentally, note that the autohandler took responsibility for the <html> and </html> tags, while the main component generated everything in the

<head> and <body> sections This is not necessarily good design you must determine the right factorization for each site you create but it made the example straightforward

Now that you know what methods are and how they work, we can explore some ways that you can use them to design your site to be flexible and

maintainable

Using Methods for Titles and Headers

The most familiar example of commonality within a site's structure is

probably the overall design of pages Most web sites want to have a common design structure across multiple pages, including common colors and fonts, common navigational elements and headers, common keywords in <META> tags, and so on In this section, we explore how you can use methods for the

Trang 13

specific problem of generating commonly styled headers and titles for your pages

Generating titles and headers was the major motivation behind developing Mason's method capabilities in the first place Consider for a moment the

"title and header problem": it is often desirable to control the top and bottom

of an HTML page centrally, for all the reasons we've tried to drum into your skull throughout this chapter However, while large portions of the top and bottom of the page may be the same for all pages on your site, certain small pieces may be different on every page titles and headers often fall into this category So, you would like a way to generate the large common portions of your pages centrally but insert the noncommon titles and headers where they belong

Mason's methods provide a perfect answer Each title and header can be specified using a method Then an autohandler can generate the common headers and footers, calling the base component's title and header methods to insert the page-specific information in its proper place (Example 5-5 and

Trang 15

parent hierarchy (autohandler and fancy_page.html in this case) defines a

certain method and that method is invoked, a fatal exception will be thrown

If you don't want to have a default title and header, ensuring that each page sets its own, you can simply omit the default methods in the autohandler If a page fails to set its title or header, you will know it pretty quickly in the development cycle

Remember that methods are Mason components, so they can contain more than just static text You might compute a page's title or header based on information determined at runtime, for example

Methods with Dynamic Content

As you know, methods and inheritance may be used to let a page and its autohandler share the responsibility for generating page elements like

headers and titles Since these elements may often depend on user input or other environmental conditions (e.g., "Welcome, Jon Swartz!" or

"Information about your 9/13/2001 order"), you'll need a way to set these properties (like "Jon Swartz" or "9/13/2001") at run-time Why is this an

issue? Well, the following won't work:

Trang 16

.generate item listing here

The reason that won't work is that variables set in the <%init> block won't

be visible inside the <%method title> block Even if the scope of

$order_date included the <%method title> block (it doesn't), the sequence of events at runtime wouldn't allow its value to be seen:

1 A request for /your_order.html is received Mason constructs the

runtime inheritance hierarchy, assigning /autohandler as

/your_order.html's parent

2 Mason executes the /autohandler component, which invokes its

SELF:title method The title method invoked is the one

4 Control returns to /autohandler, which eventually calls

$m->call_next and passes control to /your_order.html

Trang 17

5 /your_order.html runs its <%init> section and then its main body

Note that it would set $order_date much too late to affect the title method back in step 3

6 /your_order.html finishes and passes control back to /autohandler,

and the request ends

What's a Mason designer to do? The solution is simple: use a <%shared> block instead of an <%init> block to set the $order_date variable This way, the variable can be shared among all the methods of the

/your_order.html component, and it will be set at the proper time (right

before step 2 in the previous listing) for it to be useful when the methods are invoked

The proper code is remarkably similar to the improper code; the only

difference is the name of the block in which the $order_date variable is set:

Your order included the following items:

.generate item listing here

<%shared>

Trang 18

Now imagine another scenario, one in which the method needs to examine the incoming arguments in order to generate its output For instance, suppose you request /view_user.html?id=2982, and you want the title of the page to display some information about user 2982 You'll have to make sure that the user ID is available to the method, because under normal conditions

it isn't The two most common ways to get this information in the method are either for the method to call $m->request_args() or for the

autohandler to pass its %ARGS to the method when calling it The method could then either declare $id in an <%args> block or examine the

incoming %ARGS hash directly An example using request_args() follows:

Trang 19

If you find yourself in this situation, Mason's component attributes may be

of interest An attribute is like a method in the way its inheritance works, but the value of an attribute is a Perl scalar variable, not a Mason component

Example 5-7 and Example 5-8 rewrite our previous autohandler example using attributes instead of methods

Example 5-7 autohandler

<html>

Trang 20

title => "Fancy Page"

header => "A Very Fancy Page"

Ngày đăng: 14/12/2013, 12:15

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN