The Savory Framework, version R81
(See the initial announcement)
So, what do we have here...
- Forms: comprehensive new forms library, including converting all Savory libraries to use it
- Validation: server- and client-side, including reCAPTCHA support
- Console: support for print() and println() shortcuts
- Classes: new "_configure" and "_configureOnly" options for self-configuration classes
- Progress: the old "processing" service was renamed to this
- RPC: can now be configured via a DSL
- Backup: new service for high-performance, multi-threaded backing up MongoDB to real JSON
- JVM: new API: exec
- Files: new APIs: openTextForReading, openTextForWriting
- Lucene: search results are now returned as an interator
- Ext JS: new reCAPTCHA form field widget
- Ext JS Forms: standard, AJAX and Ext Direct
- Ext Direct: support webform calls
- Dependency bumps: MongoDB-Rhino R95
And lots of bug fixes, too many to mention! Hey, we're still in Early Bird mode.
Without doubt, the most exciting addition is the forms API:
There's not that much code here, but it's pretty darn sophisticated. Every web development framework needs good form support, but for a lot of frameworks out there (I've worked with dozens!) this often means that any form that is not trivial becomes an exercize in hacking into the framework code. I've really tried to learn from bad experience elsewhere and design what I hope is a sensible architecture for Savory. I've tested it a lot with various complex forms, and so far I am happy.
Savory handles both standard HTML forms and AJAX forms (such as those used by Ext JS) smoothly. It does both client- and server-side validation, also allowing for internationalization of validation error strings on both the client and the server. And it's very easy to extend and make it do things the way you need them.
Many other JS libraries allow for this, but in Savory I insisted on listing exactly which fields you want merged (and this list is concatenated from inherited classes, unless you use "_configureOnly"). I believe this is better because it avoids users essentially working around constructor limitations. The proper way to solve such problems is to create a new class, not to kludge constructor values.