505
Jifty 唐鳳 1

Jifty - pugs.blogs.com · ⚁ 明天飛日本 ⚁ 在 YAPC::Asia ... ♨簡單的事情 = 輕鬆完成 18. Jifty ♨網站應用程式框架 ♨簡單的事情 = 輕鬆完成 ♨複雜的事情

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Jifty♨

唐鳳

1

⚁2

2007/04/01

3

2007/04/01

⚁ 明天飛日本

3

2007/04/01

⚁ 明天飛日本

⚁ 在YAPC::Asia要講兩場

3

2007/04/01

⚁ 明天飛日本

⚁ 在YAPC::Asia要講兩場

⚁ 糟:簡報還沒寫!

3

<@ij1iao>JIT流簡報

4

<@ij1iao>JIT流簡報

4

<@ij1iao>JIT流簡報

4

兩難

5

兩難

⚁ 有兩場演講

5

兩難

⚁ 有兩場演講

⚁ 要先做哪份簡報?

5

兩難

⚁ 有兩場演講

⚁ 要先做哪份簡報?

⚁ 糟:拿不定主意!

5

6

7

7

8

鬆了一口氣

9

鬆了一口氣

⚁ 坐等大家幫我下決定

9

鬆了一口氣

⚁ 坐等大家幫我下決定

⚁ 完全不急著準備簡報了

9

鬆了一口氣

⚁ 坐等大家幫我下決定

⚁ 完全不急著準備簡報了

⚁ 閒來無事,幫別人做決定吧!

9

Pick!

10

Pick!

“偽兩難”

10

Pick!

11

Pick!

11

Pick!

12

Pick!

12

Pick!

13

Pick!

13

Pick!

14

一小時過去了...

15

...開票!

16

♨17

Jifty

18

Jifty

♨網站應用程式框架

18

Jifty

♨網站應用程式框架♨簡單的事情=輕鬆完成

18

Jifty

♨網站應用程式框架♨簡單的事情=輕鬆完成

♨複雜的事情=輕鬆完成

18

Jifty=JFDI

19

Jifty=JFDI

♨ JustF*ckingDoIt

19

Jifty=JFDI

♨ JustF*ckingDoIt

♨讓大家JFDI

19

Jifty=JFDI

♨ JustF*ckingDoIt

♨讓大家JFDI

♨直接來寫Doxory!

19

20

•$cpan

20

•$cpan•cpan>notestinstallJifty

20

•$cpan•cpan>notestinstallJifty

“notest”可以省一小時的時間.

20

21

• $jiftyapp‐‐nameDoxory

21

• $jiftyapp‐‐nameDoxory• CreatingnewapplicationDoxory

CreatingdirectorylibCreatingdirectorylib/DoxoryCreatingdirectorybinCreatingdirectoryetcCreatingdirectorydocCreatingdirectorylogCreatingdirectoryvarCreatingdirectoryvar/masonCreatingdirectoryshareCreatingdirectoryshare/poCreatingdirectoryshare/webCreatingdirectoryshare/web/templatesCreatingdirectoryshare/web/staticCreatingdirectorylib/Doxory/ModelCreatingdirectorylib/Doxory/ActionCreatingdirectorytCreatingconfigurationfileDoxory/etc/config.yml

21

三份檔案

22

三份檔案

♨ bin/jifty

22

三份檔案

♨ bin/jifty

♨ etc/config.yml

22

三份檔案

♨ bin/jifty

♨ etc/config.yml

♨ Makefile.PL

22

23

• $jiftyserver

23

• $jiftyserver• INFO‐Youcanconnecttoyourserverat

http://localhost:8888/

23

動了!

24

動了!

這並不是Doxory.使用者(Users)在哪裡?

24

25

•$cdDoxory

25

•$cdDoxory

•$jiftymodel‐‐nameUser

25

•$cdDoxory

•$jiftymodel‐‐nameUser•Writingfilet/00‐model‐User.tWritingfilelib/Doxory/Model/User.pm

25

•$cdDoxory

•$jiftymodel‐‐nameUser•Writingfilet/00‐model‐User.tWritingfilelib/Doxory/Model/User.pm

•$vimlib/Doxory/Model/User.pm

25

• packageDoxory::Model::User;• useJifty::DBI::Schema;• • useDoxory::Recordschema{•

• • };

26

• packageDoxory::Model::User;• useJifty::DBI::Schema;• • useDoxory::Recordschema{• • columnname=>• labelis'Username',• hintsis'Otherpeopleseethiswhenyouaskquestions.',• isdistinct,• ismandatory;• • columnemail=>• labelis'Email',• hintsis'Wewillnotsellittoanybody.Honest.',• defaultis'',• isdistinct,• isimmutable;• • };

27

28

• $jiftyschema‐‐setup

28

• $jiftyschema‐‐setup• INFO‐GeneratingSQLforapplicationDoxory...

INFO‐UsingDoxory::Model::UserINFO‐UsingJifty::Model::SessionINFO‐UsingJifty::Model::MetadataINFO‐Setupversionv0.0.1,jiftyversion0.701170

28

• $jiftyschema‐‐setup• INFO‐GeneratingSQLforapplicationDoxory...

INFO‐UsingDoxory::Model::UserINFO‐UsingJifty::Model::SessionINFO‐UsingJifty::Model::MetadataINFO‐Setupversionv0.0.1,jiftyversion0.701170

•$jiftyserver&

28

• $jiftyschema‐‐setup• INFO‐GeneratingSQLforapplicationDoxory...

INFO‐UsingDoxory::Model::UserINFO‐UsingJifty::Model::SessionINFO‐UsingJifty::Model::MetadataINFO‐Setupversionv0.0.1,jiftyversion0.701170

•$jiftyserver&

• INFO‐Youcanconnecttoyourserverathttp://localhost:8888/

28

• $jiftyschema‐‐setup• INFO‐GeneratingSQLforapplicationDoxory...

INFO‐UsingDoxory::Model::UserINFO‐UsingJifty::Model::SessionINFO‐UsingJifty::Model::MetadataINFO‐Setupversionv0.0.1,jiftyversion0.701170

•$jiftyserver&

• INFO‐Youcanconnecttoyourserverathttp://localhost:8888/

• $openhttp://localhost:8888/

28

29

29

30

30

31

31

32

32

33

AudreyT

33

AudreyT

33

34

接著來寫選擇題(Choice)模型.

34

35

•$jiftymodel‐‐nameChoice

35

•$jiftymodel‐‐nameChoice•Writingfilet/00‐model‐Choice.tWritingfilelib/Doxory/Model/Choice.pm

35

•$jiftymodel‐‐nameChoice•Writingfilet/00‐model‐Choice.tWritingfilelib/Doxory/Model/Choice.pm

•$vimlib/Doxory/Model/Choice.pm

35

• packageDoxory::Model::Choice;• useJifty::DBI::Schema;• useDoxory::Recordschema{• • columnname=>• labelis'Ineedhelpdeciding...',• renderas'textarea';• • columna=>• labelis'Ontheonehand',• renderas'textarea',ismandatory;

• columnb=>• labelis'Ontheotherhand',• renderas'textarea',ismandatory;

• columnasked_by=>• labelis'Askedby',• defaultisdefer{Jifty‐>web‐>current_user‐>id},• referencesDoxory::Model::User;• • };

36

37

• $jiftyschema‐‐drop‐database‐‐setup

37

• $jiftyschema‐‐drop‐database‐‐setup• INFO‐GeneratingSQLforapplicationDoxory...

INFO‐UsingDoxory::Model::UserINFO‐UsingDoxory::Model::ChoiceINFO‐UsingJifty::Model::SessionINFO‐UsingJifty::Model::MetadataINFO‐Setupversionv0.0.1,jiftyversion0.701170

37

• $jiftyschema‐‐drop‐database‐‐setup• INFO‐GeneratingSQLforapplicationDoxory...

INFO‐UsingDoxory::Model::UserINFO‐UsingDoxory::Model::ChoiceINFO‐UsingJifty::Model::SessionINFO‐UsingJifty::Model::MetadataINFO‐Setupversionv0.0.1,jiftyversion0.701170

• $openhttp://localhost:8888/

37

38

38

39

39

40

40

41

41

42

42

43

做完了!...可是使用者要怎麼登入呢?

43

✍44

45

•$vimetc/config.yml

45

•$vimetc/config.yml

這裡要加兩列設定.

45

•‐‐‐•framework:•Plugins:•‐SkeletonApp:{}•‐REST:{}•‐Halo:{}•‐ErrorTemplates:{}•‐CompressedCSSandJS:{}••

•46

•‐‐‐•framework:•Plugins:•‐SkeletonApp:{}•‐REST:{}•‐Halo:{}•‐ErrorTemplates:{}•‐CompressedCSSandJS:{}•‐Authentication::Password:{}•SkipAccessControl:1

•47

•‐‐‐•framework:•Plugins:•‐SkeletonApp:{}•‐REST:{}•‐Halo:{}•‐ErrorTemplates:{}•‐CompressedCSSandJS:{}•‐Authentication::Password:{}•SkipAccessControl:1

• 懶得定義存取權限規則(ACL).

47

48

•$vimlib/Doxory/Model/User.pm

48

•$vimlib/Doxory/Model/User.pm

為User.pm加上兩個mixin.

48

• packageDoxory::Model::User;• useJifty::DBI::Schema;• useDoxory::Recordschema{• • columnname=>• labelis'Username',• hintsis'Otherpeopleseethiswhenyouaskquestions.',• isdistinct,• ismandatory;• • columnemail=>• labelis'Email',• hintsis'Wewillnotsellittoanybody.Honest.',• defaultis'',• isdistinct,• isimmutable;

• };

•49

• packageDoxory::Model::User;• useJifty::DBI::Schema;• useDoxory::Recordschema{• • columnname=>• labelis'Username',• hintsis'Otherpeopleseethiswhenyouaskquestions.',• isdistinct,• ismandatory;• • columnemail=>• labelis'Email',• hintsis'Wewillnotsellittoanybody.Honest.',• defaultis'',• isdistinct,• isimmutable;

• };

• useJifty::Plugin::User::Mixin::Model::User;• useJifty::Plugin::Authentication::Password::Mixin::Model::User;

50

51

51

52

52

53

From: Doxory <>Date: April 3, 2007 5:43:07 PM JSTTo: [email protected]: 歡迎光臨 Doxory!

您 (或自稱是您的某人) 在 Doxory 申請註冊新帳號.

請點擊以下鏈結, 以確認您的電郵位址:

http://127.0.0.1:8888/let/jesse%40bestpractical.com/confirm_email/78f28e934cf6c058

53

From: Doxory <>Date: April 3, 2007 5:43:07 PM JSTTo: [email protected]: 歡迎光臨 Doxory!

您 (或自稱是您的某人) 在 Doxory 申請註冊新帳號.

請點擊以下鏈結, 以確認您的電郵位址:

http://127.0.0.1:8888/let/jesse%40bestpractical.com/confirm_email/78f28e934cf6c058

53

54

54

55

登入成功了...(網頁界面呢?)

55

❁56

57

•$vimlib/Doxory/Dispatcher.pm

57

•$vimlib/Doxory/Dispatcher.pm

Dispatcher負責將網址對映到頁面(View).

57

58

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

58

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

58

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;$top‐>child('Choices'=>url=>'/choices');

58

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;$top‐>child('Choices'=>url=>'/choices');

• }

58

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;$top‐>child('Choices'=>url=>'/choices');

• }• elsif($1!~/^login|^signup/){

tangent'login';}};

58

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;$top‐>child('Choices'=>url=>'/choices');

• }• elsif($1!~/^login|^signup/){

tangent'login';}};

• #on'/'=>show'/';

58

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;$top‐>child('Choices'=>url=>'/choices');

• }• elsif($1!~/^login|^signup/){

tangent'login';}};

• #on'/'=>show'/';• #on'/choices'=>show'choices';

58

59

接著來寫“/”頁面.

59

60

•$vimlib/Doxory/View.pm

60

•$vimlib/Doxory/View.pm

TT2退散!Mason退散!

60

61

• packageDoxory::View;useJifty::View::Declare‐base;

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';• };

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';• };

• privatetemplatenew_choice=>sub{div{form{

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';• };

• privatetemplatenew_choice=>sub{div{form{

• my$action=new_action(class=>'CreateChoice');

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';• };

• privatetemplatenew_choice=>sub{div{form{

• my$action=new_action(class=>'CreateChoice');• render_action($action=>['name','a','b']);

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';• };

• privatetemplatenew_choice=>sub{div{form{

• my$action=new_action(class=>'CreateChoice');• render_action($action=>['name','a','b']);• form_submit(label=>'AsktheCrowd!');

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';• };

• privatetemplatenew_choice=>sub{div{form{

• my$action=new_action(class=>'CreateChoice');• render_action($action=>['name','a','b']);• form_submit(label=>'AsktheCrowd!');• }}

61

• packageDoxory::View;useJifty::View::Declare‐base;

•template'/'=>page{h1{'Askaquestion!'}

• show'new_choice';• };

• privatetemplatenew_choice=>sub{div{form{

• my$action=new_action(class=>'CreateChoice');• render_action($action=>['name','a','b']);• form_submit(label=>'AsktheCrowd!');• }}• };

61

62

62

63

columna=>labelis'Ontheonehand',renderas'textarea',ismandatory;

63

64

64

65

然後輪到“choices”頁面.

65

•$vimlib/Doxory/View.pm

66

67

• packageDoxory::View;useJifty::View::Declare‐base;

67

• packageDoxory::View;useJifty::View::Declare‐base;

• template'/'=>page{...};privatetemplatenew_choice=>sub{...};

67

• packageDoxory::View;useJifty::View::Declare‐base;

• template'/'=>page{...};privatetemplatenew_choice=>sub{...};

• templatechoices=>page{

67

• packageDoxory::View;useJifty::View::Declare‐base;

• template'/'=>page{...};privatetemplatenew_choice=>sub{...};

• templatechoices=>page{• h1{'MyChoices'}

dl{

67

• packageDoxory::View;useJifty::View::Declare‐base;

• template'/'=>page{...};privatetemplatenew_choice=>sub{...};

• templatechoices=>page{• h1{'MyChoices'}

dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

67

• packageDoxory::View;useJifty::View::Declare‐base;

• template'/'=>page{...};privatetemplatenew_choice=>sub{...};

• templatechoices=>page{• h1{'MyChoices'}

dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

• while(my$c=$choices‐>next){dt{$c‐>name,'(',$c‐>asked_by‐>name,')'}dd{b{$c‐>a}em{'vs'}b{$c‐>b}}}}};

67

68

等等...要怎麼投票啊?

68

☑69

70

•$jiftymodel‐‐nameVote

70

•$jiftymodel‐‐nameVote•Writingfilet/00‐model‐Vote.tWritingfilelib/Doxory/Model/Vote.pm

70

•$jiftymodel‐‐nameVote•Writingfilet/00‐model‐Vote.tWritingfilelib/Doxory/Model/Vote.pm

•$vimlib/Doxory/Model/Vote.pm

70

• packageDoxory::Model::Vote;• useJifty::DBI::Schema;

• useDoxory::Recordschema{• • columnchoice=>• referencesDoxory::Model::Choice;• • columnvoter=>• referencesDoxory::Model::User;

• columnsuggestion=>• validareqw(abskip);

• columncomments=>• labelis'Comments?',• renderas'textarea’;• • };

71

72

72

73

接著來寫“pick”頁面.

73

•$vimlib/Doxory/Dispatcher.pm

74

•$vimlib/Doxory/Dispatcher.pm

先將/pick加進導覽列.

74

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;

• $top‐>child('Pick!'=>url=>'/pick');

• $top‐>child('Choices'=>url=>'/choices');• }• elsif($1!~/^login|^signup/){• tangent'login';

}• };•

on'/'=>show'new_choice';

75

• packageDoxory::Dispatcher;• ...• onpick=>run{• my$choices=Doxory::Model::ChoiceCollection‐>new;• my$votes=$choices‐>join(• type=>'left',• alias1=>'main',column1=>'id',• table2=>'votes',column2=>'choice',• );• $choices‐>limit(• leftjoin=>$votes,column=>'voter',• value=>Jifty‐>web‐>current_user‐>id,• );• $choices‐>limit(• alias=>$votes,column=>'voter',• operator=>'IS',value=>'NULL',• );• if(my$c=$choices‐>first){• setchoice=>$c;• }• else{• show'nothing_to_pick';• }• };

76

• packageDoxory::Dispatcher;• ...• onpick=>run{• my$choices=Doxory::Model::ChoiceCollection‐>new;• my$votes=$choices‐>join(• type=>'left',• alias1=>'main',column1=>'id',• table2=>'votes',column2=>'choice',• );• $choices‐>limit(• leftjoin=>$votes,column=>'voter',• value=>Jifty‐>web‐>current_user‐>id,• );• $choices‐>limit(• alias=>$votes,column=>'voter',• operator=>'IS',value=>'NULL',• );• if(my$c=$choices‐>first){• setchoice=>$c;• }• else{• show'nothing_to_pick';• }• };

“頭一道我還沒投票的選擇題”

76

•$vimlib/Doxory/View.pm

77

78

• packageDoxory::View;

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');• my$action=new_action(class=>'CreateVote');

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');• my$action=new_action(class=>'CreateVote');• my$redir=new_action(

class=>"Jifty::Action::Redirect",arguments=>{url=>'/pick'},);

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');• my$action=new_action(class=>'CreateVote');• my$redir=new_action(

class=>"Jifty::Action::Redirect",arguments=>{url=>'/pick'},);

• my%args=(choice=>$choice‐>id,voter=>Jifty‐>web‐>current_user‐>id,);

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');• my$action=new_action(class=>'CreateVote');• my$redir=new_action(

class=>"Jifty::Action::Redirect",arguments=>{url=>'/pick'},);

• my%args=(choice=>$choice‐>id,voter=>Jifty‐>web‐>current_user‐>id,);

• h1{$choice‐>asked_by‐>name,':',$choice‐>name}

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');• my$action=new_action(class=>'CreateVote');• my$redir=new_action(

class=>"Jifty::Action::Redirect",arguments=>{url=>'/pick'},);

• my%args=(choice=>$choice‐>id,voter=>Jifty‐>web‐>current_user‐>id,);

• h1{$choice‐>asked_by‐>name,':',$choice‐>name}• div{form{

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');• my$action=new_action(class=>'CreateVote');• my$redir=new_action(

class=>"Jifty::Action::Redirect",arguments=>{url=>'/pick'},);

• my%args=(choice=>$choice‐>id,voter=>Jifty‐>web‐>current_user‐>id,);

• h1{$choice‐>asked_by‐>name,':',$choice‐>name}• div{form{• my($x,$y)=map{$action‐>button(

submit=>[$action,$redir],label=>$choice‐>$_,arguments=>{suggestion=>$_,%args},)}((rand>0.5)?('a','b'):('b','a'));

78

• packageDoxory::View;• useJifty::View::Declare‐base;

template''=>page{...};privatetemplatechoices=>sub{...};

• templatepick=>page{• my$choice=get('choice');• my$action=new_action(class=>'CreateVote');• my$redir=new_action(

class=>"Jifty::Action::Redirect",arguments=>{url=>'/pick'},);

• my%args=(choice=>$choice‐>id,voter=>Jifty‐>web‐>current_user‐>id,);

• h1{$choice‐>asked_by‐>name,':',$choice‐>name}• div{form{• my($x,$y)=map{$action‐>button(

submit=>[$action,$redir],label=>$choice‐>$_,arguments=>{suggestion=>$_,%args},)}((rand>0.5)?('a','b'):('b','a'));

• span{$x}em{'or'}span{$y}em{'or'}span{$action‐>button(submit=>[$action,$redir],label=>'Noneoftheabove',arguments=>{suggestion=>'skip',%args},);}

p{render_param($action=>'comments')}}}};

78

79

• packageDoxory::View;useJifty::View::Declare‐base;

template''=>page{...};privatetemplatenew_choice=>sub{...};templatechoices=>page{...};templatepick=>page{...};

79

• packageDoxory::View;useJifty::View::Declare‐base;

template''=>page{...};privatetemplatenew_choice=>sub{...};templatechoices=>page{...};templatepick=>page{...};

• templatenothing_to_pick=>page{h1{"There'snothingforyoutopick."}

79

• packageDoxory::View;useJifty::View::Declare‐base;

template''=>page{...};privatetemplatenew_choice=>sub{...};templatechoices=>page{...};templatepick=>page{...};

• templatenothing_to_pick=>page{h1{"There'snothingforyoutopick."}

•p{"Nooneyouknowisangstingaboutanything.Everybodyknowswherethey'regoingtodinner,whattodoontheirnextdateandwhethertodropthatclass.Youhavesuchlovelyandwelladjustedfriends."}

79

• packageDoxory::View;useJifty::View::Declare‐base;

template''=>page{...};privatetemplatenew_choice=>sub{...};templatechoices=>page{...};templatepick=>page{...};

• templatenothing_to_pick=>page{h1{"There'snothingforyoutopick."}

•p{"Nooneyouknowisangstingaboutanything.Everybodyknowswherethey'regoingtodinner,whattodoontheirnextdateandwhethertodropthatclass.Youhavesuchlovelyandwelladjustedfriends."}

• h2{"Maybeit'stimetoaskforsomeadvice..."};

79

• packageDoxory::View;useJifty::View::Declare‐base;

template''=>page{...};privatetemplatenew_choice=>sub{...};templatechoices=>page{...};templatepick=>page{...};

• templatenothing_to_pick=>page{h1{"There'snothingforyoutopick."}

•p{"Nooneyouknowisangstingaboutanything.Everybodyknowswherethey'regoingtodinner,whattodoontheirnextdateandwhethertodropthatclass.Youhavesuchlovelyandwelladjustedfriends."}

• h2{"Maybeit'stimetoaskforsomeadvice..."};

• show'new_choice';};

79

80

81

81

82

最後來改choices頁面,顯示目前統計的票數.

82

•$vimlib/Doxory/Model/Choice.pm

83

• packageDoxory::Model::Choice;• useJifty::DBI::Schema;• useDoxory::Recordschema{...}

• subin_favor_of_a{• my$self=shift;• $self‐>in_favor_of('a');• }

• subin_favor_of_b{• my$self=shift;• $self‐>in_favor_of('b');• }

• subin_favor_of{• my($self,$x)=@_;• my$votes=Doxory::Model::VoteCollection‐>new;• $votes‐>limit(column=>'choice',value=>$self‐>id);• $votes‐>limit(column=>'suggestion',value=>$x);• return$votes;• }•

84

•$vimlib/Doxory/View.pm

85

86

86

• packageDoxory::View;useJifty::View::Declare‐base;...

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

• dl{

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

• dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

• dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

• while(my$c=$choices‐>next){dt{$c‐>name,'(',$c‐>asked_by‐>name,')'}dd{

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

• dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

• while(my$c=$choices‐>next){dt{$c‐>name,'(',$c‐>asked_by‐>name,')'}dd{

• b{$c‐>a,'(',$c‐>in_favor_of_a‐>count,')'}

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

• dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

• while(my$c=$choices‐>next){dt{$c‐>name,'(',$c‐>asked_by‐>name,')'}dd{

• b{$c‐>a,'(',$c‐>in_favor_of_a‐>count,')'}• em{'vs'}

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

• dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

• while(my$c=$choices‐>next){dt{$c‐>name,'(',$c‐>asked_by‐>name,')'}dd{

• b{$c‐>a,'(',$c‐>in_favor_of_a‐>count,')'}• em{'vs'}• b{$c‐>b,'(',$c‐>in_favor_of_b‐>count,')'}

86

• packageDoxory::View;useJifty::View::Declare‐base;...

• templatechoices=>page{h1{'MyChoices'}

• dl{• my$choices=Doxory::Model::ChoiceCollection‐>new;

$choices‐>limit(column=>'asked_by',value=>Jifty‐>web‐>current_user‐>id,);

• while(my$c=$choices‐>next){dt{$c‐>name,'(',$c‐>asked_by‐>name,')'}dd{

• b{$c‐>a,'(',$c‐>in_favor_of_a‐>count,')'}• em{'vs'}• b{$c‐>b,'(',$c‐>in_favor_of_b‐>count,')'}

• }}}};

86

87

隨堂練習:顯示投票時的留言.☺

87

大功告成!

88

大功告成!♨ lib/Doxory/Model/User.pm

88

大功告成!♨ lib/Doxory/Model/User.pm

♨ lib/Doxory/Model/Choice.pm

88

大功告成!♨ lib/Doxory/Model/User.pm

♨ lib/Doxory/Model/Choice.pm

♨ lib/Doxory/Model/Vote.pm

88

大功告成!♨ lib/Doxory/Model/User.pm

♨ lib/Doxory/Model/Choice.pm

♨ lib/Doxory/Model/Vote.pm

♨ lib/Doxory/Dispatcher.pm

88

大功告成!♨ lib/Doxory/Model/User.pm

♨ lib/Doxory/Model/Choice.pm

♨ lib/Doxory/Model/Vote.pm

♨ lib/Doxory/Dispatcher.pm

♨ lib/Doxory/View.pm

88

大功告成!♨ lib/Doxory/Model/User.pm

♨ lib/Doxory/Model/Choice.pm

♨ lib/Doxory/Model/Vote.pm

♨ lib/Doxory/Dispatcher.pm

♨ lib/Doxory/View.pm

88

☈89

網路分級

90

網路分級

☈ Doxory是普級網站

90

網路分級

☈ Doxory是普級網站

☈ 不能帶有色情暴力字樣

90

網路分級

☈ Doxory是普級網站

☈ 不能帶有色情暴力字樣☈ ...英文髒話也不行

90

Doxory言論管制

91

Doxory言論管制

☈ 沒問題!

91

Doxory言論管制

☈ 沒問題!

☈ 改一小段就行了

91

Doxory言論管制

☈ 沒問題!

☈ 改一小段就行了☈ vimlib/Doxory/Model/Choice.pm

91

92

• packageDoxory::Model::Choice;

92

• packageDoxory::Model::Choice;

• useRegexp::Common'profanity_us';

92

• packageDoxory::Model::Choice;

• useRegexp::Common'profanity_us';

• subvalidate_name{my($self,$name)=@_;

92

• packageDoxory::Model::Choice;

• useRegexp::Common'profanity_us';

• subvalidate_name{my($self,$name)=@_;

•if($name=~/$RE{profanity}/i){return(0,'Wouldyouspeaklikethat'.'infrontofyourmother?*cough*');}

92

• packageDoxory::Model::Choice;

• useRegexp::Common'profanity_us';

• subvalidate_name{my($self,$name)=@_;

•if($name=~/$RE{profanity}/i){return(0,'Wouldyouspeaklikethat'.'infrontofyourmother?*cough*');}

•return1;}

92

93

檢查器(Validator)

94

檢查器(Validator)

☈ 效果差強人意

94

檢查器(Validator)

☈ 效果差強人意☈ 使用者覺得要一直改很煩

94

檢查器(Validator)

☈ 效果差強人意☈ 使用者覺得要一直改很煩☈ 直接清乾淨就是了!

94

• packageDoxory::Model::Choice;useRegexp::Common'profanity_us';

• subcanonicalize_name{• my($self,$name)=@_;

• $name=~s/$RE{profanity}/**expletives**/gi;• return$name;• }

95

96

正規化(Canonicalizer)

97

正規化(Canonicalizer)

☈ 屬於Model的一部份

97

正規化(Canonicalizer)

☈ 屬於Model的一部份

☈ 自動補完(Autocompleter)亦同

97

正規化(Canonicalizer)

☈ 屬於Model的一部份

☈ 自動補完(Autocompleter)亦同

☈ 下一個題目:中文版Doxory

97

文98

•$vimlib/Doxory/Dispatcher.pm

99

•$vimlib/Doxory/Dispatcher.pm

先標明選單裡要國際化的字串.

99

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;

• $top‐>child('Pick!'=>url=>'/pick');• $top‐>child('Choices'=>url=>'/choices');

• }• elsif($1!~/^login|^signup/){• tangent'login';

}• };

• ...

100

• packageDoxory::Dispatcher;useJifty::Dispatcher‐base;

•before'*'=>run{if(Jifty‐>web‐>current_user‐>id){

• my$top=Jifty‐>web‐>navigation;

• $top‐>child(_('Pick!')=>url=>'/pick');• $top‐>child(_('Choices')=>url=>'/choices');

• }• elsif($1!~/^login|^signup/){• tangent'login';

}• };

• ...

101

•$vimlib/Doxory/Model/*.pm

102

•$vimlib/Doxory/Model/*.pm

再將各欄位的label,hints等標明.

102

• packageDoxory::Model::Choice;• useJifty::DBI::Schema;• useDoxory::Recordschema{• • columnname=>• labelis_('Ineedhelpdeciding...'),• renderas'textarea';• • columna=>• labelis_('Ontheonehand'),• renderas'textarea',ismandatory;

• columnb=>• labelis_('Ontheotherhand'),• renderas'textarea',ismandatory;

• columnasked_by=>• labelis_('Askedby'),• defaultisdefer{Jifty‐>web‐>current_user‐>id},• referencesDoxory::Model::User;• • };

103

• packageDoxory::Model::User;• useJifty::DBI::Schema;• • useDoxory::Recordschema{• • columnname=>

• labelis_('Username'),• hintsis_('Otherpeopleseethiswhenyouaskquestions.'),

• isdistinct,• ismandatory;• • columnemail=>

• labelis_('Email'),• hintsis_('Wewillnotsellittoanybody.Honest.'),

• defaultis'',• isdistinct,• isimmutable;• • };

104

• packageDoxory::Model::Vote;• useJifty::DBI::Schema;

• useDoxory::Recordschema{• • columnchoice=>• referencesDoxory::Model::Choice;• • columnvoter=>• referencesDoxory::Model::User;

• columnsuggestion=>• validareqw(abskip);

• columncomments=>• labelis_('Comments?'),• renderas'textarea’;• • };

105

•$vimlib/Doxory/View.pm

106

•$vimlib/Doxory/View.pm

最後再標明頁面裡要翻譯的部份.

106

• packageDoxory::View;useJifty::View::Declare‐base;

template'/'=>page{h1{_('Askaquestion!')}

• show'new_choice';• };

• privatetemplatenew_choice=>sub{div{form{

• my$action=new_action(class=>'CreateChoice');• render_action($action=>['name','a','b']);• form_submit(label=>_('AsktheCrowd!'));• }}• };

• ...

107

108

• $jiftypo‐‐languagezh_tw

108

• $jiftypo‐‐languagezh_tw

產生正體中文字典檔.

108

• $jiftypo‐‐languagezh_tw• INFO‐Extractingmessagesfrom'lib/Doxory/Dispatcher.pm'

INFO‐Extractingmessagesfrom'lib/Doxory/View.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/Choice.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/User.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/Vote.pm'INFO‐Extractingmessagesfrom'bin/jifty'INFO‐Updatingmessagecatalog'share/po/zh_tw.po'

產生正體中文字典檔.

108

• $jiftypo‐‐languagezh_tw• INFO‐Extractingmessagesfrom'lib/Doxory/Dispatcher.pm'

INFO‐Extractingmessagesfrom'lib/Doxory/View.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/Choice.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/User.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/Vote.pm'INFO‐Extractingmessagesfrom'bin/jifty'INFO‐Updatingmessagecatalog'share/po/zh_tw.po'

• $vimshare/po/zh_tw.po

產生正體中文字典檔.

108

• $jiftypo‐‐languagezh_tw• INFO‐Extractingmessagesfrom'lib/Doxory/Dispatcher.pm'

INFO‐Extractingmessagesfrom'lib/Doxory/View.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/Choice.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/User.pm'INFO‐Extractingmessagesfrom'lib/Doxory/Model/Vote.pm'INFO‐Extractingmessagesfrom'bin/jifty'INFO‐Updatingmessagecatalog'share/po/zh_tw.po'

• $vimshare/po/zh_tw.po

產生正體中文字典檔.

編輯正體中文字典檔.

108

• msgid""• msgstr""• "Content‐Type:text/plain;

charset=CHARSET\n"

• #:lib/Doxory/View.pm:8• msgid"Askaquestion!"• msgstr""

• #:lib/Doxory/View.pm:16• msgid"Askthecrowd!"• msgstr""

• #:lib/Doxory/Model/Choice.pm:23• msgid"Askedby"• msgstr""

• #:lib/Doxory/Dispatcher.pm:10• msgid"Choices"• msgstr""

• #:lib/Doxory/Model/Vote.pm:18• msgid"Comments?"• msgstr""

• #:lib/Doxory/Model/Choice.pm:9• msgid"Ineedhelpdeciding..."• msgstr""

• #:lib/Doxory/Model/Choice.pm:13• msgid"Ontheonehand"• msgstr""

• #:lib/Doxory/Model/Choice.pm:18• msgid"Ontheotherhand"• msgstr""

• #:lib/Doxory/Dispatcher.pm:9• msgid"Pick!"• msgstr""•

109

• msgid""• msgstr""• "Content‐Type:text/plain;

charset=UTF‐8\n"

• #:lib/Doxory/View.pm:8• msgid"Askaquestion!"• msgstr"我有問題!"

• #:lib/Doxory/View.pm:16• msgid"Askthecrowd!"• msgstr"聽聽鄉民怎麼說!"

• #:lib/Doxory/Model/Choice.pm:23• msgid"Askedby"• msgstr"提問人"

• #:lib/Doxory/Dispatcher.pm:10• msgid"Choices"• msgstr"開票紀錄"

• #:lib/Doxory/Model/Vote.pm:18• msgid"Comments?"• msgstr"有何指教?"

• #:lib/Doxory/Model/Choice.pm:9• msgid"Ineedhelpdeciding..."• msgstr"幫幫我,該怎麼辦..."

• #:lib/Doxory/Model/Choice.pm:13• msgid"Ontheonehand"• msgstr"我應該...?"

• #:lib/Doxory/Model/Choice.pm:18• msgid"Ontheotherhand"• msgstr"或者...?"

• #:lib/Doxory/Dispatcher.pm:9• msgid"Pick!"• msgstr"投票!"

110

111

现在译成简体中文看看...

111

112

• $b2g.pl‐p‐ushare/po/zh_tw.po>share/po/zh_cn.po

112

• $b2g.pl‐p‐ushare/po/zh_tw.po>share/po/zh_cn.po

先用Encode::HanConvert转成简体.

112

• $b2g.pl‐p‐ushare/po/zh_tw.po>share/po/zh_cn.po

• $vimetc/config.yml

先用Encode::HanConvert转成简体.

112

• $b2g.pl‐p‐ushare/po/zh_tw.po>share/po/zh_cn.po

• $vimetc/config.yml

先用Encode::HanConvert转成简体.

然后强制设定语系.

112

•‐‐‐•framework:•L10N:•PoDir:share/po

•113

•‐‐‐•framework:•L10N:•PoDir:share/po•Lang:zh‐cn

•114

115

国际化完成!

115

∀116

開發工具

117

開發工具

∀ 內建HTTP伺服器

117

開發工具

∀ 內建HTTP伺服器

∀ Module::Install

117

開發工具

∀ 內建HTTP伺服器

∀ Module::Install

∀ 自動生成PAR安裝套件

117

加持光輪(Halo)

118

加持光輪(Halo)

∀ 頁面顯示紀錄

118

加持光輪(Halo)

∀ 頁面顯示紀錄∀ 線上即時編輯

118

加持光輪(Halo)

∀ 頁面顯示紀錄∀ 線上即時編輯∀ ...還有更多更多!

118

Halo

119

Halo

∀ SQL查詢紀錄

119

Halo

∀ SQL查詢紀錄

∀ SQL效能分析

119

Halo

∀ SQL查詢紀錄

∀ SQL效能分析

∀ 頁面效能分析

119

Halo

∀ SQL查詢紀錄

∀ SQL效能分析

∀ 頁面效能分析

119

開發模式(DevelMode)

120

開發模式(DevelMode)

∀ Module::Refresh

120

開發模式(DevelMode)

∀ Module::Refresh

∀ Log4Perl事件紀錄

120

開發模式(DevelMode)

∀ Module::Refresh

∀ Log4Perl事件紀錄

∀ 線上管理界面

120

建置支援

121

建置支援

∀ Lighttpd/Apache

121

建置支援

∀ Lighttpd/Apache

∀ CSS::Squish壓縮器

121

建置支援

∀ Lighttpd/Apache

∀ CSS::Squish壓縮器

∀ JavaScript::Squish壓縮器

121

還有很多有趣的...

122

還有很多有趣的...

∀ 完善的I18N支援

122

還有很多有趣的...

∀ 完善的I18N支援

∀ 用戶端Session

122

還有很多有趣的...

∀ 完善的I18N支援

∀ 用戶端Session

∀ 事件(Event)訂閱

122

✈123

未來計劃

124

未來計劃

✈WikiUI線上互動編輯器

124

未來計劃

✈WikiUI線上互動編輯器

✈打更少字,做更多事

124

未來計劃

✈WikiUI線上互動編輯器

✈打更少字,做更多事

✈有聲書,教學光碟,MTV...

124

範例程式

125

範例程式

✈Wifty

125

範例程式

✈Wifty

✈ CommitBit

125

範例程式

✈Wifty

✈ CommitBit

✈ BabelBee

125

範例程式

✈Wifty

✈ CommitBit

✈ BabelBee

✈ Ping

125

範例程式

✈Wifty

✈ CommitBit

✈ BabelBee

✈ Ping

✈ Chat

125

範例程式

✈Wifty

✈ CommitBit

✈ BabelBee

✈ Ping

✈ Chat

✈ Clock

125

範例程式

✈Wifty

✈ CommitBit

✈ BabelBee

✈ Ping

✈ Chat

✈ Clock

✈ Doxory!

125

下載Jifty

126

下載Jifty

✈ cpanJifty

126

下載Jifty

✈ cpanJifty

✈ http://svn.jifty.org/svn/jifty.org

126

下載Jifty

✈ cpanJifty

✈ http://svn.jifty.org/svn/jifty.org

✈ http://jifty.org/

126

社群支援

127

社群支援

✈ Jifty::Manual::Tutorial

127

社群支援

✈ Jifty::Manual::Tutorial

✈ irc.freenode.net#jifty

127

社群支援

✈ Jifty::Manual::Tutorial

✈ irc.freenode.net#jifty

✈ jifty‐[email protected]

127

fin.128

Bonus Slides(來不及譯成中文)

129

☺130

AnatomyofaJiftyApp

131

AnatomyofaJiftyApp

☺Model:Columns

131

AnatomyofaJiftyApp

☺Model:Columns

☺Action:Parameters

131

AnatomyofaJiftyApp

☺Model:Columns

☺Action:Parameters

☺ Template:Fragments

131

MoreComponents

132

MoreComponents

☺Dispatcher

132

MoreComponents

☺Dispatcher

☺ ClassLoader

132

MoreComponents

☺Dispatcher

☺ ClassLoader

☺ Continuations

132

䷗133

Jifty::DBI

134

Jifty::DBI

∅ CREATETABLE

134

Jifty::DBI

∅ CREATETABLE

∅ ALTERTABLE

134

Jifty::DBI

∅ CREATETABLE

∅ ALTERTABLE

∅ CREATEFOREIGNKEY

134

ObjectRelationalMapper

135

ObjectRelationalMapper

∅ SELECT

135

ObjectRelationalMapper

∅ SELECT

∅ INSERT

135

ObjectRelationalMapper

∅ SELECT

∅ INSERT

∅ UPDATE

135

ObjectRelationalMapper

∅ SELECT

∅ INSERT

∅ UPDATE

∅ DELETE

135

Jifty::DBI::Handle

136

Jifty::DBI::Handle

䷗SQLite

136

Jifty::DBI::Handle

䷗SQLite

䷗Postgres

136

Jifty::DBI::Handle

䷗SQLite

䷗Postgres

䷗MySQL

136

Jifty::DBI::Handle

䷗SQLite

䷗Postgres

䷗MySQL

䷗Oracle

136

Jifty::DBI::Collection

137

Jifty::DBI::Collection

䷗ JoinsandLimits

137

Jifty::DBI::Collection

䷗ JoinsandLimits

䷗ Paging=Data::Page

137

Jifty::DBI::Collection

䷗ JoinsandLimits

䷗ Paging=Data::Page

䷗ Caching=Memcached

137

Jifty::DBI::Schema

138

Jifty::DBI::Schema

䷗ DeclarativeColumns

138

Jifty::DBI::Schema

䷗ DeclarativeColumns

䷗ RememberourDoxory?

138

Jifty::DBI::Schema

䷗ DeclarativeColumns

䷗ RememberourDoxory?

䷗ Timefor0.0.2!

138

139

• packageDoxory::Model::Comment;useJifty::DBI::Schema;useDoxory::Recordschema{

since'0.0.2';

139

• packageDoxory::Model::Comment;useJifty::DBI::Schema;useDoxory::Recordschema{

since'0.0.2';•

columnUser=>referstoDoxory::Model:User;columnauthor=>referstoDoxory::Model::User;

139

• packageDoxory::Model::Comment;useJifty::DBI::Schema;useDoxory::Recordschema{

since'0.0.2';•

columnUser=>referstoDoxory::Model:User;columnauthor=>referstoDoxory::Model::User;

•columnbody=>labelis'Content',typeis'Text',renderas'Textarea',defaultis'FirstPost!';

139

• packageDoxory::Model::Comment;useJifty::DBI::Schema;useDoxory::Recordschema{

since'0.0.2';•

columnUser=>referstoDoxory::Model:User;columnauthor=>referstoDoxory::Model::User;

•columnbody=>labelis'Content',typeis'Text',renderas'Textarea',defaultis'FirstPost!';

•columntitle=>ismandatory,labelis'Title',lengthis40,hintsis'40bytesmax';

139

• packageDoxory::Model::Comment;useJifty::DBI::Schema;useDoxory::Recordschema{

since'0.0.2';•

columnUser=>referstoDoxory::Model:User;columnauthor=>referstoDoxory::Model::User;

•columnbody=>labelis'Content',typeis'Text',renderas'Textarea',defaultis'FirstPost!';

•columntitle=>ismandatory,labelis'Title',lengthis40,hintsis'40bytesmax';

•};

139

DatabaseUpgrade

140

DatabaseUpgrade

䷗ Usedtobepainful

140

DatabaseUpgrade

䷗ Usedtobepainful

䷗ Notanymore

140

DatabaseUpgrade

䷗ Usedtobepainful

䷗ Notanymore

䷗ Jiftyfixedit!

140

141

• $vimetc/config.yml

141

• $vimetc/config.yml• (Setversionto0.0.2)

141

• $vimetc/config.yml• (Setversionto0.0.2)

• $jiftyserver

141

• $vimetc/config.yml• (Setversionto0.0.2)

• $jiftyserver• Applicationschemaversionindatabase(v0.0.1)

doesn'tmatchapplicationschemaversion(0.0.2)Pleaserun`bin/jiftyschema‐‐setup`toupgradethedatabase.

141

• $vimetc/config.yml• (Setversionto0.0.2)

• $jiftyserver• Applicationschemaversionindatabase(v0.0.1)

doesn'tmatchapplicationschemaversion(0.0.2)Pleaserun`bin/jiftyschema‐‐setup`toupgradethedatabase.

•$jiftyschema‐‐setup

141

• $vimetc/config.yml• (Setversionto0.0.2)

• $jiftyserver• Applicationschemaversionindatabase(v0.0.1)

doesn'tmatchapplicationschemaversion(0.0.2)Pleaserun`bin/jiftyschema‐‐setup`toupgradethedatabase.

•$jiftyschema‐‐setup

• Jiftyversion0.605070uptodate.INFO‐GeneratingSQLtoupgradeDoxoryv0.0.1databasetov0.0.2INFO‐Upgradedtoversionv0.0.2

141

• $vimetc/config.yml• (Setversionto0.0.2)

• $jiftyserver• Applicationschemaversionindatabase(v0.0.1)

doesn'tmatchapplicationschemaversion(0.0.2)Pleaserun`bin/jiftyschema‐‐setup`toupgradethedatabase.

•$jiftyschema‐‐setup

• Jiftyversion0.605070uptodate.INFO‐GeneratingSQLtoupgradeDoxoryv0.0.1databasetov0.0.2INFO‐Upgradedtoversionv0.0.2

•$jiftyserver

141

• $vimetc/config.yml• (Setversionto0.0.2)

• $jiftyserver• Applicationschemaversionindatabase(v0.0.1)

doesn'tmatchapplicationschemaversion(0.0.2)Pleaserun`bin/jiftyschema‐‐setup`toupgradethedatabase.

•$jiftyschema‐‐setup

• Jiftyversion0.605070uptodate.INFO‐GeneratingSQLtoupgradeDoxoryv0.0.1databasetov0.0.2INFO‐Upgradedtoversionv0.0.2

•$jiftyserver

• INFO‐Youcanconnecttoyourserverathttp://localhost:8888/

141

142

• columntags=>since'0.0.3',referstoDoxory::Model::TagCollectionby'User';

142

• columntags=>since'0.0.3',referstoDoxory::Model::TagCollectionby'User';

•columnmood=>since'0.0.4',defaultis'happy',validare{display=>'Sad',value=>'sad'},{display=>'Happy',value=>'happy'};

142

• columntags=>since'0.0.3',referstoDoxory::Model::TagCollectionby'User';

•columnmood=>since'0.0.4',defaultis'happy',validare{display=>'Sad',value=>'sad'},{display=>'Happy',value=>'happy'};

•columncreated=>since'0.0.5',isimmutable,typeis'timestamp',defaultisliteral'now()',filtersare'Jifty::DBI::Filter::DateTime';

142

143

• $vimetc/config.yml

143

• $vimetc/config.yml• (Setversionto0.0.5)

143

• $vimetc/config.yml• (Setversionto0.0.5)•

$jiftyschema‐‐setup

143

• $vimetc/config.yml• (Setversionto0.0.5)•

$jiftyschema‐‐setup• Jiftyversion0.605070uptodate.

INFO‐GeneratingSQLtoupgradeDoxoryv0.0.2databasetov0.0.5INFO‐Upgradedtoversionv0.0.5

143

• $vimetc/config.yml• (Setversionto0.0.5)•

$jiftyschema‐‐setup• Jiftyversion0.605070uptodate.

INFO‐GeneratingSQLtoupgradeDoxoryv0.0.2databasetov0.0.5INFO‐Upgradedtoversionv0.0.5

•$jiftyserver

143

• $vimetc/config.yml• (Setversionto0.0.5)•

$jiftyschema‐‐setup• Jiftyversion0.605070uptodate.

INFO‐GeneratingSQLtoupgradeDoxoryv0.0.2databasetov0.0.5INFO‐Upgradedtoversionv0.0.5

•$jiftyserver

• INFO‐Youcanconnecttoyourserverathttp://localhost:8888/

143

⇛144

Action=APIs

145

Action=APIs

⇛ MethodCalls

145

Action=APIs

⇛ MethodCalls

⇛ Typednamedarguments

145

Action=APIs

⇛ MethodCalls

⇛ Typednamedarguments

⇛ Returnsresultsorerrors

145

Action≠URLs

146

Action≠URLs

⇛ Manyactionsononepage

146

Action≠URLs

⇛ Manyactionsononepage

⇛ Calledwithwebforms

146

Action≠URLs

⇛ Manyactionsononepage

⇛ Calledwithwebforms

⇛ SoundslikeRPC?

146

Action=RPC

147

Action=RPC

⇛ Webformencoding

147

Action=RPC

⇛ Webformencoding

⇛ XML/YAMLencoding

147

Action=RPC

⇛ Webformencoding

⇛ XML/YAMLencoding

⇛ Webservicesforfree!

147

Model⇛Action

148

Model⇛Action⇛ Doxory::Action::CreateUser

148

Model⇛Action⇛ Doxory::Action::CreateUser

⇛ Doxory::Action::SearchUser

148

Model⇛Action⇛ Doxory::Action::CreateUser

⇛ Doxory::Action::SearchUser

⇛ Doxory::Action::UpdateUser

148

Model⇛Action⇛ Doxory::Action::CreateUser

⇛ Doxory::Action::SearchUser

⇛ Doxory::Action::UpdateUser

⇛ Doxory::Action::DeleteUser

148

MakeyourownActions

149

150

• packageHello::Action::SayHi;useJifty::Param::Schema;useJifty::Actionschema{paramname=>labelis'Yourname?';};

150

• packageHello::Action::SayHi;useJifty::Param::Schema;useJifty::Actionschema{paramname=>labelis'Yourname?';};

•subtake_action{my$self=shift;my$name=$self‐>argument_value('name');$self‐>result‐>message("Hello,$name");}

150

151

• <%init>my$action=Jifty‐>web‐>new_action(class=>'SayHi');</%init>

151

• <%init>my$action=Jifty‐>web‐>new_action(class=>'SayHi');</%init>

•<&|/_elements/wrapper&><%Jifty‐>web‐>form‐>start%><%$action‐>form_field('name')%><%Jifty‐>web‐>form‐>submit%><%Jifty‐>web‐>form‐>end%></&>

151

• <%init>my$action=Jifty‐>web‐>new_action(class=>'SayHi');</%init>

•<&|/_elements/wrapper&><%Jifty‐>web‐>form‐>start%><%$action‐>form_field('name')%><%Jifty‐>web‐>form‐>submit%><%Jifty‐>web‐>form‐>end%></&>

151

• <%init>my$action=Jifty‐>web‐>new_action(class=>'SayHi');</%init>

•<&|/_elements/wrapper&><%Jifty‐>web‐>form‐>start%><%$action‐>form_field('name')%><%Jifty‐>web‐>form‐>submit%><%Jifty‐>web‐>form‐>end%></&>

151

152

• $curl\http://localhost:8888/__jifty/webservices/yaml?\J:A‐1=SayHi;J:A:F‐name‐1=Jesse

152

• $curl\http://localhost:8888/__jifty/webservices/yaml?\J:A‐1=SayHi;J:A:F‐name‐1=Jesse

•1:!!perl/hash:Jifty::Result_content:{}action_class:Hello::Action::SayHifailure:0field_errors:name:~field_warnings:name:~message:'Hello,Jesse'

152

☸153

Jifty::Dispatcher

154

Dispatcher=Kernel

155

Dispatcher=Kernel

☸ Simple

155

Dispatcher=Kernel

☸ Simple

☸ Declarative

155

Dispatcher=Kernel

☸ Simple

☸ Declarative

☸ Encapsulatesviewlogic

155

ThreeStages

156

ThreeStages

☸ Before:Setsupstate

156

ThreeStages

☸ Before:Setsupstate

☸ On:Showsyourpages

156

ThreeStages

☸ Before:Setsupstate

☸ On:Showsyourpages

☸ After:Cleansupstate

156

Jifty::ClassLoader

157

ScaffoldingBad

158

ScaffoldingBad

☸ Ugly

158

ScaffoldingBad

☸ Ugly

☸ Redundant

158

ScaffoldingBad

☸ Ugly

☸ Redundant

☸ Fragile

158

ScaffoldingBad

☸ Ugly

☸ Redundant

☸ Fragile

☸ Annoying

158

ScaffoldingBad

☸ Ugly

☸ Redundant

☸ Fragile

☸ Annoying

☸ Redundant

158

ScaffoldingBad

☸ Ugly

☸ Redundant

☸ Fragile

☸ Annoying

☸ Redundant

☸ Redundant

158

WhyEmptyClasses?

159

WhyEmptyClasses?

☸ Jifty::ClassLoader

159

WhyEmptyClasses?

☸ Jifty::ClassLoader

☸ Auto‐createsclasses

159

WhyEmptyClasses?

☸ Jifty::ClassLoader

☸ Auto‐createsclasses

☸ Neverwritesthemtodisk

159

Auto‐createdClasses

160

Auto‐createdClasses☸ Doxory

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher☸ Doxory::CurrentUser

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher☸ Doxory::CurrentUser

☸ Doxory::Model::UserCollection

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher☸ Doxory::CurrentUser

☸ Doxory::Model::UserCollection

☸ Doxory::Action::CreateUser

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher☸ Doxory::CurrentUser

☸ Doxory::Model::UserCollection

☸ Doxory::Action::CreateUser☸ Doxory::Action::SearchUser

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher☸ Doxory::CurrentUser

☸ Doxory::Model::UserCollection

☸ Doxory::Action::CreateUser☸ Doxory::Action::SearchUser☸ Doxory::Action::UpdateUser

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher☸ Doxory::CurrentUser

☸ Doxory::Model::UserCollection

☸ Doxory::Action::CreateUser☸ Doxory::Action::SearchUser☸ Doxory::Action::UpdateUser☸ Doxory::Action::DeleteUser

160

Auto‐createdClasses☸ Doxory☸ Doxory::Record☸ Doxory::Collection☸ Doxory::Bootstrap☸ Doxory::Upgrade☸ Doxory::Dispatcher☸ Doxory::CurrentUser

☸ Doxory::Model::UserCollection

☸ Doxory::Action::CreateUser☸ Doxory::Action::SearchUser☸ Doxory::Action::UpdateUser☸ Doxory::Action::DeleteUser☸ ...etcetera

160

☯161

Continuation=JobControl

162

Continuation=JobControl

☯ ContinuationsinPerl?

162

Continuation=JobControl

☯ ContinuationsinPerl?

☯ NotFullContinuations

162

Continuation=JobControl

☯ ContinuationsinPerl?

☯ NotFullContinuations

☯ DelimitedContinuations

162

FullContinuations

163

FullContinuations

☯ Serializeseverything

163

FullContinuations

☯ Serializeseverything

☯ %ENV,STDIN,STDOUT

163

FullContinuations

☯ Serializeseverything

☯ %ENV,STDIN,STDOUT

☯ DBIHandle,LogHandle

163

FullContinuations

☯ Serializeseverything

☯ %ENV,STDIN,STDOUT

☯ DBIHandle,LogHandle

☯ Phaseofthemoon

163

JiftyContinuations

164

JiftyContinuations

☯ Onlytheapplicationstate

164

JiftyContinuations

☯ Onlytheapplicationstate

☯ RequestsandActions

164

JiftyContinuations

☯ Onlytheapplicationstate

☯ RequestsandActions

☯ That’sallweneed

164

WhyContinuations?

165

WhyContinuations?

☯ ThewebisbuiltonGOTO

165

WhyContinuations?

☯ ThewebisbuiltonGOTO

☯ DoyoulikeGOTO?

165

WhyContinuations?

☯ ThewebisbuiltonGOTO

☯ DoyoulikeGOTO?

☯ ContinuationsareGOSUB

165

WhyContinuations?

☯ ThewebisbuiltonGOTO

☯ DoyoulikeGOTO?

☯ ContinuationsareGOSUB

☯ WelcometoCivilization!

165

❀166

Templates=View

167

Templates=View

❀ Template::Declare

167

Templates=View

❀ Template::Declare

❀ HTML::Mason

167

Templates=View

❀ Template::Declare

❀ HTML::Mason

❀MasonhasComponents

167

Templates=View

❀ Template::Declare

❀ HTML::Mason

❀MasonhasComponents

❀ Server‐sideinclusion

167

Fragments

168

Fragments

❀ Components2.0

168

Fragments

❀ Components2.0

❀ Client‐sideforAJAX

168

Fragments

❀ Components2.0

❀ Client‐sideforAJAX

❀ Server‐sideforLynx

168

• <%Jifty‐>web‐>region(• name=>"myweDoxory‐posts",• path=>"/fragments/page_of_posts"• )%>

169

Chat

170

Chat

❀ Server‐push(Comet)

170

Chat

❀ Server‐push(Comet)

❀ Refreshedfragments

170

Chat

❀ Server‐push(Comet)

❀ Refreshedfragments

❀ LiveDemo!

170

!ank y"!♨

171