Обсуждение модуля:Header
Добавить темуДля каких проектов модуль
[править]Этот модуль для какого проекта/шапки? Могу сюда перенести содержимое Модуль:ТСД? --Vladis13 (обсуждение) 23:09, 28 сентября 2015 (UTC)
- Это для почти всех проектов -- посмотрите список префиксов страниц в ф-ции word_list... А чем вам отдельный модуль ТСД не нравится? Надо бы со временем наоборот провести здесь в модуле cleanup и вытащить функционал, специфичный для отдельных проектов, в отдельные модули для проектов (или подмодули вида Header/Проект), а то со временем тут функционал стал монстроидальным... Переименуйте, например свой модуль в Модуль:Header/ТСД, надо будет и остальные так же "вытащить"... Hinote (обсуждение) 23:53, 28 сентября 2015 (UTC)
- Преимущество совместного модуля перед отдельным - за функциями будут присматривать, и может будет улучшаться знающими участниками (к примеру, вы с первого взгляда что-то дельное предложили). Если же отдельный модуль - вот я по какой-то причине отойду от проекта, внесёт кто-то в модуль правку (а в проекте ТСД, кроме меня в последние 2-3 месяца, только 1 активный участник - не программист), - и десятки тысяч страниц сломаются. Или наоборот потребуется обновление. --Vladis13 (обсуждение) 15:04, 29 сентября 2015 (UTC)
- С точки зрения maintenance -- да, наверное тут есть некоторое здравое зерно... Но, учитывая текущее состояние этого модуля (он перегружен и требует cleanup), я бы все же попросил вас не вносить сюда еще функции, специфичные для ТСД. А чтобы тот ваш модуль не был так "оторван" от остальных проектов -- переименуйте, его, например, в "Header/ТСД"... А я со временем возможно из этого модуля перенесу части, специфичные для ЭСБЕ, для РБС в аналогичные "подмодули"... Тем самым вы инициируете как раз такое разгребание существующего кода этого модуля... Hinote (обсуждение) 15:55, 29 сентября 2015 (UTC)
- Тогда пусть как есть. Переименовыввать смысла нету, ибо не все функции могут относится к «Header» (шапке). И разве перенос его в «подпространство» «Header/» добавит ту страницу в списки наблюдений следящих за этим модулем? — вроде нет. --Vladis13 (обсуждение) 19:34, 29 сентября 2015 (UTC)
- С точки зрения maintenance -- да, наверное тут есть некоторое здравое зерно... Но, учитывая текущее состояние этого модуля (он перегружен и требует cleanup), я бы все же попросил вас не вносить сюда еще функции, специфичные для ТСД. А чтобы тот ваш модуль не был так "оторван" от остальных проектов -- переименуйте, его, например, в "Header/ТСД"... А я со временем возможно из этого модуля перенесу части, специфичные для ЭСБЕ, для РБС в аналогичные "подмодули"... Тем самым вы инициируете как раз такое разгребание существующего кода этого модуля... Hinote (обсуждение) 15:55, 29 сентября 2015 (UTC)
- Преимущество совместного модуля перед отдельным - за функциями будут присматривать, и может будет улучшаться знающими участниками (к примеру, вы с первого взгляда что-то дельное предложили). Если же отдельный модуль - вот я по какой-то причине отойду от проекта, внесёт кто-то в модуль правку (а в проекте ТСД, кроме меня в последние 2-3 месяца, только 1 активный участник - не программист), - и десятки тысяч страниц сломаются. Или наоборот потребуется обновление. --Vladis13 (обсуждение) 15:04, 29 сентября 2015 (UTC)
1-й параметр (list) в функции wordlist
[править]function p.wordlist (frame, noframe)
local list = frame.args[1];
Что значит первый параметр (list)? --Vladis13 (обсуждение) 22:30, 13 октября 2016 (UTC)
- Был оставлен для возможности передавать список функции извне. Скорее всего, не используется (но на 100% не уверен). — Lozman (talk) 23:46, 13 октября 2016 (UTC)
Парсинг суффикса "/ДО" для ТСД
[править]Что-то не работает парсинг суффикса "/ДО" в названиях страниц. Эти работают: ← Алый Алыкъ
{{#invoke:Header|previous|ТСД/Алык|ТСД-словник/А/2-е изд.|safe=true}} {{#invoke:Header|title|ТСД/Алык|ТСД-словник/А/2-е изд.|safe=true|ДО=true}}
А эти не возвращают ничего:
{{#invoke:Header|previous|ТСД/Алык/ДО|ТСД-словник/А/2-е изд.|safe=true}} {{#invoke:Header|title|ТСД/Алык/ДО|ТСД-словник/А/2-е изд.|safe=true|ДО=true}}
Hinote вроде прописывал обработку параметров шаблона словника:
x = x:gsub("{{[Tt]sds|", "{{Статья в словнике3|") -- ТСД x = x:gsub("{{[Тт]сдс|", "{{Статья в словнике3|") -- ТСД x = x:gsub("{{[Сс]татья в словнике ТСД|", "{{Статья в словнике3|") -- ТСД -- ТСД x = x:gsub( "{{Статья в словнике3|([^|]+)|[%s]*|[%s]*|[^{}]-}}", "[[" .. root .. "/%1|%1]]") if oldspell then x = x:gsub( "{{Статья в словнике3|([^|]+)|[%s]*|[^|]+|[^{}]-}}", "[[" .. root .. "/%1|%1]]") x = x:gsub( "{{Статья в словнике3|([^|]+)|([^|]+)|[%s]*|[^{}]-}}", "[[" .. root .. "/%1|%2]]") x = x:gsub( "{{Статья в словнике3|([^|]+)|([^|]+)|[^|]+|[^{}]-}}", "[[" .. root .. "/%1|%2]]") else x = x:gsub( "{{Статья в словнике3|([^|]+)|[^|]+|[%s]*|[^{}]-}}", "[[" .. root .. "/%1|%1]]") x = x:gsub( "{{Статья в словнике3|([^|]+)|[%s]*|([^|]+)|[^{}]-}}", "[[" .. root .. "/%1|%2]]") x = x:gsub( "{{Статья в словнике3|([^|]+)|[^|]+|([^|]+)|[^{}]-}}", "[[" .. root .. "/%1|%2]]") end
--Vladis13 (обсуждение)
Оптимизация парсинга
[править]@Sergey kudryavtsev, Сергей, как успехи с конвертом словника в массив-модуль Lua? Это вообще возможно реализовать? По сути, парсинг словников — это «костыльная» симуляция обычной базы данных. Я подумал, в формат SQL, и тем более на Викиданные словники переводить наверно не стоит — получится сотни тысяч элементов. Можно было бы ещё сделать базы данных на tools.wmflabs (можно и переведя в формат sqlite), но для редакторов доступ туда весьма затруднён, и негоже держать такие критичные данные в стороне. К тому же, запросы к SQL или Викиданным получатся сложнее и дороже (програмно). Получается, что текущий формат словников списком на странице более оптимален?
Хотелось бы ещё скрестить функцию списка словников на одной обычной странице, как сделано в ТСД (пример) и парсится шаблоном «Отексте» и модулем, со списком этих же словников в модуле «Header». Чтобы не дублироваться, и редакторы-не программисты не морочились редактированием этого списка в Lua, рискуя заодно повредить код.
И ещё вопрос, как в модуле получить коротким массивом за один проход все данные по термину в словнике (о котором есть страница) — название страницы, название термина в ДО, в СО, пагинация, предыдущая и следующая страница. Насколько я понимаю, сейчас надо делать множество дорогих одних и тех же проходов парсера по словнику, чтобы получить отдельно заголовок, отдельно пагинацию, отдельно названия, отдельно предыдущая и отдельно следующая страницы. Хотя фактически эта инфа парсится сразу, как бы и получить сразу. --Vladis13 (обсуждение) 20:11, 14 октября 2016 (UTC)
- Вроде получилось. Модуль:Header/termindata собирает всю инфу по термину из словника и загружается один раз, возвращает таблицу (массив). Вызывается примерно так — для примера все данные в одну строку. --Vladis13 (обсуждение) 03:32, 15 октября 2016 (UTC)
- Сергей, как успехи с конвертом словника в массив-модуль Lua? — Я ещё не начинал. Все дело в последнем параметре словника (номер страницы скана). В словнике ЭЛ он лишний, потому что он есть функция от номера тома и страницы в томе.
- Получается, что текущий формат словников списком на странице более оптимален? — Задайте себе вопрос — оптимален для чего? Текущий формат словников оптимален для редактирования людьми, но не оптимален для доступа из кода LUA.
- Оптимальность в плане дороговизны дублирующихся проходов парсера, при текущих словниках оптимизированных для людей. Я поверхностно исследовал модуль, но мне кажется, функция makelink возвращает только 1 параметр за раз (вынуждая вызывать отдельно p.title, p.next, p.previous), а потом дополнительно p.pagenum. Хотя вызывает makelist, которая возвращает спарсенный словник при каждом вызове.
Получается, что, к примеру, для рендеринга шапки статьи ТСД (привожу его как непростой пример, и поскольку им занимаюсь) надо сделать 20 раз (!) парсинг одной и той же страницы словника… Код шапки. — Это десять ссылок, и перед каждой проверка на существование термина в словнике (10*2). +К этому идут также проверки на наличие словников (запуск функции wordlist), которой надо вроде тоже минимум 20 штук. И это грубый вариант, возможно нужно добавить ещё проверки, что увеличит парсинги ещё на порядок. / Объединение в data-модуль должно сократить всё до ~5 перезапусков парсера. Хотя хотелось бы получить всю инфу за один проход. --Vladis13 (обсуждение) 20:16, 15 октября 2016 (UTC) - Может проблема ЭЛ тоже в этом?
- Это всё было понятно и по первой вашей реплике, я с вами согласен. Но к сожалению, чтобы решить эту проблему, надо перепахать весь этот модуль. Если вы готовы на это, попробуйте это сделать. -- Sergey kudryavtsev (обсуждение) 07:28, 17 октября 2016 (UTC)
- Оптимальность в плане дороговизны дублирующихся проходов парсера, при текущих словниках оптимизированных для людей. Я поверхностно исследовал модуль, но мне кажется, функция makelink возвращает только 1 параметр за раз (вынуждая вызывать отдельно p.title, p.next, p.previous), а потом дополнительно p.pagenum. Хотя вызывает makelist, которая возвращает спарсенный словник при каждом вызове.
- Я предлагаю использовать data-модули LUA, чтобы исключить парсинг викитекста. Точнее парсинг будет осуществлять функцией mw.loadData. Одно из достоинств mw.loadData() — это то, что обещается: The loaded module is evaluated only once per page, rather than once per {{#invoke:}} call. Но на код LUA будет возложена другая критичная для скорости операция — поиск нужного элемента в словника. Обратите внимание — в силу того, что элементы словника должны быть упорядочены в том порядке, к каком статьи идут книге, стало быть поиск возможен только последовательным перебором элементов — а это весьма не быстрая операция.
- И ещё вопрос, как в модуле получить коротким массивом за один проход все данные по термину — Я планировал парсить его внешней программой, которой на вход даёшь файл текста словника, а на выходе она формирует текст data-модуля LUA.
- Да, вставить mw.loadData() в функцию makelink, мне кажется надо обязательно, и может лучше саму её вынести в data-модуль. Хотя непонятно как в data-модуль передать параметр (название словника).
- В data-модуль ничего передать нельзя — там не может быть функций по определению, почитайте mw:Extension:Scribunto/Lua reference manual#mw.loadData. А имя data-модуля и будет именем словника, например:
local word_list = mw.loadData("Модуль:ЭЛ/Словники/" .. tostring(n));
- где n — номер тома (словника). -- Sergey kudryavtsev (обсуждение) 07:28, 17 октября 2016 (UTC)
- Именно, что в документации сказано что функции могут быть. Рабочий пример функции внутри data-модуля. Возврат t['pagename']: ТСД/Алык-test.
- Единственно в начале модуля не может быть определения
local p = {}
, к которому в Lua подключаются функции. Вроде поэтому не передаются параметры извне через frame. --Vladis13 (обсуждение) 18:00, 17 октября 2016 (UTC)- Забавно. Я прочитал «Other data types, particularly functions, are not allowed.» и подумал что функции «not allowed» везде, а не только в таблице. Меня, конечно, смущало, что можно писать return, local но я не стал глубоко над этим задумываться. Получается, что в таких модулях может быть сколь угодно сложный код инициализации. Теперь я понял вашу идею — вы хотите в коде инициализации построить требуемую таблицу по нашим обычным словникам. Да, это может сработать. А получить информацию извне можно из контекста вызова (mw.getCurrentFrame(), mw.title.getCurrentTitle() и подобными функциями). Попробуйте также передать параметры через переменную _G — может сработает... -- Sergey kudryavtsev (обсуждение) 03:31, 18 октября 2016 (UTC)
- Спихнул почти все функции в модуль данных [1], в статье работает[2].
- С _G и mw.getCurrentFrame() что-то не получается [3] [4]. _G ничего не возвращает. Модуль данных _G не принимает, надо по особому обращаться, или может глобальные переменные действуют только в пределах модуля?.. И
t['frame'] = mw.getCurrentFrame().args[1]
ничего не возвращает,t['frame'] = mw.getCurrentFrame():getParent().args[1]
даёт ошибку: «attempt to index a nil value. Время, выделенное для выполнения скриптов, истекло.» Может не правильный синтаксис? --Vladis13 (обсуждение) 04:54, 18 октября 2016 (UTC)- Да, замуровали демоны! ;-) Может глобальные переменные действуют только в пределах модуля? — очень может быть. Ошибка «attempt to index a nil value» означает что либо mw.getCurrentFrame():getParent(), либо mw.getCurrentFrame():getParent().args == nil (первое вероятнее). Ну а mw.title.getCurrentTitle() внутри модуля возвращает имя текущей статьи? -- Sergey kudryavtsev (обсуждение) 08:15, 18 октября 2016 (UTC)
- Да, с
local currtitle = mw.title.getCurrentTitle()
всё отлично. Но возвращать можно только подстроки этого объекта (массива). Иначе, при попытке вернуть сам этот объект будет ошибка «нельзя вернуть функцию» (как и сказано в документации).--Vladis13 (обсуждение) 21:02, 18 октября 2016 (UTC)local currtitle = mw.title.getCurrentTitle() t['currname'] = currtitle["text"] -- ок -- t['currname'] = currtitle -- ошибка -- t['g'] = _G -- ошибка -- t['frame'] = mw.getCurrentFrame() -- ошибка return t
- Я просто о том, что data-модуль при помощи mw.title.getCurrentTitle() «знает» откуда он был вызван. Т.е. можно узнать название статьи, энциклопедию и вид орфографии, подгрузить нужный словник и вернуть информацию именно по этой статье на блюдечке с золотой каёмочкой.
- Другой способ получить информацию от вызывающего — сделать внутри из data-модуля так называемый обратный вызов (callback) вызывающего модуля:
lоcal var1, var2, ... = require("имя вызывающего модуля").название_функции(par1, par2, ...) . -- ...
- В силу того, что в момент загрузки data-модуля вызывающий модуль, очевидно, уже загружен, то я ожидаю, что require() просто вернёт ссылку именно на экземпляр вызывававшего модуля. -- Sergey kudryavtsev (обсуждение) 11:37, 19 октября 2016 (UTC)
- Да, рабочие примеры этого способа приводил ранее. Действительно, в заголовке текущей статьи есть же название энциклопедии, и имея список её словников, можно вычислить любой путь из самого модуля данных без дополнительных параметров. --Vladis13 (обсуждение) 13:38, 20 октября 2016 (UTC)
- «Ошибка Lua: not enough memory», — если из модуля «ТСД» загрузить дата модуль, в котором вызвать
local moduleTSD = require('Module:ТСД')
… Мне кажется, утечка памяти из-за рекурсивного создания объектов. Можно ещё поизвращаться над алгоритмом: сделать 3-й модуль как библиотеку функций. Тогда и из 1-го (и извне) их можно будет вызывать с любыми параметрами, и из модуля данных только для текущей страницы без этой ошибки, (и заодно дублироваться не будут). Надо попробовать. :) --Vladis13 (обсуждение) 17:40, 21 октября 2016 (UTC)
- «Ошибка Lua: not enough memory», — если из модуля «ТСД» загрузить дата модуль, в котором вызвать
- Да, рабочие примеры этого способа приводил ранее. Действительно, в заголовке текущей статьи есть же название энциклопедии, и имея список её словников, можно вычислить любой путь из самого модуля данных без дополнительных параметров. --Vladis13 (обсуждение) 13:38, 20 октября 2016 (UTC)
- Да, с
- Да, замуровали демоны! ;-) Может глобальные переменные действуют только в пределах модуля? — очень может быть. Ошибка «attempt to index a nil value» означает что либо mw.getCurrentFrame():getParent(), либо mw.getCurrentFrame():getParent().args == nil (первое вероятнее). Ну а mw.title.getCurrentTitle() внутри модуля возвращает имя текущей статьи? -- Sergey kudryavtsev (обсуждение) 08:15, 18 октября 2016 (UTC)
- Забавно. Я прочитал «Other data types, particularly functions, are not allowed.» и подумал что функции «not allowed» везде, а не только в таблице. Меня, конечно, смущало, что можно писать return, local но я не стал глубоко над этим задумываться. Получается, что в таких модулях может быть сколь угодно сложный код инициализации. Теперь я понял вашу идею — вы хотите в коде инициализации построить требуемую таблицу по нашим обычным словникам. Да, это может сработать. А получить информацию извне можно из контекста вызова (mw.getCurrentFrame(), mw.title.getCurrentTitle() и подобными функциями). Попробуйте также передать параметры через переменную _G — может сработает... -- Sergey kudryavtsev (обсуждение) 03:31, 18 октября 2016 (UTC)
- В data-модуль ничего передать нельзя — там не может быть функций по определению, почитайте mw:Extension:Scribunto/Lua reference manual#mw.loadData. А имя data-модуля и будет именем словника, например:
- Да, вставить mw.loadData() в функцию makelink, мне кажется надо обязательно, и может лучше саму её вынести в data-модуль. Хотя непонятно как в data-модуль передать параметр (название словника).
- Ещё вариант — поставить бота, который конвертил бы словники в data-модули. И автозапускался при появлении новых правок словников. Но вопрос как его запускать — если по расписанию, например раз в день/час, то будет запаздывание. — Редакторы изменят словник, но изменения не отобразится. Можно запускать и каждые 5 минут, но вроде это слишком часто, и всеровно будет задержка и непонятки редакторов. / Или в Проекты энциклопедий добавить кнопку для однократного запуска бота-конвертатора словников. Т.е. редактор изменил словники, затем жмёт кнопку для обновления.
- Я тоже об этом думал. -- Sergey kudryavtsev (обсуждение) 07:28, 17 октября 2016 (UTC)
- Ещё вариант — поставить бота, который конвертил бы словники в data-модули. И автозапускался при появлении новых правок словников. Но вопрос как его запускать — если по расписанию, например раз в день/час, то будет запаздывание. — Редакторы изменят словник, но изменения не отобразится. Можно запускать и каждые 5 минут, но вроде это слишком часто, и всеровно будет задержка и непонятки редакторов. / Или в Проекты энциклопедий добавить кнопку для однократного запуска бота-конвертатора словников. Т.е. редактор изменил словники, затем жмёт кнопку для обновления.
- Выборка в массивах работает быстро, они в памяти. Парсинг регулярками считается медленной и дорогой функцией. --Vladis13 (обсуждение) 20:16, 15 октября 2016 (UTC)
- Парсинг регулярками тоже производится в памяти, но это не делает его быстрым. ;-) Среднее время поиска последовательным перебором прямо пропорционально размеру массива. У нас число статей в одном томе ЭЛ — до полутора тысяч (см. таблицу в Обсуждение Викитеки:Проект:ЭЛ#Разделение словников), только это нас и спасает. -- Sergey kudryavtsev (обсуждение) 07:28, 17 октября 2016 (UTC)
- Выборка в массивах работает быстро, они в памяти. Парсинг регулярками считается медленной и дорогой функцией. --Vladis13 (обсуждение) 20:16, 15 октября 2016 (UTC)
- По вашему примеру. зря вы добавили поля next и previous — если так сделать, то редактирование data-модуля LUA для человека станет очень неудобным. их надо определять исходя из последовательности элементов словника. -- Sergey kudryavtsev (обсуждение) 18:25, 15 октября 2016 (UTC)
- Этот пример если хотите можете переписывать. Для ТСД я буду использовать другой вариант с 2-мерным массивом и циклом, ибо там 3 издания на странице.
- Поля next и previous не для отдельного редактирования, они вычисляются текущими функциями Header из словников, необходимы для рендеринга шапки статьи (ссылки «ПРЕДЫДУЩИЙ»|«СЛЕДУЮЩИЙ»).
- В моём предложенном варианте чуть другая идея. Мне кажется, для отдельной статьи не нужно конвертить весь словник в data-модуль. Нужны только данные по термину этой статьи. --Vladis13 (обсуждение) 20:16, 15 октября 2016 (UTC)
word_list() - 3-й параметр в списке словников
[править]@Sergey kudryavtsev вы добавили параметр, и вроде из ЭЛ/ДО/Веньшан исчезла ошибка. Что он значит? --Vladis13 (обсуждение) 09:30, 24 октября 2016 (UTC)
- Для того и добавлял. ;-) Этот «параметр» — второй словник, который просматривается, тогда, когда в первом статья не нашлась. Этому меня Lozmann научил пару лет назад... Тут есть тонкость: если в первом словнике статья нашлась, то второй не просматривается. В результате получается, что в Модуль:Header не умеет правильно обрабатывать статьи из нескольких частей, которые расположены в разных томах (в ЭЛ такие мне встречались). -- Sergey kudryavtsev (обсуждение) 09:42, 24 октября 2016 (UTC)
- Спасибо, то что надо! --Vladis13 (обсуждение) 10:11, 24 октября 2016 (UTC)