Modulo:Software: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
super ricorsione Wikidata Considerazioni implementative -- ora nessuna licenza ci scappa!
Riga 2:
local getArgs = require('Modulo:Arguments').getArgs
local conf = mw.loadData('Modulo:Software/Configurazione')
 
local p = {}
 
--------------------------------------------------------------------------------
-- TODO Implementare in Modulo:Wikidata
 
local UNKNOWN = -1 -- Non è possibile identificare la licenza
local FREE = 1 -- È una licenza di software libero
local PROPRIETARY = 2 -- È una licenza di software proprietario
 
local MAX_RECURSION = 3 -- [[Modulo:Software/man#Considerazioni implementative]]
 
-------------------------------- Sgabuzzino ------------------------------------
 
-- TODO Spostare in Modulo:Wikidata
function p._subclassOf(args)
local statements = mWikidata._getProperty({'P279', from = args.from, formatting = 'raw'}, true)
Line 18 ⟶ 27:
end
return false
end
 
function p._isFreeSoftwareByTemplate(frame)
local is = nil
local args = frame and getArgs(frame)
local v = args['SoftwareLibero']
if v then
local yep = {['sì'] = true, ['si'] = true, ['no'] = false}
v = yep[ mw.ustring.lower(v) ]
end
return v
end
 
function p._isFreeSoftwareByWikidata(frame)
-- Q341 free software
-- Q1130645 open-source software
return mWikidata._instanceOf({'Q341', 'Q1130645'}) or p._hasAFreeLicense(frame)
end
 
function p._isProprietarySoftwareByWikidata(frame)
-- Q218616 proprietary software
-- Q178285 freeware TODO: impropria, subclass of precedente
return mWikidata._instanceOf({'Q218616', 'Q178285'}) or p._hasAProprietaryLicense(frame)
end
 
--[[
* La voce è software libero?
*
* @return true|false|nil
]]
function p._isFreeSoftware(frame)
local is_wd = p._isFreeSoftwareByWikidata()
local isnt_wd = p._isProprietarySoftwareByWikidata()
local is_tp = p._isFreeSoftwareByTemplate(frame)
local is = nil
if is_wd then
is = true
end
if isnt_wd then
is = false
end
if is_tp ~= nil then
is = is_tp
end
 
--if is_wd == true and isnt_wd == true then
-- Wikidata nonsense
--end
 
--if is_wd == true and is_tp == true then
-- Local same as Wikidata
--
 
--if (is_wd == true and is_tp == false) or (isnt_wd == true and is_tp == false) then
-- Free different from Wikidata
--
 
--if (is_wd ~= nil or isnt_wd ~= nil) and is_tp == false then
-- Free/proprietary read from Wikidata
--
return is
end
 
Line 100 ⟶ 48:
end
 
function p.isFreeSoftware(frame)
return yesNoNil( p._isFreeSoftware(frame) )
end
 
--[[
* Poi non ditemi che PHP fa schifo. asd.
* Il template ha linguaggi?
* 00:28, 28 feb 2017‎ Valerio Bozzolan
*
* @return truly|nil
]]
local function p._templateHasLanguagescount(framet)
local argsi = frame and getArgs(frame)0
for _,__ in pairs(t) do
return args['Linguaggio'] or args['NotaLinguaggio'] or args['LinguaggioAltri']
i = i + 1
end
end
 
return i
function p._templateHasExtraInformations(frame)
local args = frame and getArgs(frame)
return args['LinguaggioAltri'] or args['NotaLinguaggio'] or args['NotaLinguaggio2'] or args['NotaLinguaggio3']
end
 
--[[
* Restituisce una tabella completa di proprietà non formattate.
* La voce specifica un linguaggio di programmazione?
* @return {}|nil
*
* ]]
* @return true|nil
local function rawProperties(from, property)
]]
return mWikidata._getProperty({property, from = from, formatting = 'raw'}, true)
function p._specifiesALanguage(frame)
local args = frame and getArgs(frame)
return p._templateHasLanguages(frame) or mWikidata._getClaims('P277')
end
 
------------------------------- Frontend ---------------------------------------
function p.specifiesALanguage(frame)
return yesNo( p._specifiesALanguage(frame) )
end
 
function p.isFreeSoftware(frame)
--[[
return yesNoNil( p._isFreeSoftware(frame) )
* La voce dovrebbe specificare un linguaggio?
*
* @return true|nil
]]
function p._shouldHaveALanguage(frame)
return p._isFreeSoftware(frame) or p._specifiesALanguage(frame)
end
 
Line 146 ⟶ 79:
end
 
function p.hasAFreeLicense(frame)
--[[
return yesNoNil( p._hasAFreeLicense(frame) )
* 'cpp' → 'c++'
* 'c++' → 'c++'
]]
function p._preferredLanguageSlug(slug)
if slug then
slug = string.lower(slug)
end
return conf.languageSlugAlias[slug] or slug
end
 
function p.hasAProprietaryLicense(frame)
--[[
return yesNoNil( p._hasAProprietaryLicense(frame) )
* Reverse tree di Modulo:Software/Configurazione
*
* 'cpp' → 'Q2407'
]]
local _languageSlugToWikidata = {}
function p._languageSlugToWikidata(slug)
if next(_languageSlugToWikidata) == nil then
for q,l in pairs(conf.wikidataToLanguageSlug) do
_languageSlugToWikidata[l] = q
end
end
return _languageSlugToWikidata[ p._preferredLanguageSlug(slug) ]
end
 
function p.languageSlugToWikidataspecifiesALanguage(frame)
return p._languageSlugToWikidatayesNo( getArgsp._specifiesALanguage(frame)[1] )
end
 
--[[
* @return string[] = 'c' => 'nota linguaggio c', 'c++' = '', ..
]]
function p._getTemplateLanguages(frame)
local languages = {}
local args = frame and getArgs(frame)
local v = args['Linguaggio']
if v then
languages[ p._preferredLanguageSlug(v) ] = args['NotaLinguaggio'] or ''
end
for i=1,3 do
v = args['Linguaggio' .. i]
if v then
languages[ p._preferredLanguageSlug(v) ] = args['NotaLinguaggio' .. i] or ''
end
end
return languages
end
 
--[[
* Poi non ditemi che PHP fa schifo. asd.
* 00:28, 28 feb 2017‎ Valerio Bozzolan
]]
local function count(t)
local i = 0
for _,__ in pairs(t) do
i = i + 1
end
return i
end
 
--[[
* Le licenze della voce.
*
* @return pairs( {} )
]]
local _licenses_cache = false
function p._licenses(frame)
if _licenses_cache == false then
_licenses_cache = mWikidata._getClaims('P275') or {}
end
return _licenses_cache
end
 
Line 227 ⟶ 98:
end
return s
end
 
-- Cache
local licenseIsFree_ = {}
function p._licenseIsFree(license)
if licenseIsFree_[license] == nil then
licenseIsFree_[license] =
-- Q3943414 free software license
-- | Q7603 GNU General Public License (inherit Q27016754 GPL-3.0+)
-- | Q1131681 GNU Affero General Public License (inherit Q27017232 AGPL-3.0)
-- | Q616526 Apache License (inherit Q13785927 Apache-2.0)
mWikidata._instanceOf({'Q3943414', 'Q7603', 'Q1131681', 'Q616526', from = license})
or
-- Q1437937 permissive free software licence (to get Q616526 Apache License, Q191307 BSD license)
p._subclassOf({'Q1437937', from = license})
or
false
end
return licenseIsFree_[license]
end
 
-- Cache
local licenseIsProprietary_ = {}
function p._licenseIsProprietary(license)
-- Q14624820 non-free software license
-- Q218616 proprietary software
if license == 'Q14624820' or license == 'Q218616' then
return true
end
if licenseIsProprietary_[license] == nil then
-- Q14624820 non-free software license
-- Q218616 proprietary software
-- Q178285 freeware (to get Q193345 adware)
licenseIsProprietary_[license] = p._subclassOf({'Q14624820', 'Q218616', 'Q178285', from = license}) or false
end
return licenseIsProprietary_[license]
end
 
--[[
* La voce ha almeno una licenza di software libero?
]]
function p._hasAFreeLicense(frame)
for _, l in pairs( p._licenses(frame) ) do
l = mWikidata._formatStatement(l, {formatting = 'raw'})
if p._licenseIsFree(l) then
return true
end
end
return false
end
 
--[[
* La voce ha almeno una licenza di software proprietario?
]]
function p._hasAProprietaryLicense(frame)
for _, l in pairs( p._licenses(frame) ) do
l = mWikidata._formatStatement(l, {formatting = 'raw'})
if p._licenseIsProprietary(l) then
return true
end
end
return false
end
 
function p.hasAFreeLicense(frame)
return yesNoNil( p._hasAFreeLicense(frame) )
end
 
function p.hasAProprietaryLicense(frame)
return yesNoNil( p._hasAProprietaryLicense(frame) )
end
 
Line 399 ⟶ 200:
 
return s
end
 
-------------------------------- Backend ---------------------------------------
 
--[[
* Riassumendo. La voce è software libero?
*
* @return true|false|nil
]]
function p._isFreeSoftware(frame)
local is_wd = p._isFreeSoftwareByWikidata()
local isnt_wd = p._isProprietarySoftwareByWikidata()
local is_tp = p._isFreeSoftwareByTemplate(frame)
local is = nil
if is_wd then
is = true
end
if isnt_wd then
is = false
end
if is_tp ~= nil then
is = is_tp
end
 
--if is_wd == true and isnt_wd == true then
-- Wikidata nonsense
--end
 
--if is_wd == true and is_tp == true then
-- Local same as Wikidata
--
 
--if (is_wd == true and is_tp == false) or (isnt_wd == true and is_tp == false) then
-- Free different from Wikidata
--
 
--if (is_wd ~= nil or isnt_wd ~= nil) and is_tp == false then
-- Free/proprietary read from Wikidata
--
return is
end
 
--[[
* Spesso la voce è definita in Wikidata come istanza di software libero.
* Per quanto riguarda Wikipedia è comodo.
* Per quanto riguarda Wikidata è ridondante col campo licenza P275.
*
* @return true|false
]]
function p._isFreeSoftwareByWikidata()
-- Q341 free software
-- Q1130645 open-source software
return mWikidata._instanceOf({'Q341', 'Q1130645'}) or p._hasAFreeLicense()
end
 
--[[
* Spesso la voce è definita in Wikidata come istanza di software proprietario.
* Per quanto riguarda Wikipedia è comodo.
* Per quanto riguarda Wikidata è ridondante col campo licenza P275.
*
* @return true|false
]]
function p._isProprietarySoftwareByWikidata()
-- Q218616 proprietary software
-- Q178285 freeware TODO: impropria, subclass of precedente
return mWikidata._instanceOf({'Q218616', 'Q178285'}) or p._hasAProprietaryLicense()
end
 
--[[
* Banale lettura di `SoftwareLibero = sì/no` nel template {{Software}}
*
* @return nil|true|false
--]]
function p._isFreeSoftwareByTemplate(frame)
local is = nil
local args = frame and getArgs(frame)
local v = args['SoftwareLibero']
if v then
local yep = {['sì'] = true, ['si'] = true, ['no'] = false}
v = yep[ mw.ustring.lower(v) ]
end
return v
end
 
--[[
* Riassumendo. La voce dovrebbe specificare un linguaggio?
*
* @return true|nil
]]
function p._shouldHaveALanguage(frame)
return p._isFreeSoftware(frame) or p._specifiesALanguage(frame)
end
 
--[[
* C'è un linguaggio?
*
* @return truly|nil
]]
function p._specifiesALanguage(frame)
local args = frame and getArgs(frame)
return p._templateHasLanguages(frame) or mWikidata._getClaims('P277')
end
 
--[[
* Il template ha il campo "Linguaggio"?
*
* @return truly|nil
]]
function p._templateHasLanguages(frame)
local args = frame and getArgs(frame)
return args['Linguaggio'] or args['NotaLinguaggio'] or args['LinguaggioAltri']
end
 
--[[
* Il template ha valori non unibili a Wikidata?
*
* @return truly|nil
]]
function p._templateHasExtraInformations(frame)
local args = frame and getArgs(frame)
return args['LinguaggioAltri'] or args['NotaLinguaggio'] or args['NotaLinguaggio2'] or args['NotaLinguaggio3']
end
 
--[[
* Per mantenere retrocompatibilità con la possibilità di avere più codici.
*
* Esempio:
* 'cpp' → 'c++'
* 'c++' → 'c++'
*
* @see Template:Software/Linguaggio
* @return string
]]
function p._preferredLanguageSlug(slug)
if slug then
slug = string.lower(slug)
end
return conf.languageSlugAlias[slug] or slug
end
 
--[[
* I codici dei linguaggi del template {{Software}}.
*
* @return string[] = 'c' => 'nota linguaggio c', 'c++' = '', ..
]]
function p._getTemplateLanguages(frame)
local languages = {}
local args = frame and getArgs(frame)
local v = args['Linguaggio']
if v then
languages[ p._preferredLanguageSlug(v) ] = args['NotaLinguaggio'] or ''
end
for i=1,3 do
v = args['Linguaggio' .. i]
if v then
languages[ p._preferredLanguageSlug(v) ] = args['NotaLinguaggio' .. i] or ''
end
end
return languages
end
 
--[[
* Questa licenza è una classe radice identificabile?
*
* @param license string
* @return FREE|PROPRIETARY|UNKNOWN
* ]]
function p._singleLicenseType(license)
-- Q3943414 free software license
-- Q14624820 non-free software license
-- Q218616 proprietary software
 
--[[
* Approfonditi studi da punti di vista non neutrali hanno evidenziato come
* le prossime tre righe riassumino l'*unica* parte piacevole del Lua.
]]
return license == 'Q3943414' and FREE
or (license == 'Q14624820' or license == 'Q218616') and PROPRIETARY
or UNKNOWN
end
 
--[[
* Fra queste licenze c'è una classe radice identificabile?
*
* @param license string
* @return FREE|PROPRIETARY|UNKNOWN
* ]]
function p._findLicenseType(licenses)
local type = UNKNOWN
for _, license in pairs(licenses) do
type = p._singleLicenseType(license)
if type ~= UNKNOWN then
break
end
end
return type
end
 
--[[
* Ottiene la tipologia di una qualsiasi licenza software.
*
* Una licenza è identificabile grazie a Wikidata scorrendo ricorsivamente
* l'albero di licenze madri fino ad arrivare ad una classe radice identificabile.
*
* Questo può sembrare spaventoso, in verità sembra piuttosto efficiente,
* portando l'utilizzo medio di funzioni parser dispendiose a +2/+3.
*
* In ogni caso il limite delle funzioni parser dispendiose è 500,
* mentre si ipotizza che questa funzione possa provocarne al massimo +5/+6
* per casi peggiori.
*
* @see Modulo:Software/man#Considerazioni implementative
* @param string license
* @param int i Livello di
* @return UNKNOWN|FREE|PROPRIETARY
]]
local _licenseType_ = {} --cache
function p._licenseType(license, i)
i = i or 0
 
if _licenseType_[license] == nil then
 
-- È una licenza radice?
local type = p._singleLicenseType(license)
 
local license_instances = {}
if type == UNKNOWN then
-- In `istance of` c'è una licenza radice?
license_instances = rawProperties(license, 'P31')
if license_instances then
type = p._findLicenseType(license_instances)
end
end
 
local license_classes = {}
if type == UNKNOWN then
-- In `subclass of` c'è una licenza radice?
license_classes = rawProperties(license, 'P279')
if license_classes then
type = p._findLicenseType(license_classes)
end
end
 
if i <= MAX_RECURSION then
 
-- Risali `istance of`
if type == UNKNOWN then
if license_instances then
for _, license_instance in pairs(license_instances) do
type = p._licenseType(license_instance, i + 1)
if type ~= UNKNOWN then
break
end
end
end
end
 
-- Risali `subclass of`
if type == UNKNOWN then
if type == UNKNOWN and license_classes then
for _, license_class in pairs(license_classes) do
type = p._licenseType(license_class, i + 1)
if type ~= UNKNOWN then
break
end
end
end
end
 
-- Non si ha altro su cui aggrapparsi
 
end
 
_licenseType_[license] = type
end
 
return _licenseType_[license]
end
 
--[[
* Licenze da Wikidata.
*
* @return table|nil
]]
local _licenses_cache = false
function p._licenses()
if _licenses_cache == false then
_licenses_cache = mWikidata._getClaims('P275') or {}
end
return _licenses_cache
end
 
--[[
* Ha una licenza di un certo tipo?
*
* @param type FREE|PROPRIETARY|UNKNOWN
* @return true|false
]]
function p._hasALicenseOfType(type)
for _, l in pairs( p._licenses() ) do
l = mWikidata._formatStatement(l, {formatting = 'raw'})
if p._licenseType(l) == type then
return true
end
end
return false
end
 
--[[
* La voce ha almeno una licenza di software libero?
*
* @return true|false
]]
function p._hasAFreeLicense()
return p._hasALicenseOfType(FREE)
end
 
--[[
* La voce ha almeno una licenza di software proprietario?
*
* @return true|false
]]
function p._hasAProprietaryLicense()
return p._hasALicenseOfType(PROPRIETARY)
end
 
--------------------------- Non usate. Perchè? Boh. ----------------------------
 
--[[
* Albero inverso di Modulo:Software/Configurazione
*
* 'cpp' → 'Q2407'
* @return string|nil
]]
local _languageSlugToWikidata = {}
function p._languageSlugToWikidata(slug)
if next(_languageSlugToWikidata) == nil then
for q,l in pairs(conf.wikidataToLanguageSlug) do
_languageSlugToWikidata[l] = q
end
end
return _languageSlugToWikidata[ p._preferredLanguageSlug(slug) ]
end
 
--[[
* Usata solo per debug.
]]
function p.languageSlugToWikidata(frame)
return p._languageSlugToWikidata( getArgs(frame)[1] )
end