lib/infoboxer/media_wiki/traits.rb
# frozen_string_literal: true
module Infoboxer
class MediaWiki
# DSL for defining "traits" for some site.
#
# More docs (and possible refactoring) to follow.
#
# You can look at current
# [English Wikipedia traits](https://github.com/molybdenum-99/infoboxer/blob/master/lib/infoboxer/definitions/en.wikipedia.org.rb)
# definitions in Infoboxer's repo.
class Traits
class << self
# Define set of templates for current site's traits.
#
# See {Templates::Set} for longer (yet insufficient) explanation.
#
# Expected to be used inside Traits definition block.
def templates(&definition)
@templates ||= Templates::Set.new
return @templates unless definition
@templates.define(&definition)
end
# @private
def domain(d)
# NB: explicitly store all domains in base Traits class
Traits.domains.key?(d) and
fail(ArgumentError, "Domain binding redefinition: #{Traits.domains[d]}")
Traits.domains[d] = self
end
# @private
def get(domain, site_info = {})
(Traits.domains[domain] || Traits).new(site_info)
end
# @private
def domains
@domains ||= {}
end
# Define traits for some domain. Use it like:
#
# ```ruby
# MediaWiki::Traits.for 'ru.wikipedia.org' do
# templates do
# template '...' do
# # some template definition
# end
# end
# end
# ```
#
# Again, you can look at current
# [English Wikipedia traits](https://github.com/molybdenum-99/infoboxer/blob/master/lib/infoboxer/definitions/en.wikipedia.org.rb)
# for example implementation.
def for(domain, &block)
Traits.domains[domain]&.instance_eval(&block) ||
Class.new(self, &block).domain(domain)
end
# @private
alias_method :default, :new
end
def initialize(site_info = {})
@site_info = site_info
end
def namespace?(prefix)
known_namespaces.include?(prefix)
end
def interwiki?(prefix)
known_interwikis.key?(prefix)
end
# @private
def file_namespace
@file_namespace ||= ns_aliases('File')
end
# @private
def category_namespace
@category_namespace ||= ns_aliases('Category')
end
# @private
def templates
self.class.templates
end
private
def known_namespaces
@known_namespaces ||=
if @site_info.empty?
STANDARD_NAMESPACES
else
(@site_info['namespaces'].values + @site_info['namespacealiases']).map { |n| n['*'] }
end
end
def known_interwikis
@known_interwikis ||=
if @site_info.empty?
{}
else
@site_info['interwikimap'].map { |iw| [iw['prefix'], iw] }.to_h
end
end
def ns_aliases(base)
return [base] if @site_info.empty?
main = @site_info['namespaces'].values.detect { |n| n['canonical'] == base }
[base, main['*']] +
@site_info['namespacealiases']
.select { |a| a['id'] == main['id'] }.flat_map { |n| n['*'] }
.compact.uniq
end
# See https://www.mediawiki.org/wiki/Help:Namespaces#Standard_namespaces
STANDARD_NAMESPACES = [
'Media', # Direct linking to media files.
'Special', # Special (non-editable) pages.
'', # (Main)
'Talk', # Article discussion.
'User', #
'User talk', #
'Project', # Meta-discussions related to the operation and development of the wiki.
'Project talk', #
'File', # Metadata for images, videos, sound files and other media.
'File talk', #
'MediaWiki', # System messages and other important content.
'MediaWiki talk', #
'Template', # Templates: blocks of text or wikicode that are intended to be transcluded.
'Template talk', #
'Help', # Help files, instructions and "how-to" guides.
'Help talk', #
'Category', # Categories: dynamic lists of other pages.
'Category talk', #
].freeze
end
end
end