ब्लॉक की परिभाषाओं में बदलाव करना

एक सामान्य सवाल यह है कि किसी मौजूदा ब्लॉक की परिभाषा में कैसे बदलाव किया जाए. उदाहरण के लिए, हो सकता है कि आपको कनेक्शन की जांच करने की सुविधा जोड़नी हो या किसी फ़ील्ड को वैल्यू इनपुट में बदलना हो.

आम तौर पर, किसी ब्लॉक की डेफ़िनिशन में बदलाव नहीं किया जा सकता.

किसी मौजूदा परिभाषा में बदलाव करने का तरीका

अगर आपको किसी मौजूदा ब्लॉक टाइप की परिभाषा में बदलाव करना है, तो:

  1. ब्लॉक-कोड जनरेटर के साथ-साथ, मौजूदा परिभाषा की कॉपी बनाएं.
  2. कॉपी में बदलाव करें और अपने टाइप को नया नाम दें.
  3. Blockly.Blocks में अपनी नई डेफ़िनिशन जोड़ें.

मैं किसी मौजूदा परिभाषा में सीधे तौर पर बदलाव क्यों नहीं कर सकता/सकती?

अगर आपको यह जानना है कि किसी मौजूदा परिभाषा में बदलाव क्यों नहीं किया जा सकता, तो आगे पढ़ें. हम कुछ संभावनाओं पर विचार करेंगे.

किसी मौजूदा परिभाषा में सीधे बदलाव करना

किसी मौजूदा ब्लॉक की परिभाषा में सीधे तौर पर बदलाव करने के दो तरीके हैं: मंकीपैचिंग और कोड को फ़ॉर्क करना. हम इन दोनों तरीकों का सुझाव नहीं देते, क्योंकि इनसे कोड में गड़बड़ी हो सकती है. यह गड़बड़ी, मॉन्कीपैच किए गए या फ़ॉर्क किए गए कोड पर निर्भर करती है. इन दोनों तरीकों से, अपडेट और गड़बड़ियों को ठीक करने की सुविधा को इंटिग्रेट करना भी मुश्किल हो जाता है. ज़्यादा जानकारी के लिए, मंकी पैचिंग के बारे में क्या जानकारी है? और Blockly को फ़ॉर्क करना लेख पढ़ें.

किसी मौजूदा परिभाषा का सबक्लास बनाना

ऐसा हो सकता है कि आपको किसी मौजूदा परिभाषा को किसी तरह से सबक्लास में बदलना पड़े. माफ़ करें, ऐसा नहीं किया जा सकता, क्योंकि ब्लॉक डेफ़िनिशन क्लास नहीं हैं -- वे मिक्सिन हैं. उदाहरण के लिए, कलर प्रॉपर्टी को ओवरराइट करने का कोई तरीका नहीं है, क्योंकि परिभाषा में कलर प्रॉपर्टी नहीं है. इसके बजाय, इसमें एक init फ़ंक्शन है, जो ब्लॉक पर कलर प्रॉपर्टी सेट करने के लिए setColour को कॉल करता है. कॉल init में होने की वजह से, पूरे init फ़ंक्शन को बदले बिना इसे बदला नहीं जा सकता.

किसी मौजूदा परिभाषा में फ़ंक्शन को ओवरराइट करना

किसी मौजूदा परिभाषा में फ़ंक्शन को ओवरराइट किया जा सकता है:

Blockly.Blocks['existing_block'].init = function() {/*new function*/};

यह काम करता है, लेकिन आपको मौजूदा फ़ंक्शन को कॉपी करके उसमें बदलाव करना होगा. सिर्फ़ एक लाइन को जादुई तरीके से बदला नहीं जा सकता. इसमें कई समस्याएं हैं:

  • यह पूरी परिभाषा को कॉपी करने और उसमें बदलाव करने से काफ़ी अलग नहीं है.
  • इसका इस्तेमाल, जेएसओएन में तय किए गए ब्लॉक के init फ़ंक्शन में बदलाव करने के लिए नहीं किया जा सकता. जैसे, Blockly में पहले से मौजूद ब्लॉक. ऐसा इसलिए है, क्योंकि कॉपी करने के लिए कोई init फ़ंक्शन नहीं है -- यह रन टाइम पर जनरेट होता है.
  • इसके लिए, आपको JavaScript का इस्तेमाल करके अपना ब्लॉक तय करना होगा. इससे लोकलाइज़ेशन से जुड़ी समस्याएं हो सकती हैं.

init के नतीजों को बदलना

init फ़ंक्शन की "सिर्फ़ एक लाइन को बदलने" का एक तरीका यह है कि init फ़ंक्शन को ऐसे फ़ंक्शन से बदलें जो ओरिजनल init फ़ंक्शन को कॉल करता है और फिर उस कॉल के नतीजे को ओवरराइट करता है. उदाहरण के लिए, यह कोड logic_null ब्लॉक का रंग बदलता है:

const originalInit = Blockly.Blocks['logic_null'].init;
Blockly.Blocks['logic_null'].init = function() {
  originalInit.call(this);
  this.setColour(300);
}

माफ़ करें, यह उतना काम का नहीं है जितना दिखता है. उदाहरण के लिए:

  • कनेक्शन की जांच को बेहतर बनाने या कम पाबंदी वाले फ़ील्ड की पुष्टि करने वाले टूल का इस्तेमाल करने पर, ब्लॉक-कोड जनरेटर और इवेंट हैंडलर की ओर से की गई अनुमानित गणना अमान्य हो सकती है.

  • किसी फ़ील्ड को वैल्यू इनपुट से बदलने पर, ब्लॉक-कोड जनरेटर और फ़ील्ड की पुष्टि करने वाले टूल काम नहीं करेंगे. साथ ही, हो सकता है कि इवेंट हैंडलर भी काम न करें. स्थानीय भाषा के हिसाब से ब्लॉक बनाने के लिए भी, ऐसा करना काफ़ी मुश्किल हो सकता है. इसकी वजह यह है कि अलग-अलग स्थानीय भाषाओं के लिए, इनपुट और फ़ील्ड के अलग-अलग टाइप और क्रम वाले ब्लॉक बन सकते हैं.

JSON की परिभाषा में की-वैल्यू पेयर को बदलना

अगर किसी ब्लॉक के लिए JSON सार्वजनिक तौर पर उपलब्ध है, तो अलग-अलग JSON वैल्यू को फिर से लिखा जा सकता है. उदाहरण के लिए:

// Block definition.
blockJson = {...};
Blockly.Blocks['my_block'] = {
  init: function() {
    initJson(blockJson); // Called when the block is created.
  }
}

// Third-party code.
blockJson.colour = 100;

हालांकि, यह सिर्फ़ तब काम करता है, जब JSON ऑब्जेक्ट सार्वजनिक तौर पर उपलब्ध हो, परिभाषा में init फ़ंक्शन के बारे में साफ़ तौर पर बताया गया हो, और init फ़ंक्शन initJson को कॉल करता हो. अगर JSON को defineBlocksWithJsonArray या createBlockDefinitionsFromJsonArray को पास किया जाता है, तो यह काम नहीं करता. ऐसा इसलिए होता है, क्योंकि तीसरे पक्ष को JSON में बदलाव करने का मौका मिलने से पहले ही, उसे प्रोसेस कर दिया जाता है. ध्यान दें कि Blockly के पहले से मौजूद ब्लॉक में createBlockDefinitionsFromJsonArray का इस्तेमाल किया जाता है.

अगर JSON को इस तरह से नहीं बनाया गया है, तो क्या होगा? क्या अब भी JSON प्रॉपर्टी को बदला जा सकता है? माफ़ करें, नहीं. परिभाषा में init फ़ंक्शन (JSON नहीं) शामिल है और init फ़ंक्शन को JSON में बदलने का कोई फ़ंक्शन नहीं है.

// Doesn't work. There is no getJson() function.
const json = Blockly.Blocks['existing_block'].getJson();
json['message0'] = 'my new message0';
Blockly.Blocks['existing_block'].init = function () {
  initJson(json);
};

फिर से इस्तेमाल करने के लिए डिज़ाइन करना

अपने कस्टम ब्लॉक डिज़ाइन करते समय, उन्हें इस तरह से डिज़ाइन किया जा सकता है कि उनका फिर से इस्तेमाल किया जा सके.

JSON का फिर से इस्तेमाल करना

अगर आपके पास दो ऐसे ब्लॉक हैं जो काफ़ी हद तक मिलते-जुलते हैं, तो पैरंट JSON परिभाषा बनाई जा सकती है और इसे चाइल्ड परिभाषाओं में फिर से इस्तेमाल किया जा सकता है. उदाहरण के लिए:

const parentJson = {
  // shared properties
};

Blockly.Blocks['child_block_1'] = {
  init: function() {
    initJson({...parentJson, colour: 100})
  }
}

Blockly.Blocks['child_block_2'] = {
  init: function() {
    initJson({...parentJson, colour: 200})
  }
}

एक और विकल्प यह है कि आप अपने JSON को सार्वजनिक तौर पर उपलब्ध ऑब्जेक्ट में तय करें और उस ऑब्जेक्ट को अपने init फ़ंक्शन में initJson को पास करें. इससे, अन्य लोग अलग-अलग प्रॉपर्टी को ओवरराइट कर सकते हैं. ज़्यादा जानकारी के लिए, JSON परिभाषा में किसी की-वैल्यू पेयर को बदलना लेख पढ़ें.

फ़ंक्शन का फिर से इस्तेमाल करना

ब्लॉक में कई स्टैंडर्ड फ़ंक्शन तय किए जा सकते हैं. जैसे, ब्लॉक-लेवल इवेंट हैंडलर, कस्टम टूलटिप, फ़ील्ड की पुष्टि करने वाले फ़ंक्शन, और म्यूटेट करने वाले फ़ंक्शन. साथ ही, इसमें ऐसे फ़ंक्शन भी तय किए जा सकते हैं जो कस्टम व्यवहार देते हैं. जैसे, ऐसा फ़ंक्शन जो बाहरी डेटा से फ़ील्ड की वैल्यू सेट करता है. जैसे, रोबोट के हाथ की मौजूदा स्थिति.

इन फ़ंक्शन का इस्तेमाल, सभी ब्लॉक में किया जा सकता है.

ड्रॉपडाउन फ़ील्ड का इस्तेमाल करना

अगर आपके पास एक सेट में ऐसे ब्लॉक हैं जो ऑपरेटर के अलावा एक जैसे हैं, तो एक ऐसा ब्लॉक डिज़ाइन किया जा सकता है जिसमें ऑपरेटर के लिए ड्रॉपडाउन फ़ील्ड हो. उदाहरण के लिए:

  • पहले से मौजूद logic_operation ब्लॉक, ऑपरेटर and और or के साथ ड्रॉपडाउन का इस्तेमाल करता है.
  • पहले से मौजूद math_arithmetic ब्लॉक, ऑपरेटर +, -, ×, ÷, और ^ के साथ ड्रॉपडाउन का इस्तेमाल करता है.

आम तौर पर, ऐसे ब्लॉक के लिए कोड जनरेटर लिखना थोड़ा मुश्किल होता है. हालांकि, यह कई ब्लॉक लिखने और उन्हें मैनेज करने के मुकाबले आसान होता है.

म्यूटेटर का इस्तेमाल करना

अगर आपके पास एक ही प्रोग्रामिंग स्ट्रक्चर के अलग-अलग वैरिएशन दिखाने वाले ब्लॉक का सेट है, तो एक ऐसा ब्लॉक बनाया जा सकता है जिसमें म्यूटेट करने वाले टूल का इस्तेमाल किया गया हो. उदाहरण के लिए, पहले से मौजूद controls_if ब्लॉक में if-then-else स्टेटमेंट के कई वैरिएंट हो सकते हैं.