Config-JFDI 0.04 should be on CPAN shortly
Config::JFDI mimics Catalyst::Plugin::ConfigLoader (without the need to load Catalyst). The new features in this release are:
I've just released Doc::Simply, a tool for generating documentation from JavaScript (or C, C++, etc.) comments.
I use it to for my b9j documentation
The idea came to me while developing some JavaScript: I was craving a way to drop in free-form documentation in a .js file as easily as I could in a .pm with perlpod.
The Doc::Simply format is modeled after Plain-Old-Documentation, but it is not an exact mimic. Body formatting, for example, is in Markdown (no C<>, L<>, ...)
However, if you are craving pure POD, then it shouldn't be too difficult to bolt a proper parser/generator on top of Doc::Simply
You can run it from the command-line as doc-simply
doc-simply < source.js > documentation.html
doc-simply --help
An example:
/*
* @head1 NAME
*
* Calculator - Add 2 + 2 and return the result
*
*/
// @head1 DESCRIPTION
// @body Add 2 + 2 and return the result (which should be 4)
/*
* @head1 FUNCTIONS
*
* @head2 twoPlusTwo
*
* Add 2 and 2 **and** return 4
*
*/
function twoPlusTwo() {
return 2 + 2; // Should return 4
}
/*
* @head1 AUTHOR
*
* Alice <alice@example.com>
*
* [http://example.com](http://example.com)
*
*/
... which will generate this document
You can download it from http://search.cpan.org/CPAN/authors/id/R/RK/RKRIMEN/Doc-Simply-0.02.tar.gz
... or install it via cpan:
cpan -i Doc::Simply
I've put together an interactive example of my JavaScript URI object:
The example will also show the code necessary to perform the given operation (next to the result)
b9j.uri.URI overview:
The code is available at http://appengine.bravo9.com/b9j/b9j.uri.js (19kb compressed / 5kb gzipped)
See also the documentation for b9j.uri
Following my b9j.path release, I just finished up work on URI object-class for javascript.
It uses Steven Levithan's parseUri 1.2 to do the parsing.
Some example usage:
var uri = new b9j.uri.URI( "http://example.com/a/b?a=1&b=2&c=3&c=4&c=5" )
var host = uri.host()
var child = uri.child("c.html") // http://example.com/a/b/c.html?a=1&b=2& ...
child.query().add({ c: [ 6, 7 ], d: 8 }) // ... ?a=1&b=2&c=3&c=4&c=5&c=6&c=7&d=8
child.query().set("b", 9) // ... ?a=1&b=9&c ...
return child.toString()
Again, while CPAN has URI.pm for URI-handling, JavaScript didn't really have an equivalent (parsing yes -- modifying/generating no).
b9j.path provides a way to parse, manipulate, and generate URI/UNIX-style paths.
CPAN provides lots of different options for path-handling and path-manipulation, but there didn't seem to be anything really available in JavaScript-land.
To fill the gap, I've released b9j.path:
var path = new b9j.path.Path("/a/b/c")
// /a/b/c/xyzzy
var child = path.child("xyzzy")
// /a/b
var parent = path.parent()
// ... and much, much, more...
It's part of my b9j javascript pack available at: http://appengine.bravo9.com/b9j/b9j-latest.zip
YUI Test is a great tool for javascript testing, but it has a couple of small issues:
b9jTest addresses the problems above by:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>b9jTest example</title>
<link rel="stylesheet" type="text/css"
href="http://appengine.bravo9.com/b9j/b9jTest.css">
<script type="text/javascript"
src="http://appengine.bravo9.com/b9j/b9jTest.js"></script>
</head>
<body class="yui-skin-sam">
<div id="testLogger"></div>
<script type="text/javascript">
b9jTest(function(test) {
test.areEqual("xyzzy", "xyzzy");
test.areEqual("apple", "apple");
test.areEqual("banana", "banana");
});
</script>
</body>

b9jTest() is a global function that accepts a function that is called with a testing object. The testing object provides access to the standard YUI assertions and more.
Documentation:
http://appengine.bravo9.com/b9j/documentation/b9jTest.html
Download:
b9jTest.js
b9jTest.css
Example of copying text into the clipboard
Firefox won't allow copying text into the clipboard via javascript for a variety of reasons.
For better or worse, you can get around this problem with a little .swf (Flash):
function copyIntoClipboard(text) {
var flashId = 'flashId-HKxmj5';
/* Replace this with your clipboard.swf location */
var clipboardSWF = 'http://appengine.bravo9.com/copy-into-clipboard/clipboard.swf';
if(!document.getElementById(flashId)) {
var div = document.createElement('div');
div.id = flashId;
document.body.appendChild(div);
}
document.getElementById(flashId).innerHTML = '';
var content = '<embed src="' +
clipboardSWF +
'" FlashVars="clipboard=' + encodeURIComponent(text) +
'" width="0" height="0" type="application/x-shockwave-flash"></embed>';
document.getElementById(flashId).innerHTML = content;
}
The above trick will also work in Safari, IE, and Opera.
Download clipboard.swf
Alternatively, you can use the Google App Engine hosted version at
http://appengine.bravo9.com/copy-into-clipboard/clipboard.swf
(Originally adapted from http://www.jeffothy.com/weblog/clipboard-copy/)
Getopt::Chain will help you make your command-line scripts work like this:
./script --opt --opt=<value> cmd --opt ...
./script cmd ...
NOTE: Any option specification covered by Getopt::Long is fair game.
Here is some example usage:
#!/usr/bin/perl -w
use strict;
use Getopt::Chain;
# A partial, pseudo-reimplementation of git(1):
Getopt::Chain->process(
options => [qw/ version bare git-dir=s /]
run => sub {
my $context = shift;
my @arguments = @_; # Remaining, unparsed arguments
# ... do stuff before any subcommand ...
}
commands => {
init => {
options => [qw/ quiet|q --template=s /]
run => sub {
my $context = shift;
my @arguments = @_; # Again, remaining unparsed arguments
# ... do init stuff ...
}
}
commit => {
options => [qw/ all|a message|m=s /]
run => sub {
my $context = shift;
# ... do commit stuff ..
}
}
add => ...
help => ...
...
}
)
# The above will allow the following (example) usage:
#
# ./script --version
# ./script --git-dir path/to/repository init
# ./script --git-dir path/to/repository commit -a --message '...'
# ./script commit -m '~'
The source repository is on GitHub: http://github.com/robertkrimen/getopt-chain/tree/master
my $params = Hash::Param->new(parameters => {
qw/a 1 b 2 c 3/,
d => [qw/4 5 6 7/],
})
$result = $params->param( a ) # Returns 1
$result = $params->param( d ) # Returns 4
@result = $params->param( d ) # Returns 4, 5, 6, 7
@result = $params->params # Returns a, b, c, d
$result = $params->params # Returns { a => , b => 2,
c => 3, d => [ 4, 5, 6, 7 ] }
@result = $params->params( a, b, d ) # Returns 1, 2, [ 4, 5, 6, 7 ]
%result = $params->slice( a, b ) # Returns a => 1, b => 2
$params->param( a => 8 ) # Sets a to 8
$params->param( a => 8, 9 ) # Sets a to [ 8, 9 ]
The source repository is on GitHub: http://github.com/robertkrimen/hash-param/tree/master
my $comments = String::Comments::Extract::C->extract($source)
String::Comments::Extract is a tool for extracting comments from C/C++/JavaScript/Java. The extractor is implemented using an actual tokenizer (written in C via XS [adapted from JavaScript::Minifier::XS]). By using a tokenizer, it can correctly deal with notoriously problematic cases, such as comment-like structures embedded in strings:
std::cout << "This is not a // real C++ comment " << std::endl
printf("/* This is not a real C comment */\n");
# The extractor will ignore both of the above
The source repository is on GitHub: http://github.com/robertkrimen/string-comments-extract/tree/master
with Module::Install, add the following to your Makefile.PL:
resources repository => 'http://...';
with MakeMaker, add the following to WriteMakefile (thanks claes):
EXTRA_META => q{
resources:
repository: http://.../ [...]
},
Example of a simple lightbox (modal) dialog with YUI
A lightbox (modal) dialog is an effective way to bring attention to an input form or important message.
You'll need the following YUI assets:
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset-fonts-grids/reset-fonts-grids.css">
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/container/assets/skins/sam/container.css">
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.2/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.2/build/container/container-min.js"></script>
The easiest way to make a lightbox in YUI is to construct a YAHOO.widget.Panel and use .setBody to put in content:
var panel = new YAHOO.widget.Panel(
"panel", // The element id
{
width: "480px",
fixedcenter: true,
close: false,
draggable: false,
zindex: 4,
modal: true,
visible: false
}
);
panel.setBody("<p>Aliquam ultrices. Nulla dictum, augue et condimentum commodo.</p>");
panel.render(document.body);
panel.show();
One gotcha to keep in mind is that the class attribute of the page <body> must include yui-skin-sam. The yui-skin-sam class is necessary to provide:
Another gotcha with the example is that you cannot change the content after rendering (doing so will cause the close link to stop working). This has to do with associating an event handler with a DOM node and then destroying that node when you change the content. Event delegation is a good solution to this problem.
Just released Google::AJAX::Library for accessing the Google AJAX Libraries API in Perl.
Here is some example usage:
use Google::AJAX::Library;
my $library = Google::AJAX::Library->jquery;
$library->uri
# http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
$library->html
# <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
Usually when you want to serve static content from within a dynamic application, you have to designate a special folder, such as /static/ (or have your code serve static files). The web server then understands that a request hitting /static/ should be served from the file system and not by the application.
Below is an Apache configurion for layering a FastCGI application on top of a static directory using mod_alias and mod_rewrite. With this method, you can put static files anywhere you want, if a file exists in your DocumentRoot, then Apache will serve the file instead of letting your code handle the request.
DocumentRoot /var/www/htdocs
# Set up virtual file as http://example.net/.fcgi
FastCgiExternalServer /var/www/htdocs/.fcgi -host 127.0.0.1:8000
# First, alias the static content to http://example.net/htdocs
Alias /htdocs /var/www/htdocs/
# ... configure the virtual fastcgi file, as usual (if no static file exists,
# the request will get passed to your application)
Alias / /var/www/htdocs/.fcgi/
# Make sure the rewriting phase skips http://example.net/htdocs
# and http://example.net/.fcgi
RewriteCond $1 !^(htdocs|.fcgi)/?$
# If a file OR directory matching the request exists...
RewriteCond "/var/www/htdocs/$1" -f [OR]
RewriteCond "/var/www/htdocs/$1/index.html" -f
# ...then rewrite the request to use our fake static
# content alias (which is actually the DocumentRoot)
RewriteRule ^/(.*)$ /htdocs/$1
# If the request is for a directory, then make sure to serve up index.html
RewriteCond "/var/www/htdocs/$1" -d
RewriteRule ^/htdocs/(.*)/?$ /htdocs/$1/index.html
# Finally, signal that rewriting is done and pass-through
# the request to the alias handler
RewriteRule ^/htdocs/ - [L,PT]
I fleshed this out with Catalyst in mind, but it should work for any mod_fastcgi application.