======================================================================
 PSGI::Handy Tutorial (tut/)
 ट्यूटोरियल मैनुअल                                         [HI] हिंदी
======================================================================

 tut/ PSGI::Handy का आधिकारिक शिक्षण ट्यूटोरियल है: छह अध्यायों और चौबीस चरणों का एक पाठ्यक्रम जो बिना किसी ब्लैक बॉक्स के, एक नंगी HTTP प्रतिक्रिया से शुरू होकर एक पूर्ण CRUD अनुप्रयोग तक, शून्य से एक वेब अनुप्रयोग बनाता है। प्रत्येक चरण एक स्वतंत्र, चलने योग्य Perl प्रोग्राम है। पूरा स्टैक शुद्ध Perl और निर्भरता-रहित है: PSGI::Handy (फ्रेमवर्क), HTTP::Handy (सर्वर), HP::Handy (टेम्पलेट) और DB::Handy (डेटाबेस)।

[ कैसे चलाएं ]

  tut/ निर्देशिका के अंदर से एक बार में एक चरण चलाएं, उदाहरण के लिए perl 01_step01_text.pl  । प्रत्येक प्रोग्राम एक सर्वर शुरू करता है और अपना URL प्रिंट करता है; ब्राउज़र में http://127.0.0.1:8080/ खोलें और रोकने के लिए Ctrl-C दबाएं। templates/ निर्देशिका और data.csv वर्तमान निर्देशिका से पहुंच योग्य होने चाहिए, इसलिए प्रोग्राम हमेशा tut/ के अंदर से शुरू करें।

[ सामान्य हेडर ]

  प्रत्येक .pl फ़ाइल एक ही हेडर से खुलती है: use 5.00503; use strict; एक छोटा BEGIN ब्लॉक जो 5.6 से पुराने Perl पर एक निष्क्रिय warnings stub प्रदान करता है; फिर use warnings; local $^W = 1;  । प्रोग्राम bareword filehandle और दो-तर्क वाले open का उपयोग करते हैं ताकि वे Perl 5.005_03 तक मान्य रहें। यह हेडर हर चरण में समान है और नीचे दोहराया नहीं गया है।

----------------------------------------------------------------------
 रूट फ़ाइलें
----------------------------------------------------------------------

  00_README.txt
      पाठ्यक्रम अवलोकन: प्रत्येक अध्याय और चरण अपने सीखने के लक्ष्य के साथ। किसी भी प्रोग्राम को खोलने से पहले पूरा क्रम देखने के लिए इसे पहले पढ़ें।

  data.csv
      अध्याय 4 के लिए नमूना डेटा (CSV चरण): id,name,age की तीन अल्पविराम-पृथक पंक्तियां। चरण 12, 14 और 15 इस फ़ाइल को फिर से लिखते हैं, इसलिए यदि आप इसे रीसेट करना चाहते हैं तो एक बैकअप रखें। 1,Alice,20 / 2,Bob,22 / 3,Charlie,25

----------------------------------------------------------------------
 अध्याय 1 — HTTP प्रतिक्रिया मूल बातें (स्थिर से गतिशील तक)
----------------------------------------------------------------------

  HTTP प्रतिक्रिया के आकार को समझने के लिए ब्राउज़र और सर्वर के बीच, बिना टेम्पलेट इंजन के, सबसे सरल संभव आदान-प्रदान।

  01_step01_text.pl
      GET / के लिए $c->text() के माध्यम से सादा पाठ '.' लौटाता है। सबसे छोटा संभव अनुप्रयोग: ब्राउज़र कच्चे वर्ण प्राप्त करता है (text/plain)।

  01_step02_html.pl
      $c->html() के माध्यम से '<a>.' को text/html के रूप में लौटाता है। चरण 1 के समान बाइट्स, लेकिन Content-Type ब्राउज़र को उन्हें मार्कअप के रूप में मानने के लिए कहता है। पाठ बनाम HTML के अंतर को दिखाता है।

  01_step03_dyn_text.pl
      वर्तमान समय को सादे पाठ के रूप में लौटाता है, प्रत्येक अनुरोध पर scalar localtime() के साथ नए सिरे से पढ़ा जाता है। गतिशील आउटपुट का पहला स्वाद: प्रतिक्रिया हर बार बदलती है।

  01_step04_dyn_html.pl
      गतिशील समय को <h1>/<p> मार्कअप में लपेटता है और HTML के रूप में लौटाता है। चरों से एक स्ट्रिंग जोड़कर एक स्क्रीन बनाना।

----------------------------------------------------------------------
 अध्याय 2 — उपयोगकर्ता इनपुट और स्थिति (फॉर्म और शाखन)
----------------------------------------------------------------------

  ब्राउज़र से सर्वर तक डेटा भेजना, और जो आता है उस पर शाखन करना।

  02_step05_form.pl
      GET / एक HTML फॉर्म (एक टेक्स्ट बॉक्स और एक सबमिट बटन) दिखाता है जो /echo पर POST करता है। सबमिशन के लिए अभी तक कोई हैंडलर नहीं है; यह चरण केवल फॉर्म मार्कअप के बारे में है।

  02_step06_echo.pl
      POST /echo हैंडलर जोड़ता है। यह $c->param('message') के साथ 'message' फ़ील्ड पढ़ता है और इसे HTML प्रतिक्रिया के अंदर वापस प्रतिध्वनित करता है: अनुरोध-से-प्रतिक्रिया का मूल चक्र।

  02_step07_auth.pl
      एक न्यूनतम लॉगिन। POST /login 'username' और 'password' पढ़ता है और शाखन के लिए एक if का उपयोग करता है: admin/secret सफलता पृष्ठ तक पहुंचता है, बाकी सब विफलता पृष्ठ तक। प्रमाणीकरण और सशर्त प्रवाह का बीज।

----------------------------------------------------------------------
 अध्याय 3 — View को अलग करना (HP::Handy का परिचय)
----------------------------------------------------------------------

  प्रोग्राम के अंदर HTML लिखना बंद करें; इसे टेम्पलेट फ़ाइलों में ले जाएं। HP::Handy render_file()/render_string() को उजागर करता है, इसलिए यह एक छोटे CODE renderer के माध्यम से PSGI::Handy से जुड़ा है जो टेम्पलेट नाम को render_file() पर मैप करता है। वह renderer ब्लॉक हर टेम्पलेट वाले चरण में समान है।

  03_step08_template.pl
      बिना चरों के स्थिर templates/step08.html को रेंडर करता है। HTML अब तर्क से अलग, अपनी फ़ाइल में रहता है।

  03_step09_template_var.pl
      templates/step09.html को { current_time => ... } पास करता है, जो इसे {{ current_time }} प्लेसहोल्डर के साथ प्रिंट करता है। डेटा प्रोग्राम से टेम्पलेट तक बहता है।

  03_step10_template_form.pl
      दो टेम्पलेट का उपयोग करके चरण 6 की प्रतिध्वनि को फिर से लिखता है: इनपुट के लिए step10_form.html और परिणाम के लिए step10_result.html। हैंडलर तर्क बहुत छोटा हो जाता है।

----------------------------------------------------------------------
 अध्याय 4 — फ़ाइल I/O और CSV स्थायित्व (CRUD मूल बातें)
----------------------------------------------------------------------

  बिना डेटाबेस के, एक सादी CSV फ़ाइल के विरुद्ध Create/Read/Update/Delete लागू करें। मैन्युअल डेटा प्रबंधन की लागत महसूस करना अध्याय 5 में डेटाबेस की ओर बढ़ने को प्रेरित करता है।

  04_step11_csv_readall.pl
      Read All. data.csv खोलता है, प्रत्येक पंक्ति को अल्पविराम पर { id, name, age } hash में विभाजित करता है, और सूची को HTML तालिका के रूप में रेंडर करता है (step11_list.html)।

  04_step12_csv_create.pl
      Create. POST /add append मोड (>>) में data.csv में एक 'id,name,age' पंक्ति जोड़ता है, फिर एक पूर्णता पृष्ठ दिखाता है।

  04_step13_csv_readone.pl
      Read One. रूट /user/:id एक id पकड़ता है; प्रोग्राम मिलान पंक्ति के लिए data.csv को स्कैन करता है और इसका विवरण दिखाता है (step13_detail.html), या नहीं मिलने पर 404 लौटाता है।

  04_step14_csv_update.pl
      Update. एक पंक्ति बदलने के लिए यह हर पंक्ति पढ़ता है, मिलान वाली को बदलता है और पूरी फ़ाइल फिर से लिखता है: 'सब पढ़ें, बदलें, सब लिखें' का काम जिसे डेटाबेस हटा देगा।

  04_step15_csv_delete.pl
      Delete. वही पूरी फ़ाइल पुनर्लेखन, लेकिन मिलान पंक्ति को बदलने के बजाय छोड़ दिया जाता है।

----------------------------------------------------------------------
 अध्याय 5 — Model का परिचय (DB::Handy की ओर बढ़ना)
----------------------------------------------------------------------

  CSV को DB::Handy से बदलें। हैंडल DB::Handy->connect('data','app',{...}) के साथ बनाया जाता है और db => $dbh के माध्यम से इंजेक्ट किया जाता है, फिर हैंडलर में $c->db के रूप में पहुंचा जाता है। एक _bootstrap() रूटीन 'users' तालिका को एक बार बनाता और बीज देता है, इसलिए प्रत्येक उदाहरण स्वतंत्र रूप से चलता है।

  05_step16_db_readall.pl
      Read All. selectall_arrayref(..., { Slice => {} }) सूची टेम्पलेट (step16_list.html) के लिए प्रत्येक users पंक्ति को hash के रूप में लाता है। अब कोई मैन्युअल फ़ाइल पार्सिंग नहीं।

  05_step17_db_create.pl
      Create. POST /add एक प्लेसहोल्डर INSERT के साथ एक पंक्ति सम्मिलित करता है, फिर / (सूची) पर पुनर्निर्देशित करता है: मानक post-then-redirect पैटर्न।

  05_step18_db_readone.pl
      Read One. /user/:id selectrow_hashref() के साथ प्राथमिक कुंजी द्वारा एक पंक्ति लाता है, या 404 लौटाता है। हर पंक्ति स्कैन करने के बजाय सीधी कुंजी खोज।

  05_step19_db_update.pl
      Update. GET /user/:id/edit संपादन फॉर्म दिखाता है; POST UPDATE ... WHERE id=? चलाता है और विवरण पृष्ठ पर पुनर्निर्देशित करता है। मेमोरी में कोई पूरी फ़ाइल पुनर्लेखन नहीं।

  05_step20_db_delete.pl
      Delete. DELETE ... WHERE id=? चलाया जाता है, फिर / पर पुनर्निर्देशन। स्थिति बदलने वाला रूट केवल POST है, GET से आकस्मिक विलोपन से बचने के लिए।

----------------------------------------------------------------------
 अध्याय 6 — संबंधपरक डेटा और एक वास्तविक अनुप्रयोग
----------------------------------------------------------------------

  दूसरे डेटाबेस 'app2' में दो संबंधित तालिकाएं (users और depts)। JOIN को Perl में हाथ से किया जाता है ताकि यह ब्लैक बॉक्स न हो, फिर सब कुछ एक पूर्ण अनुप्रयोग में इकट्ठा किया जाता है।

  06_step21_db_join_list.pl
      JOIN List. दोनों तालिकाओं को पढ़ता है, एक dept_id => name खोज बनाता है, प्रत्येक उपयोगकर्ता को dept_name जोड़ता है (एक हाथ से लिखा JOIN), और उन्हें सूचीबद्ध करता है (step21_join_list.html)।

  06_step22_db_join_detail.pl
      JOIN Read One. एक उपयोगकर्ता लाता है, फिर उस उपयोगकर्ता के एकल विभाग को खोजता है और विवरण पृष्ठ के लिए उसका नाम जोड़ता है (step22_join_detail.html)।

  06_step23_db_form_select.pl
      Select फॉर्म. विभाग मास्टर लोड करता है और इसे <select> ड्रॉपडाउन के रूप में रेंडर करता है (step23_form_select.html), ताकि उपयोगकर्ता id टाइप करने के बजाय एक विभाग चुने।

  06_step24_fullstack_app.pl
      एक फ़ाइल में पूर्ण अनुप्रयोग: users+depts डेटा पर list, detail, add, edit और delete; जुड़े विभाग नाम, एक select ड्रॉपडाउन, हर जगह post-then-redirect, और एक _next_id() सहायक (DB::Handy में कोई ऑटो-इंक्रीमेंट नहीं)। app_list.html और app_form.html का उपयोग करता है।

----------------------------------------------------------------------
 टेम्पलेट (templates/)
----------------------------------------------------------------------

  HP::Handy टेम्पलेट Jinja2 जैसी वाक्यविन्यास का उपयोग करते हैं: {{ var }} एक मान प्रिंट करता है ({{ user.name }} जैसे डॉटेड पथ hash में पहुंचते हैं), {% for x in list %} ... {% endfor %} लूप करता है, और {% if ... %} शाखन करता है। renderer को auto_escape => 1 के साथ बनाया जाता है, इसलिए प्रिंट किए गए मान HTML-escape होते हैं।

  templates/step08.html
      चरण 8 द्वारा उपयोग किया गया पूरी तरह से स्थिर पृष्ठ; कोई प्लेसहोल्डर नहीं।

  templates/step09.html
      {{ current_time }} के माध्यम से सर्वर समय प्रिंट करता है (चरण 9)।

  templates/step10_form.html
      चरण 10 की प्रतिध्वनि के लिए इनपुट फॉर्म; 'message' को /echo पर POST करता है।

  templates/step10_result.html
      चरण 10 के लिए प्रतिध्वनित {{ message }} दिखाता है।

  templates/step11_list.html
      CSV तालिका बनाने के लिए {{ users }} पर लूप करता है (चरण 11)।

  templates/step12_form.html
      चरण 12 के लिए जोड़ें फॉर्म (id, name, age)।

  templates/step12_result.html
      चरण 12 का "Added" पुष्टि पृष्ठ: {{ name }} और वापसी लिंक दिखाता है।

  templates/step13_list.html
      चरण 13 की अनुक्रमणिका: प्रत्येक उपयोगकर्ता अपने /user/:id विवरण पृष्ठ से जुड़ता है।

  templates/step13_detail.html
      चरण 13 के लिए एक उपयोगकर्ता का id/name/age दिखाता है।

  templates/step14_list.html
      चरण 14 का पृष्ठ: वर्तमान पंक्तियाँ और /update पर POST करने वाला अद्यतन फ़ॉर्म।

  templates/step15_list.html
      चरण 15 का पृष्ठ: वर्तमान पंक्तियाँ और /delete पर POST करने वाला हटाने का फ़ॉर्म।

  templates/step16_list.html
      चरण 16 की सादा DB उपयोगकर्ता सूची (अभी कोई लिंक नहीं)।

  templates/step17_form.html
      चरण 17 के लिए उपयोगकर्ता जोड़ें फॉर्म।

  templates/step17_list.html
      /add के लिए "Add New User" लिंक वाली चरण 17 की सूची।

  templates/step18_list.html
      चरण 18 की सूची: प्रत्येक नाम अपने /user/:id विवरण से जुड़ता है।

  templates/step18_detail.html
      चरण 18 का सादा उपयोगकर्ता विवरण, वापसी लिंक के साथ।

  templates/step19_list.html
      चरण 19 की सूची: प्रत्येक नाम अपने विवरण पृष्ठ से जुड़ता है।

  templates/step19_detail.html
      चरण 19 का उपयोगकर्ता विवरण, संपादन लिंक और वापसी लिंक के साथ।

  templates/step19_edit.html
      चरण 19 के लिए संपादन फॉर्म (name, age); /user/:id/edit पर POST करता है।

  templates/step20_list.html
      प्रत्येक पंक्ति पर पुष्टि-युक्त POST Delete बटन वाली चरण 20 की सूची।

  templates/step21_join_list.html
      जुड़े {{ user.dept_name }} कॉलम के साथ कर्मचारी सूची (चरण 21)।

  templates/step22_join_list.html
      चरण 22 की कर्मचारी अनुक्रमणिका: प्रत्येक नाम अपने विवरण पृष्ठ से जुड़ता है।

  templates/step22_join_detail.html
      विभाग का नाम दिखाने वाला कर्मचारी विवरण (चरण 22)।

  templates/step23_list.html
      /add के लिए "Add New Employee" लिंक वाली चरण 23 की कर्मचारी सूची।

  templates/step23_form_select.html
      {{ depts }} से बने विभाग <select> के साथ जोड़ें फॉर्म (चरण 23)।

  templates/app_list.html
      पूर्ण अनुप्रयोग की कर्मचारी सूची (चरण 24): ID, लिंक किया नाम, विभाग, साथ ही प्रत्येक पंक्ति के लिए Edit और एक पुष्टि-संरक्षित POST Delete, और एक Add लिंक।

  templates/app_form.html
      पूर्ण अनुप्रयोग का साझा जोड़ें/संपादन फॉर्म (चरण 24): {{ action }} लक्ष्य create और update के बीच स्विच करता है, और विभाग <select> {% if %} के माध्यम से {{ user.dept_id }} को पूर्व-चयनित करता है।

----------------------------------------------------------------------
 संदर्भ
----------------------------------------------------------------------

  MetaCPAN पर PSGI::Handy और शेष Handy स्टैक, और PSGI विनिर्देश:

    https://metacpan.org/dist/PSGI-Handy
    https://metacpan.org/dist/HTTP-Handy
    https://metacpan.org/dist/HP-Handy
    https://metacpan.org/dist/DB-Handy
    https://github.com/plack/psgi-specs/blob/master/PSGI.pod

======================================================================
