Introduction to Jifty

6,293 views

Published on

A brief introduction to Jifty using a demo app that emulates Qublog

Published in: Technology, Art & Photos
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,293
On SlideShare
0
From Embeds
0
Number of Embeds
91
Actions
Shares
0
Downloads
19
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Introduction to Jifty

  1. 1. Introduction to Jifty Sterling Hanenkamp, PPW 2008
  2. 2. I Work for a Living
  3. 3. I Work for a Living • Contract work / Billable Hours: How do I track them?
  4. 4. I Work for a Living • Contract work / Billable Hours: How do I track them? • Weekly Status Reports: What did I do?
  5. 5. I Work for a Living • Contract work / Billable Hours: How do I track them? • Weekly Status Reports: What did I do? • Reliable Memory: Did I do that? How? When? Why?
  6. 6. I Work for a Living • Contract work / Billable Hours: How do I track them? • Weekly Status Reports: What did I do? • Reliable Memory: Did I do that? How? When? Why? • Task Lists: What should I do next?
  7. 7. Existing Solutions Time Sheet
  8. 8. Existing Solutions Planner
  9. 9. Existing Solutions Scratch Paper
  10. 10. Existing Solutions
  11. 11. Existing Solutions Things Sunbird Day Planner Hiveminder Entourage Stikkit iCal/Apple Mail Lightning OmniFocus
  12. 12. Qublog
  13. 13. Qublog • I don’t want to store this information in four places
  14. 14. Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus
  15. 15. Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time
  16. 16. Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time • I built Qublog (originally MyToDo and Kiln for a short while)
  17. 17. Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time • I built Qublog (originally MyToDo and Kiln for a short while) • It’s written using Jifty
  18. 18. Qublog • I don’t want to store this information in four places • I have a habit of writing down what I’m doing to focus • I needed something else to do with my lack of spare time • I built Qublog (originally MyToDo and Kiln for a short while) • It’s written using Jifty • We’re going to look at how I did it to explain Jifty
  19. 19. What’s it look like?
  20. 20. What’s it look like?
  21. 21. What’s it look like?
  22. 22. What’s it look like?
  23. 23. What’s it look like?
  24. 24. What’s it look like?
  25. 25. What’s it look like?
  26. 26. What’s it look like?
  27. 27. What’s it look like?
  28. 28. What’s it look like?
  29. 29. What’s it look like?
  30. 30. What’s it look like?
  31. 31. What’s it look like?
  32. 32. What’s it look like?
  33. 33. What’s it look like?
  34. 34. Qublog
  35. 35. Qublog • Provides a Journal for keeping thoughts
  36. 36. Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks
  37. 37. Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks • Journal Comments are grouped into Timers that keep track of time spent
  38. 38. Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks • Journal Comments are grouped into Timers that keep track of time spent • Timers are grouped into Entries to sum up work for reporting
  39. 39. Qublog • Provides a Journal for keeping thoughts • Provides a To Do List for organizing tasks • Journal Comments are grouped into Timers that keep track of time spent • Timers are grouped into Entries to sum up work for reporting • Comments also connect with Tasks to keep track of what’s next
  40. 40. This is a talk about Jifty
  41. 41. This is a talk about Jifty • Not Qublog • Okay, so let’s see if we can build QublogMini in the time remaining...
  42. 42. Install Jifty As with “that-other-framework,” the worst part is over when you finish the install.
  43. 43. Install Jifty
  44. 44. Install Jifty • Method 1: Shipwright
  45. 45. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty
  46. 46. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN
  47. 47. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty
  48. 48. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty “notest” saves ~60 minutes according to Audrey • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty
  49. 49. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty “notest” saves ~60 minutes according to Audrey • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty “notest” will get you no support according to Jesse
  50. 50. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty
  51. 51. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty • ActiveState installation on Windows: http://jifty.org/view/DownloadJifty
  52. 52. Install Jifty • Method 1: Shipwright svn co http://code.bestpractical.com/shipwright/jifty/ jifty-builder cd jifty-builder ./bin/shipwright-builder # optionally --skip perl --skip-test cp -rvp /tmp/jifty-$random/jifty /usr/local/jifty ln -s /usr/local/jifty/bin/jifty /usr/local/bin/jifty • Method 2: CPAN perl -MCPAN -eshell # or just cpan cpan> notest install Jifty • ActiveState installation on Windows: http://jifty.org/view/DownloadJifty • Jifty is in Debian unstable
  53. 53. % jifty app --name QublogMini
  54. 54. % jifty app --name QublogMini Creating new application QublogMini Creating directory QublogMini/lib Creating directory QublogMini/lib/QublogMini Creating directory QublogMini/bin Creating directory QublogMini/etc Creating directory QublogMini/doc Creating directory QublogMini/log Creating directory QublogMini/var Creating directory QublogMini/var/mason Creating directory QublogMini/share Creating directory QublogMini/share/po Creating directory QublogMini/share/web Creating directory QublogMini/share/web/templates Creating directory QublogMini/share/web/static Creating directory QublogMini/lib/QublogMini/Model Creating directory QublogMini/lib/QublogMini/Action Creating directory QublogMini/t Creating configuration file QublogMini/etc/config.yml
  55. 55. % cd QublogMini % find . -type f
  56. 56. % cd QublogMini % find . -type f ./bin/jifty ./etc/config.yml ./Makefile.PL
  57. 57. % ./bin/jifty server
  58. 58. % ./bin/jifty server WARN - Application schema has no version in the database. WARN - Automatically creating your database. INFO - Generating SQL for application QublogMini... INFO - Using Jifty::Model::Session, as it appears to be new. INFO - Using Jifty::Model::Metadata, as it appears to be new. INFO - Set up version v0.0.1, jifty version 0.804080 INFO - You can connect to your server at http://localhost:8888/
  59. 59. % ./bin/jifty server WARN - Application schema has no version in the database. WARN - Automatically creating your database. INFO - Generating SQL for application QublogMini... INFO - Using Jifty::Model::Session, as it appears to be new. INFO - Using Jifty::Model::Metadata, as it appears to be new. INFO - Set up version v0.0.1, jifty version 0.804080 INFO - You can connect to your server at http://localhost:8888/
  60. 60. Take a Look
  61. 61. OMG! Ponies!!!
  62. 62. Not a very interesting journaling app... let’s fix it.
  63. 63. % ./bin/jifty model --name Comment
  64. 64. % ./bin/jifty model --name Comment Writing file t/00-model-Comment.t Writing file lib/QublogMini/Model/Comment.pm
  65. 65. % ./bin/jifty model --name Comment Writing file t/00-model-Comment.t Writing file lib/QublogMini/Model/Comment.pm % vim lib/QublogMini/Model/Comment.pm
  66. 66. package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { };
  67. 67. package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { column commented_on => type is 'datetime', label is 'Commented on', filters are qw( Jifty::DBI::Filter::DateTime ); column name => type is 'text', label is 'Name', render as 'textarea'; };
  68. 68. % bin/jifty server
  69. 69. % bin/jifty server WARN - Application schema has no version in the database. WARN - Automatically creating your database. INFO - Generating SQL for application QublogMini... INFO - Using QublogMini::Model::Comment, as it appears to be new. INFO - Using Jifty::Model::Session, as it appears to be new. INFO - Using Jifty::Model::Metadata, as it appears to be new. INFO - Set up version v0.0.1, jifty version 0.804080 INFO - You can connect to your server at http://localhost: 8888/
  70. 70. % bin/jifty model --name Timer
  71. 71. % bin/jifty model --name Timer Writing file lib/QublogMini/Model/Timer.pm Writing file t/00-model-Timer.t
  72. 72. % bin/jifty model --name Timer Writing file lib/QublogMini/Model/Timer.pm Writing file t/00-model-Timer.t % vim lib/QublogMini/Model/Timer.pm
  73. 73. package QublogMini::Model::Timer; use Jifty::DBI::Schema; use QublogMini::Record schema { };
  74. 74. package QublogMini::Model::Timer; use Jifty::DBI::Schema; use QublogMini::Record schema { column started_on => label is 'Started on', filters are qw( Jifty::DBI::Filter::DateTime ); column stopped_on => label is 'Stopped on', filters are qw( Jifty::DBI::Filter::DateTime ); column comments => references QublogMini::Model::CommentCollection by 'timer'; }; sub since { '0.0.2' }
  75. 75. package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { column commented_on => type is 'datetime', label is 'Commented on', filters are qw( Jifty::DBI::Filter::DateTime ), ; column name => type is 'text', label is 'Name', render as 'textarea', ; };
  76. 76. package QublogMini::Model::Comment; use Jifty::DBI::Schema; use QublogMini::Record schema { column commented_on => type is 'datetime', label is 'Commented on', filters are qw( Jifty::DBI::Filter::DateTime ), ; column name => type is 'text', label is 'Name', render as 'textarea', ; column timer => label is 'Timer', since '0.0.2', references QublogMini::Model::Timer; };
  77. 77. % bin/jifty server
  78. 78. % bin/jifty server WARN - Application schema version in database (v0.0.1) doesn't match application schema version (0.0.2) WARN - Automatically upgrading your database to match the current application schema. Jifty version 0.809130 up to date. Jifty::Plugin::LetMe version v0.0.1 up to date. Jifty::Plugin::SkeletonApp version v0.0.1 up to date. Jifty::Plugin::REST version v0.0.1 up to date. Jifty::Plugin::Halo version v0.0.1 up to date. Jifty::Plugin::ErrorTemplates version v0.0.1 up to date. Jifty::Plugin::OnlineDocs version v0.0.1 up to date. Jifty::Plugin::CompressedCSSandJS version v0.0.1 up to date. Jifty::Plugin::AdminUI version v0.0.1 up to date. INFO - Generating SQL to upgrade QublogMini v0.0.1 database to v0.0.2 INFO - Upgrading through 0.0.2 INFO - Running upgrade script INFO - Upgraded to version v0.0.2 INFO - You can connect to your server at http://localhost:8888/
  79. 79. package QublogMini::Model::Timer; # ... sub name { my $self = shift; $self->started_on . ' to ' . $self->stopped_on }
  80. 80. % bin/jifty model --name Entry
  81. 81. % bin/jifty model --name Entry Writing file t/00-model-Entry.t Writing file lib/QublogMini/Model/Entry.pm
  82. 82. % bin/jifty model --name Entry Writing file t/00-model-Entry.t Writing file lib/QublogMini/Model/Entry.pm % vim lib/QublogMini/Model/Entry.pm
  83. 83. package QublogMini::Model::Entry; use Jifty::DBI::Schema; use QublogMini::Record schema { };
  84. 84. package QublogMini::Model::Entry; use Jifty::DBI::Schema; use QublogMini::Record schema { column name => type is 'text', label is 'Name', is mandatory; column url => type is 'text', label is 'Name'; column timers => references QublogMini::Model::TimerCollection by 'entry'; }; sub since { '0.0.3' }
  85. 85. package QublogMini::Model::Timer; use Jifty::DBI::Schema; use QublogMini::Record schema { # ... column entry => label is 'Entry', since '0.0.3', references QublogMini::Model::Entry; # ... }; sub name { my $self = shift; my $name = ''; $name .= $self->entry->name . ': ' if $self->entry->id; $name .= $self->started_on . ' to ' . $self->stopped_on return $name; }
  86. 86. --- framework: AdminMode: 1 ApplicationClass: QublogMini ApplicationName: QublogMini ApplicationUUID: 1198420A-95A9-11DD-8ED4-3E4643B9151E ConfigFileVersion: 4 Database: AutoUpgrade: 1 CheckSchema: 1 Database: qublogmini Driver: SQLite Host: localhost Password: '' RecordBaseClass: Jifty::DBI::Record::Cachable User: '' Version: 0.0.2
  87. 87. --- framework: AdminMode: 1 ApplicationClass: QublogMini ApplicationName: QublogMini ApplicationUUID: 1198420A-95A9-11DD-8ED4-3E4643B9151E ConfigFileVersion: 4 Database: AutoUpgrade: 1 CheckSchema: 1 Database: qublogmini Driver: SQLite Host: localhost Password: '' RecordBaseClass: Jifty::DBI::Record::Cachable User: '' Version: 0.0.2
  88. 88. --- framework: AdminMode: 1 ApplicationClass: QublogMini ApplicationName: QublogMini ApplicationUUID: 1198420A-95A9-11DD-8ED4-3E4643B9151E ConfigFileVersion: 4 Database: AutoUpgrade: 1 CheckSchema: 1 Database: qublogmini Driver: SQLite Host: localhost Password: '' RecordBaseClass: Jifty::DBI::Record::Cachable User: '' Version: 0.0.3
  89. 89. % bin/jifty server
  90. 90. % bin/jifty server WARN - Application schema version in database (v0.0.2) doesn't match application schema version (0.0.3) WARN - Automatically upgrading your database to match the current application schema. Jifty version 0.809130 up to date. Jifty::Plugin::LetMe version v0.0.1 up to date. Jifty::Plugin::SkeletonApp version v0.0.1 up to date. Jifty::Plugin::REST version v0.0.1 up to date. Jifty::Plugin::Halo version v0.0.1 up to date. Jifty::Plugin::ErrorTemplates version v0.0.1 up to date. Jifty::Plugin::OnlineDocs version v0.0.1 up to date. Jifty::Plugin::CompressedCSSandJS version v0.0.1 up to date. Jifty::Plugin::AdminUI version v0.0.1 up to date. INFO - Generating SQL to upgrade QublogMini v0.0.2 database to v0.0.3 INFO - Upgrading through 0.0.3 INFO - Running upgrade script INFO - Upgraded to version v0.0.3 INFO - You can connect to your server at http://localhost:8888/
  91. 91. Ponies are great!
  92. 92. Ponies are But where’s the UI? great!
  93. 93. # Dispatcher maps URLs to Views % vim lib/QublogMini/Dispatcher.pm
  94. 94. package QublogMini::Dispatcher; use Jifty::Dispatcher -base;
  95. 95. package QublogMini::Dispatcher; use Jifty::Dispatcher -base; on '/' => dispatch '/today';
  96. 96. package QublogMini::Dispatcher; use Jifty::Dispatcher -base; on '/' => dispatch '/today'; on '/today' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; show '/today'; };
  97. 97. package QublogMini::View; use Jifty::View::Declare -base; template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; } };
  98. 98. template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; show '/timers', $entry; } };
  99. 99. private template '/timers' => sub { my ($self, $entry) = @_; my $timers = $entry->timers; while (my $timer = $timers->next) { show '/show_comment', $timer->stopped_on, _('Stopped timer.') if $timer->stopped_on; show '/comments', $timer; show '/show_comment', $timer->started_on, _('Started timer.'); } };
  100. 100. private template '/comments' => sub { my ($self, $timer) = @_; my $comments = $timer->comments; while (my $comment = $comments->next) { show '/show_comment', $comment->commented_on, $comment->name; } }; private template '/show_comment' => sub { my ($self, $time, $message) = @_; p { { class is 'time' } $time }; p { { class is 'comment' } $message }; };
  101. 101. Fine. We already knew that. Where’s the “interface”?
  102. 102. template '/today' => page { { title is quot;Today's Journalquot; } form { render_region name => 'add_entry', path => '/add_entry_button', ; }; my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url; }; show '/timers', $entry; } };
  103. 103. template '/add_entry_button' => sub { form_submit label => _('Add Entry'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_form', }, ; };
  104. 104. template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => { submit => $entry_action, region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
  105. 105. Where’d it go?
  106. 106. Where’d it go? 2 Problems
  107. 107. Where’d it go? 2 Problems We need a timer too.
  108. 108. Where’d it go? 2 Problems We need a timer too. We need to redraw the journal.
  109. 109. package QublogMini::Model::Entry; use Jifty::DBI::Schema; use DateTime; # ... # Add a timer when we add an entry sub after_create { my ($self, $id) = @_; return unless $$id; my $timer = QublogMini::Model::Timer->new; $timer->create( entry => $$id, started_on => DateTime->now, ); return 1; }
  110. 110. template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; show '/timers', $entry; } };
  111. 111. template '/today' => page { { title is quot;Today's Journalquot; } my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url }; show '/timers', $entry; } };
  112. 112. # Replace /today with a region template '/today' => page { { title is quot;Today's Journalquot; } render_region name => 'entries', path => '/entries', ; };
  113. 113. # Replace /today with a region template '/today' => page { { title is quot;Today's Journalquot; } render_region name => 'entries', path => '/entries', ; };
  114. 114. # Add a new entries fragment template '/entries' => sub { form { render_region name => 'add_entry', path => '/add_entry_button', ; }; my $entries = get 'entries'; while (my $entry = $entries->next) { h2 { $entry->name }; p { hyperlink label => $entry->url, url => $entry->url; }; show '/timers', $entry; } };
  115. 115. on '/today' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; };
  116. 116. on '/today' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; };
  117. 117. on '/entries' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '>=', value => DateTime->today, entry_aggregator => 'AND', ); $entries->limit( alias => $timer_alias, column => 'started_on', operator => '<', value => DateTime->today->add( days => 1 ), entry_aggregator => 'AND', ); set entries => $entries; };
  118. 118. template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => { submit => $entry_action, region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
  119. 119. template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => { submit => $entry_action, region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
  120. 120. # Make our entry form update everything properly template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => [ { submit => $entry_action, }, { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, { refresh => Jifty->web->current_region->parent, }, ], ; };
  121. 121. # Make our entry form update everything properly template '/add_entry_form' => sub { my $entry_action = new_action class => 'CreateEntry'; render_action $entry_action, [ qw( name url ) ]; form_submit label => _('Add Entry'), onclick => [ { submit => $entry_action, }, { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, { refresh => Jifty->web->current_region->parent, }, ], ; };
  122. 122. Bummer. Wrong Order.
  123. 123. Bummer. Wrong Order.
  124. 124. on '/entries' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); # ... $entries->order_by({ alias => $timer_alias, column => 'started_on', order => 'DES', }); set entries => $entries; };
  125. 125. on '/entries' => run { my $entries = QublogMini::Model::EntryCollection->new; my $timer_alias = $entries->join( column1 => 'id', table2 => QublogMini::Model::Timer->table, column2 => 'entry', ); # ... $entries->order_by({ alias => $timer_alias, column => 'started_on', order => 'DES', }); set entries => $entries; };
  126. 126. We have entries and timers, but what about comments?
  127. 127. package QublogMini::Model::Comment; use Jifty::DBI::Schema; use DateTime; # ... sub before_create { my ($self, $args) = @_; $args->{commented_on} = DateTime->now; return 1; }
  128. 128. template '/add_entry_button' => sub { form_submit label => _('Add Entry'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_form', }, ; form_submit label => _('Add Comment'), onclick => { region => Jifty->web->current_region, replace_with => '/add_comment_form', }, ; };
  129. 129. template '/add_entry_button' => sub { form_submit label => _('Add Entry'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_form', }, ; form_submit label => _('Add Comment'), onclick => { region => Jifty->web->current_region, replace_with => '/add_comment_form', }, ; };
  130. 130. template '/add_comment_form' => sub { my $timer = QublogMini::Model::Timer->new; $timer->load_current; # loads the latest running timer my $comment_action = new_action class => 'CreateComment'; render_action $comment_action, [ qw( name ) ]; form_submit label => _('Add Comment'), onclick => [ { submit => { action => $comment_action, arguments => { timer => $timer->id, }, }, }, { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, { refresh => Jifty->web->current_region->parent, }, ], ; # ...
  131. 131. # ... form_submit label => _('Cancel'), onclick => { region => Jifty->web->current_region, replace_with => '/add_entry_button', }, ; };
  132. 132. What about Validation
  133. 133. What about Validation • Easy
  134. 134. What about Validation • Easy • Add a validate_XXX method to the model
  135. 135. What about Validation • Easy • Add a validate_XXX method to the model • Let’s try it
  136. 136. sub validate_url { my ($self, $url) = @_; if ($url !~ m[^https?://]) { return (0, 'That does not look like a URL.'); } return 1; }
  137. 137. Canonicalization
  138. 138. Canonicalization • You can also canonicalize something
  139. 139. Canonicalization • You can also canonicalize something • What the heck is that?
  140. 140. Canonicalization • You can also canonicalize something • What the heck is that? • Rather than slap their hand, fix it for them
  141. 141. Canonicalization • You can also canonicalize something • What the heck is that? • Rather than slap their hand, fix it for them • For example, we could... (but won’t)...
  142. 142. sub canonicalize_url { my ($self, $url) = @_; if ($url !~ m[^https?://]) { return 'http://'.$url; } return $url; }
  143. 143. sub canonicalize_url { my ($self, $url) = @_; if ($url !~ m[^https?://]) { return 'http://'.$url; } return $url; Too naïve, I refuse to } implement it!
  144. 144. But it was the best I could come up with on sub canonicalize_url { short notice. my ($self, $url) = @_; if ($url !~ m[^https?://]) { return 'http://'.$url; } return $url; Too naïve, I refuse to } implement it!
  145. 145. Halos
  146. 146. Halos
  147. 147. Halos
  148. 148. Halos I’m the view code for this “frame” in the page!
  149. 149. Halos
  150. 150. Halos
  151. 151. Halos
  152. 152. Halos View the HTML source, Luke.
  153. 153. Halos
  154. 154. Halos
  155. 155. Halos
  156. 156. Page Info
  157. 157. Page Info
  158. 158. Page Info
  159. 159. Page Info
  160. 160. Page Info
  161. 161. Page Info
  162. 162. Page Info • Click on things to view info
  163. 163. Page Info • Click on things to view info • SQL Logging
  164. 164. Page Info • Click on things to view info • SQL Logging • SQL Profiling
  165. 165. Page Info • Click on things to view info • SQL Logging • SQL Profiling • Template Profiling
  166. 166. Developer Mode
  167. 167. Developer Mode • Module::Refresh
  168. 168. Developer Mode • Module::Refresh • Tracing with Log4Perl
  169. 169. Developer Mode • Module::Refresh • Tracing with Log4Perl • Administration Console
  170. 170. Developer Mode • Module::Refresh • Tracing with Log4Perl • Administration Console • (actually, that’s Administrator Mode)
  171. 171. Deployment
  172. 172. Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment)
  173. 173. Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment) • Choice of DB servers: SQLite (great for getting started/testing, but production is possible), PostgreSQL, MySQL, and other servers supported
  174. 174. Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment) • Choice of DB servers: SQLite (great for getting started/testing, but production is possible), PostgreSQL, MySQL, and other servers supported • Use a fast static server to server CSS, JS, images, etc.
  175. 175. Deployment • Choice of web servers: FastCGI on Apache / Lighttpd, HTTP::Server::Simple, mod_perl support (a little weak at the moment) • Choice of DB servers: SQLite (great for getting started/testing, but production is possible), PostgreSQL, MySQL, and other servers supported • Use a fast static server to server CSS, JS, images, etc. • Use CSS::Squish and JS::Squish to help compress and cache things
  176. 176. Other Goodies
  177. 177. Other Goodies • Several authentication plugins: typical email sign-up login, OpenID, Facebook, LDAP, CAS • Additional CRUD view helpers I haven’t demonstrated • Built-in REST interface • Full I18N support built-in • Several Plugins for lots of things: Comments, Single Page Apps, Client-Side Templating, Charting, Tab helpers • Built-in support for Comet (server push) in addition to Ajax
  178. 178. Applications
  179. 179. Applications • Hiveminder (http://hiveminder.com)
  180. 180. Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org)
  181. 181. Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net)
  182. 182. Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net) • Doxory (http://doxory.com)
  183. 183. Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net) • Doxory (http://doxory.com) • CommitBit (http://code.bestpractical.com/)
  184. 184. Applications • Hiveminder (http://hiveminder.com) • Wifty (http://jifty.org) • Qublog (http://qublog.net) • Doxory (http://doxory.com) • CommitBit (http://code.bestpractical.com/) • Ping / Chat / Clock (examples available with Jifty)
  185. 185. Jifty Resources
  186. 186. Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/)
  187. 187. Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org)
  188. 188. Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org)
  189. 189. Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod)
  190. 190. Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod) • Manual (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual.pod)
  191. 191. Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod) • Manual (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual.pod) • Mailing List: jifty‐devel@lists.jifty.org
  192. 192. Jifty Resources • CPAN (http://search.cpan.org/dist/Jifty/) • Jifty Wiki (http://jifty.org) • Jifty SVN (http://svn.jifty.org/svn/jifty.org) • Tutorial (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual/Tutorial.pod) • Manual (http://search.cpan.org/dist/Jifty/lib/Jifty/Manual.pod) • Mailing List: jifty‐devel@lists.jifty.org • IRC Channel: #jifty on irc.freenode.org
  193. 193. Qublog • See http://qublog.net • Sample code for QublogMini in SVN: http://qublog.net/svn/QublogMini
  194. 194. Thank you!

×