Модуль:SummaryII/test

Материал из свободной русской энциклопедии «Традиция»
Перейти к: навигация, поиск

Онтология[править]

Умолчания[править]

Несколько параметров[править]

Параметры Новые параметры
 {
   ['название3'] = 'Название5',
   ['название2'] = 'Название3, Название4',
   ['название'] = 'Название1, Название2',
   ['дата создания2'] = '5 ноября 1613',
   ['дата создания'] = '* 9 января 1976 года,
  • 20 апреля 1889,
  • 4 ноября 1612',
   ['Ссылка'] = '* http://traditio.wiki,

}

 {
   ['название'] = 'Я сам знаю, какое название лучше',
   ['дата создания'] = '* 9 января 1976 года,
  • 20 апреля 1889,
  • 4 ноября 1612',
   ['дата создания2'] = '5 ноября 1613',
   ['датасоздания_9991'] = '1 сентября 2016',
   ['Ссылка'] = '* http://traditio.wiki,

}

Несколько параметров[править]

Параметры Возврат
название3 = Название5
название2 = Название3, Название4
название = [[Название1]], [[Название2]]
дата создания2 = [[5 ноября]] [[1613]]
дата создания = * 9 января 1976 года,
* 20 апреля 1889,
* 4 ноября 1612
Ссылка = * http://traditio.wiki,
* http://traditio-ru.org,
* http://traditio.ru
 {
   [1] =  {
       ['датасоздания'] =  {
           [1] = '* 9 января 1976 года,
  • 20 апреля Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.1889,
  • 4 ноября Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.1612Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
           ['9991'] = '1 сентября 2016Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
           ['2'] = '5 ноября 1613Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.'
       },
       title =   {
           [1] = 'Я сам знаю, какое название лучше'
       },
       url =   {
           [1] = '* http://traditio.wiki,
       }
   },
   [2] =  {
   },
   [3] =  {
       [1] =  {
           vectors =   {
               ['датасоздания'] =  {
                   [1] =  {
                       ['Дата создания'] = '9 января 1976',
                       ['Год создания'] = '1976',
                       ['День создания'] = '9 января'
                   },
                   [2] =  {
                       ['Дата создания'] = '20 апреля 1889',
                       ['Год создания'] = '1889',
                       ['День создания'] = '20 апреля'
                   },
                   [3] =  {
                       ['Дата создания'] = '4 ноября 1612',
                       ['Год создания'] = '1612',
                       ['День создания'] = '4 ноября'
                   }
               },
               title =   {
                   [1] =  {
                       Title =  'Я сам знаю'
                   },
                   [2] =  {
                       Title =  'какое название лучше'
                   }
               },
               url =   {
                   [1] =  {
                       URL =  'http://traditio.wiki'
                   },
                   [2] =  {
                       URL =  'http://traditio-ru.org'
                   },
                   [3] =  {
                       URL =  'http://traditio.ru'
                   }
               }
           },
           lines =   {
               ['датасоздания'] = '* 9 января 1976 года,
  • 20 апреля Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.1889,
  • 4 ноября Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.1612Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
               title =  'Я сам знаю, какое название лучше',
               url =  '* http://traditio.wiki,
           }
       },
       ['9991'] =  {
           vectors =   {
               ['датасоздания'] =  {
                   [1] =  {
                       ['Дата создания'] = '1 сентября 2016',
                       ['Год создания'] = '2016',
                       ['День создания'] = '1 сентября'
                   }
               }
           },
           lines =   {
               ['датасоздания'] = '1 сентября 2016Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.'
           }
       },
       ['2'] =  {
           vectors =   {
               ['датасоздания'] =  {
                   [1] =  {
                       ['Дата создания'] = '5 ноября 1613',
                       ['Год создания'] = '1613',
                       ['День создания'] = '5 ноября'
                   }
               }
           },
           lines =   {
               ['датасоздания'] = '5 ноября 1613Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.'
           }
       }
   }

}

Сильные форматы[править]

Составные форматы[править]

Строка Захваты

дата создания5 = [[9 января]] [[1976]], [[20 апреля]] [[1889]]

{
   [1] = 'датасоздания',
   [2] = '5',
   [3] = '9 января 1976, 20 апреля Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.1889Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
   [4] =  {
       [1] =  {
           ['Дата создания'] = '9 января 1976',
           ['Год создания'] = '1976',
           ['День создания'] = '9 января'
       },
       [2] =  {
           ['Дата создания'] = '20 апреля 1889',
           ['Год создания'] = '1889',
           ['День создания'] = '20 апреля'
       }
   },
   [5] = ', '

}

дата создания4 = 9 января или 1 февраля 1976

{
   [1] = 'датасоздания',
   [2] = '4',
   [3] = '9 января или 1 февраля 1976Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
   [4] =  {
       [1] =  {
           ['Дата создания'] = '9 января 1976',
           ['Год создания'] = '1976',
           ['День создания'] = '9 января'
       },
       [2] =  {
           ['Дата создания'] = '1 февраля 1976',
           ['Год создания'] = '1976',
           ['День создания'] = '1 февраля'
       }
   },
   [5] = ', '

}

дата создания = [[9 января]] [[1976]]

{
   [1] = 'датасоздания',
   [2] = 1,
   [3] = '9 января 1976Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
   [4] =  {
       [1] =  {
           ['Дата создания'] = '9 января 1976',
           ['Год создания'] = '1976',
           ['День создания'] = '9 января'
       }
   },
   [5] = ', '

}

дата создания2 = * 9 января 1976 года, * 20 апреля 1889, * 4 ноября 1612

{
   [1] = 'датасоздания',
   [2] = '2',
   [3] = '* 9 января 1976 года,
  • 20 апреля Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.1889,
  • 4 ноября Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.1612Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
   [4] =  {
       [1] =  {
           ['Дата создания'] = '9 января 1976',
           ['Год создания'] = '1976',
           ['День создания'] = '9 января'
       },
       [2] =  {
           ['Дата создания'] = '20 апреля 1889',
           ['Год создания'] = '1889',
           ['День создания'] = '20 апреля'
       },
       [3] =  {
           ['Дата создания'] = '4 ноября 1612',
           ['Год создания'] = '1612',
           ['День создания'] = '4 ноября'
       }
   },
   [5] = ', '

}

создание3 = Предположительно, 9 января 1976 или 1977

{
   [1] = 'датасоздания',
   [2] = '3',
   [3] = 'Предположительно, 9 января 1976 или 1977Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.Свойство «Дата создания» имеет особое назначение, и его значение не может устанавливаться в семантической аннотации.',
   [4] =  {
       [1] =  {
           ['Дата создания'] = '9 января 1976',
           ['Год создания'] = '1976',
           ['День создания'] = '9 января'
       },
       [2] =  {
           ['Дата создания'] = '9 января 1977',
           ['Год создания'] = '1977',
           ['День создания'] = '9 января'
       }
   },
   [5] = ', '

}

URL[править]

Строка Захваты

ссылка(4) = traditio.wiki

{
   [1] = 'url',
   [2] = '4',
   [3] = 'traditio.wiki',
   [4] =  {
       [1] =  {
           URL =  'http://traditio.wiki'
       }
   },
   [5] = ', '

}

Ссылка3 = [http://traditio.wiki traditio.wiki]

{
   [1] = 'url',
   [2] = '3',
   [3] = 'traditio.wiki',
   [4] =  {
       [1] =  {
           URL =  'http://traditio.wiki'
       }
   },
   [5] = ', '

}

Ссылка5 = /Заглавная страница

{
   [1] = 'Not matched',
   [2] = 'Ссылка5 = /Заглавная страница'

}

ссылка = * http://traditio.wiki, * http://traditio-ru.org, * http://traditio.ru

{
   [1] = 'url',
   [2] = 1,
   [3] = '* http://traditio.wiki,
   [4] =  {
       [1] =  {
           URL =  'http://traditio.wiki'
       },
       [2] =  {
           URL =  'http://traditio-ru.org'
       },
       [3] =  {
           URL =  'http://traditio.ru'
       }
   },
   [5] = ', '

}

ссылка2 = http://traditio.wiki

{
   [1] = 'url',
   [2] = '2',
   [3] = 'http://traditio.wiki',
   [4] =  {
       [1] =  {
           URL =  'http://traditio.wiki'
       }
   },
   [5] = ', '

}

Единица измерения перед числом[править]

Строка Захваты

стоимость = 16 руб.

{
   [1] = 'cost',
   [2] = 1,
   [3] = '16 руб.',
   [4] =  {
       [1] =  {
           Cost =  '16 руб.'
       }
   },
   [5] = ', '

}

стоимость2 = $30

{
   [1] = 'cost',
   [2] = '2',
   [3] = '$30',
   [4] =  {
       [1] =  {
           Cost =  '$30'
       }
   },
   [5] = ', '

}

стоимость3 = 30 €

{
   [1] = 'cost',
   [2] = '3',
   [3] = '30€',
   [4] =  {
       [1] =  {
           Cost =  '30 руб.'
       }
   },
   [5] = ', '

}

Количество на примере массы[править]

Строка Захваты

масса6 = 64 kg

{
   [1] = 'mass',
   [2] = '6',
   [3] = '64 kg',
   [4] =  {
       [1] =  {
           Mass =  '64 kg'
       }
   },
   [5] = ', '

}

масса_5 = 6,4 * 10<sup>3</sup>

{
   [1] = 'mass',
   [2] = '5',
   [3] = '6,4 * 103',
   [4] =  {
       [1] =  {
           Mass =  '6,4e3 kg'
       }
   },
   [5] = ', '

}

масса12 = [[:46 kg]], [[120 kg]]

{
   [1] = 'mass',
   [2] = '12',
   [3] = '46 kg, 120 kg',
   [4] =  {
       [1] =  {
           Mass =  '120 kg'
       }
   },
   [5] = ', '

}

Масса = 6.4e3 kg

{
   [1] = 'mass',
   [2] = 1,
   [3] = '6.4e3 kg',
   [4] =  {
       [1] =  {
           Mass =  '6,4e3 kg'
       }
   },
   [5] = ', '

}

масса14 = 64 kg, [[:120 kg]], [[160 kg]]

{
   [1] = 'mass',
   [2] = '14',
   [3] = '64 kg, 120 kg, 160 kg',
   [4] =  {
       [1] =  {
           Mass =  '160 kg'
       }
   },
   [5] = ', '

}

масса7 = [[64 kg]]

{
   [1] = 'mass',
   [2] = '7',
   [3] = '64 kg',
   [4] =  {
       [1] =  {
           Mass =  '64 kg'
       }
   },
   [5] = ', '

}

масса10 = 64 kg, [[120 kg]]

{
   [1] = 'mass',
   [2] = '10',
   [3] = '64 kg, 120 kg',
   [4] =  {
       [1] =  {
           Mass =  '120 kg'
       }
   },
   [5] = ', '

}

масса13 = Пустая болтовня [[:в никуда| ]]

{
   [1] = 'Not matched',
   [2] = 'масса13 = Пустая болтовня  '

}

масса (1945) = 64 kg, 120 kg

{
   [1] = 'mass',
   [2] = '1945',
   [3] = '64 kg, 120 kg',
   [4] =  {
       [1] =  {
           Mass =  '64 kg'
       },
       [2] =  {
           Mass =  '120 kg'
       }
   },
   [5] = ', '

}

масса(4) = [[6,4 × 10<sup>3</sup>]]

{
   [1] = 'mass',
   [2] = '4',
   [3] = '6,4 × 103',
   [4] =  {
       [1] =  {
           Mass =  '6,4e3 kg'
       }
   },
   [5] = ', '

}

масса11 = 64 kg, [[:120 kg]]

{
   [1] = 'Not matched',
   [2] = 'масса11 = 64 kg, 120 kg'

}

масса8 = [[64 kg|4 пуда]]

{
   [1] = 'mass',
   [2] = '8',
   [3] = '4 пуда',
   [4] =  {
       [1] =  {
           Mass =  '64 kg'
       }
   },
   [5] = ', '

}

масса3 = 6,4 × 10<sup>3</sup>

{
   [1] = 'mass',
   [2] = '3',
   [3] = '6,4 × 103',
   [4] =  {
       [1] =  {
           Mass =  '6,4e3 kg'
       }
   },
   [5] = ', '

}

масса17 = -1300 kg, -1 400 kg, - 1 500 kg, -1600kg

{
   [1] = 'mass',
   [2] = '17',
   [3] = '-1300 kg, -1 400 kg, - 1 500 kg, -1600kg',
   [4] =  {
       [1] =  {
           Mass =  '-1300 kg'
       },
       [2] =  {
           Mass =  '-1400 kg'
       },
       [3] =  {
           Mass =  '-1500 kg'
       },
       [4] =  {
           Mass =  '-1600 kg'
       }
   },
   [5] = ', '

}

масса16 = 1 200 kg, 2 400 kg

{
   [1] = 'mass',
   [2] = '16',
   [3] = '1 200 kg, 2 400 kg',
   [4] =  {
       [1] =  {
           Mass =  '1200 kg'
       },
       [2] =  {
           Mass =  '2400 kg'
       }
   },
   [5] = ', '

}

масса15 = * 64 kg, * 120 kg

{
   [1] = 'mass',
   [2] = '15',
   [3] = '* 64 kg,
   [4] =  {
       [1] =  {
           Mass =  '64 kg'
       },
       [2] =  {
           Mass =  '120 kg'
       }
   },
   [5] = ', '

}

масса9 = [[:64 kg]]

{
   [1] = 'Not matched',
   [2] = 'масса9 = 64 kg'

}

масса = [[16|пуд]]

{
   [1] = 'mass',
   [2] = 1,
   [3] = 'пуд',
   [4] =  {
       [1] =  {
           Mass =  '16 kg'
       }
   },
   [5] = ', '

}

Слабые форматы (текст, страница)[править]

Строка Захваты

название9 = Тестовая строка 1, [[:тестовая строка 2]], [[тестовая строка 3]]

{
   [1] = 'title',
   [2] = '9',
   [3] = 'Тестовая строка 1, тестовая строка 2, тестовая строка 3',
   [4] =  {
       [1] =  {
           Title =  'тестовая строка 3'
       }
   },
   [5] = ', '

}

название4 = Тестовая строка 1, тестовая строка 2

{
   [1] = 'title',
   [2] = '4',
   [3] = 'Тестовая строка 1, тестовая строка 2',
   [4] =  {
       [1] =  {
           Title =  'Тестовая строка 1'
       },
       [2] =  {
           Title =  'тестовая строка 2'
       }
   },
   [5] = ', '

}

название = Тестовая строка

{
   [1] = 'title',
   [2] = 1,
   [3] = 'Тестовая строка',
   [4] =  {
       [1] =  {
           Title =  'Тестовая строка'
       }
   },
   [5] = ', '

}

название6 = Тестовая строка 1, [[:тестовая строка 2]]

{
   [1] = 'Not matched',
   [2] = 'название6 = Тестовая строка 1, тестовая строка 2'

}

название1 = [[Тестовая строка]]

{
   [1] = 'title',
   [2] = '1',
   [3] = 'Тестовая строка',
   [4] =  {
       [1] =  {
           Title =  'Тестовая строка'
       }
   },
   [5] = ', '

}

название3 = [[:Тестовая строка]]

{
   [1] = 'Not matched',
   [2] = 'название3 = Тестовая строка'

}

название10 = * Тестовая строка 1, * тестовая строка 2

{
   [1] = 'title',
   [2] = '10',
   [3] = '* Тестовая строка 1,
   [4] =  {
       [1] =  {
           Title =  'Тестовая строка 1'
       },
       [2] =  {
           Title =  'тестовая строка 2'
       }
   },
   [5] = ', '

}

название(8) = Пустая болтовня [[:в никуда| ]]

{
   [1] = 'Not matched',
   [2] = 'название(8) = Пустая болтовня  '

}

название7 = [[:Тестовая строка 1]], [[тестовая строка 2]]

{
   [1] = 'title',
   [2] = '7',
   [3] = 'Тестовая строка 1, тестовая строка 2',
   [4] =  {
       [1] =  {
           Title =  'тестовая строка 2'
       }
   },
   [5] = ', '

}

название5 = Тестовая строка 1, [[тестовая строка 2]]

{
   [1] = 'title',
   [2] = '5',
   [3] = 'Тестовая строка 1, тестовая строка 2',
   [4] =  {
       [1] =  {
           Title =  'тестовая строка 2'
       }
   },
   [5] = ', '

}

название2 = [[Тестовая строка 1|Первая тестовая строка]]

{
   [1] = 'title',
   [2] = '2',
   [3] = 'Первая тестовая строка',
   [4] =  {
       [1] =  {
           Title =  'Тестовая строка 1'
       }
   },
   [5] = ', '

}


--[[
Тесты SummaryII.
--]]

local table_and_array_functions = require "Модуль:Array"
local merge 					= table_and_array_functions.table_merge
local service					= require "Модуль:SummaryII/service"
local strip						= service.strip
local strip_number				= service.strip_number

-- Эта функция добавляет к явно заданным параметрам умолчания: которые можно перезаписать, дополнить или защищённые:
local function make_params (explicit, overwriteable_defaults, appendable_defaults, protected_defaults)
	local params = {}
	-- Перезаписываемые умолчания:
	for name, default in pairs (overwriteable_defaults or {}) do
		params [strip (name)] = default
	end
	-- Дополняемые умолчания:
	for name, values in pairs (appendable_defaults or {}) do
		for i, value in ipairs (values) do
			params [name .. '_999' .. tostring (i)] = value
		end
	end
	local protected_defaults = protected_defaults or {}
	-- Явно заданные параметры:
	for name, value in pairs (explicit) do
		local stripped = strip_number (tostring (name))
		if params [stripped] then
			params [stripped] = nil
		end
		if not protected_defaults [stripped] then
			params [name] = value
		end
	end
	-- Защищённые умолчания:
	for name, value in pairs (protected_defaults) do
		params [name] = value
	end
	return params
end		-- local function make_params (explicit, overwriteable_defaults, appendable_defaults, protected_defaults)

--[[
Class TemplateProcessor.

Зависимости:
	Модуль:Class,
	Модуль:Array,
	Модуль:SummaryII/service
	lpeg
	Модуль:Re
--]]
local Class = require ('Модуль:Class').create

-- Accelerators:
local Array						= table_and_array_functions.Array

local lpeg		= lpeg
local Ct		= lpeg.Ct
local cartesian	= require "Модуль:Array".cartesian

local deserialise_lpeg	= lpeg.serialize.load
local gsub				= mw.ustring.gsub

local TemplateProcessor = Class {
	lines		= {}
  , vectors		= {}
  , flat		= {}
  , separators	= {}
}

function TemplateProcessor:_init (serialised_parsers)
	self.lpeg = lpeg.P (false)
	for _, parser in ipairs (serialised_parsers) do
		self.lpeg = self.lpeg + deserialise_lpeg (parser)
	end
end		-- function TemplateProcessor:_init (serialised_parsers)

function TemplateProcessor:_call (params)
	local cartesian_append = Array.cartesian_append
	for name, value in pairs (params) do
		local id, index, line, vectors, separator = self:single (name, value)
		self.vectors [index] = self.vectors [index] or {lines = {}, vectors = {}}
		self.vectors [index].lines		[id] = line
		self.vectors [index].vectors	[id] = vectors
		
		self.flat [index] = (self.flat [index] or Array ()):cartesian_append (vectors)
		
		self.lines [id] = self.lines [id] or {}
		self.lines [id] [index] = line
		
		self.separators [id] = separator
	end	-- for name, value in pairs (params)
	return self.lines, self.flat, self.vectors
end		-- function TemplateProcessor:_call (params)
		
function TemplateProcessor:single (name, value)
	local glued = self:glue_param (name, value)
	local captures = Ct (self.lpeg):match (glued)
	if captures and type (captures) == 'table' then
		
		local index = captures.index or 1
		
		local line = ''
		local ordered_values = {}
		
		-- Initialise intravectors:
		local complete_vectors = Array ()
		local polyvector = {}
		local last_no = 0
		
		local separator = ', '
		for i, affixed in ipairs (captures) do
			
			-- Choose normalised SMW value:
			affixed.value = affixed.processed [2] or affixed.processed [1]
			-- Choose alias:
			affixed.alias = affixed.alias or affixed.processed [1]
			
			-- Append pure property list for later use:
			-- TODO: ordering is not needed any more.
			ordered_values [#ordered_values + 1] = {
				property	= affixed.property
			  , value		= affixed.value
			}
			
			-- Form intravectors:
			local no			= tonumber (affixed.no)
			local new_vectors	= {}
			local inject		= nil

			if no < last_no then
				-- New intravector:
				new_vectors = cartesian (polyvector)
				polyvector = {}				
				inject = captures.inject
			end
			
			polyvector [affixed.property] = polyvector [affixed.property] or {}
			polyvector [affixed.property] [#polyvector [affixed.property] + 1] = affixed.value
			last_no = no
			
			-- Append output line:
			line = line	.. self.substitute (affixed.output, affixed)

			if i == #captures then
				-- Last intravector:
				new_vectors = cartesian (polyvector)
				inject = captures.inject
			end
			
			if inject then
				for _, vector in ipairs (new_vectors) do
					line = line .. self.substitute (inject, vector)
				end
			end
							
			complete_vectors:append2self (new_vectors)
			
			separator = affixed.separtor or separator

		end	-- for _, affixed in ipairs (captures)
		
		-- Attach tail:
		line = line .. (captures.tail or '')
		
		for _, vector in ipairs (complete_vectors) do
			-- Infer properties:
			if captures.inferred then
				for property, value in pairs (captures.inferred) do
					vector [property] = self.substitute (value, vector)
				end
			end	-- if captures.inferred
		end	-- for _, vector in ipairs (complete_vectors)

		return captures.id, index, line, complete_vectors, separator --, captures, ordered_values
	else
		return 'Not matched', name .. ' = ' .. value
	end	-- if captures and type (captures) == 'table'
end	-- function TemplateProcessor:single (name, value)

function TemplateProcessor.substitute (format, values)
	return gsub (format, '@([^@]+)@', values)
end		-- function TemplateProcessor:substitute (format, values)

function TemplateProcessor.glue (args)
	return table.concat (args, mw.ustring.char (0))
end		-- function TemplateProcessor.glue (args)

function TemplateProcessor:glue_param (name, value)
	return strip (tostring (name)) .. '=' .. mw.text.trim (value)
end		-- function TemplateProcessor:glue_param (name, value)

-- end of class TemplateProcessor

local function tester (parser, args)
	local serialise = require ('Модуль:Test').serialise
	local serialised = {parser:serialise ()}
	local processor = TemplateProcessor (serialised)
	local ret = [==[
{| class="wikitable"
! Строка !! Захваты
]==]
	for name, value in pairs (args) do
		ret = ret .. '\n|-\n|\n<code><nowiki>' .. name .. ' = ' .. value .. '</nowiki></code>\n| '
				  .. serialise ({processor:single (name, value)})
	end
	ret = ret .. '\n|}'
	return ret
end		-- local function tester (parser, args)


local spaces = lpeg.S '  ' ^ 0
local html_tags = lpeg.P {
	'tags'
  , tags	= (lpeg.P '<' * (1 - lpeg.P '>') ^ 0 * lpeg.P '>') ^ 1
}
local balanced_parentheses = lpeg.P {'(' * ((1 - lpeg.S '()') + lpeg.V (1))^0 * ')'}
local separators = html_tags + lpeg.S ',;:*#\n' ^ 1

-- Module interface
local m = {}
m.test_weak = function (frame)
	local parser = require "Модуль:SummaryII/parsers".parser
	local str = parser ({'Название'}, 'string', 'Title', separators)
	return frame:preprocess (tester (str, frame.args))
end
m.test_mass = function (frame)
	local parser = require "Модуль:SummaryII/parsers".parser
	local mass = parser ({'Масса'}, 'quantity', 'Mass', separators, {units = {'kg', 'g', 'tonne', 'tonnes', 'mg', 'mkg'}, default_unit = 'kg'})
	return frame:preprocess (tester (mass, frame.args))
end
m.test_money = function (frame)
	local parser = require "Модуль:SummaryII/parsers".parser
	local cost = parser ({'Стоимость'}, 'quantity', 'Cost', separators, {units = {'руб.', 'долл.', 'USD', 'евро'}, preunits = {'$', '€', '£'}, default_unit = 'руб.'})
	return frame:preprocess (tester (cost, frame.args))
end
m.test_url = function (frame)
	local parser = require "Модуль:SummaryII/parsers".parser
	local url = parser ({'Ссылка'}, 'URL', 'URL', separators, {default_protocol = 'http'})
	return frame:preprocess (tester (url, frame.args))
end
m.test_date = function (frame)
	local parser = require "Модуль:SummaryII/parsers".parser
	local date = parser ({'Дата создания', 'создание'}, 'date', 'создания', separators)
	return frame:preprocess (tester (date, frame.args))
end
m.test_params = function (frame)
	local serialise = require ('Модуль:Test').serialise
	local factory = require "Модуль:SummaryII/parsers".parser
	local grammars = {
		factory ({'Название'}, 'string', 'Title', separators):serialise ()
	  , factory ({'Дата создания', 'создание'}, 'date', 'создания', separators):serialise ()
	  , factory ({'Масса'}, 'quantity', 'Mass', separators, {units = {'kg', 'g', 'tonne', 'tonnes', 'mg', 'mkg'}, default_unit = 'kg'}):serialise ()
	  , factory ({'Ссылка'}, 'URL', 'URL', separators, {default_protocol = 'http'}):serialise ()
	}
	local parser = TemplateProcessor (grammars)
	local ret = [==[
{| class="wikitable"
! Параметры !! Возврат
|-
|
]==]
	for name, value in pairs (frame.args) do
		ret = ret .. '\n <nowiki>' .. tostring (name) .. ' = ' .. value .. '</nowiki>'
	end
	local params = make_params (
		frame.args
	  , {['датасоздания']	= '1 октября 2016'}
	  , {['датасоздания']	= {'1 сентября 2016'}}
	  , {['название']		= 'Я сам знаю, какое название лучше'}
	)
	ret = ret .. '\n|\n ' .. serialise ({parser (params)}) .. '\n|}'
	return frame:preprocess (ret)
end	

function m.test_make_params (frame)
	local serialise = require ('Модуль:Test').serialise
	local ret = [==[
{| class="wikitable"
! Параметры !! Новые параметры
|-
|
]==]
	ret = ret .. '\n ' .. serialise (frame.args) .. ''
	local params = make_params (
		frame.args
	  , {['датасоздания']	= '1 октября 2016'}
	  , {['датасоздания']	= {'1 сентября 2016'}}
	  , {['название']		= 'Я сам знаю, какое название лучше'}
	)
	ret = ret .. '\n|\n ' .. serialise (params) .. '\n|}'
	return frame:preprocess (ret)
end		-- function m.test_make_params (frame)

-- Обёртка для frame:expandTemplate, чтобы не передавать frame всю дорогу:
local function expandTemplate (template, params)
    return mw.getCurrentFrame ():expandTemplate{ title = template, args = params }
end
 
m.testask = function (frame)
	return serialise (mw.ext.smw.ask (frame.args))
end

m.locale = function (frame)
	local serialise = require ('Модуль:Test').serialise
	return serialise (lpeg.locale ())
end

return m