wikidata_position_history 1.10.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -0
- data/exe/position-history-for-item +1 -1
- data/lib/query_service.rb +9 -1
- data/lib/sparql/bio_query.rb +16 -0
- data/lib/sparql/mandates_query.rb +29 -3
- data/lib/sparql/position_query.rb +20 -1
- data/lib/wikidata_position_history.rb +12 -0
- data/lib/wikidata_position_history/checks.rb +16 -14
- data/lib/wikidata_position_history/output_row.rb +15 -9
- data/lib/wikidata_position_history/report.rb +24 -63
- data/lib/wikidata_position_history/report/abstract.rb +20 -0
- data/lib/wikidata_position_history/report/constituency.rb +26 -0
- data/lib/wikidata_position_history/report/legislator.rb +12 -0
- data/lib/wikidata_position_history/report/mandate.rb +61 -0
- data/lib/wikidata_position_history/report/position.rb +16 -0
- data/lib/wikidata_position_history/template.rb +7 -4
- data/lib/wikidata_position_history/version.rb +1 -1
- data/wikidata_position_history.gemspec +1 -1
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43d866e3ec1ab0f61a2d8d66d46757dff7ecfd66f4c39bb7a1f90125befb3586
|
4
|
+
data.tar.gz: 9ac67f8d608c4ce7cc746b4e035664cfed07c5501f117d075fb3ab11444a4a69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24824e0ad6207a9a3c8b3e8a547a6eda2dc7e9ee5f6503995dd330c82ecb2bab11a4c4655c3fddd1d8c0235b13bc6d607010901147f305d736e46cdd959c1688
|
7
|
+
data.tar.gz: 257e34dc5e7855720b101d33d2bbf8404f1d4486270667653d1386e077ae4fbdc631b1edba4c7439f3c5f16b4cb80e6932c53d70c136577456d758fe55963b0d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,67 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
# Unreleased
|
4
|
+
|
5
|
+
# [2.3.0] 2020-10-01
|
6
|
+
|
7
|
+
* Edits on Wikidata can now set a botflag if requested, based on the
|
8
|
+
`PHH_BOT` environemnt variable.
|
9
|
+
|
10
|
+
# [2.2.0] 2020-09-18
|
11
|
+
|
12
|
+
## Enhancements
|
13
|
+
|
14
|
+
* Every position came into existence at _some_ point, and so should have
|
15
|
+
a P571 inception date. If that's missing, a warning will now be
|
16
|
+
displayed.
|
17
|
+
|
18
|
+
## Improvements
|
19
|
+
|
20
|
+
* When a position has more than one successor or prdecessor, those will
|
21
|
+
now be displayed as a proper Mediawiki list, rather than one long line
|
22
|
+
of text. As these are in a table cell, this should stop those growing
|
23
|
+
unnecessarily wide, and should generally make everything look a little
|
24
|
+
nicer.
|
25
|
+
|
26
|
+
# [2.1.0] 2020-09-16
|
27
|
+
|
28
|
+
## Enhancements
|
29
|
+
|
30
|
+
* When displaying a list of members for a constituency, also include
|
31
|
+
a 'parliamentary group' (P4100) column, and if there's a
|
32
|
+
'parliamentary term' (P2937) qualifier, use it for the ordinal.
|
33
|
+
|
34
|
+
# [2.0.0] 2020-09-16
|
35
|
+
|
36
|
+
## Interface change
|
37
|
+
|
38
|
+
* `Report#wikitext_with_header` has been removed. This was undocumented,
|
39
|
+
and only used internally, so should not be a breaking change, but if
|
40
|
+
anything *was* using it, that will now break loudly (but, usefully,
|
41
|
+
should also break very early.)
|
42
|
+
|
43
|
+
## Enhancements
|
44
|
+
|
45
|
+
* A {{PositionHolderHistory}} template can now also be added to items
|
46
|
+
representing single-member constituencies, to see the history of
|
47
|
+
representatives for that seat.
|
48
|
+
|
49
|
+
# [1.11.0] 2020-09-14
|
50
|
+
|
51
|
+
## Enhancements
|
52
|
+
|
53
|
+
* Wikidata now has a new {{QB}} template to link to _both_ an Item and
|
54
|
+
its Talk page. As the PositionHolderHistory template for a position
|
55
|
+
often lives on its Talk page, any link to a position item now uses
|
56
|
+
this template, for easier of access to that. (Requested by Tagishsimon:
|
57
|
+
https://twitter.com/Tagishsimon/status/1304363879322079233)
|
58
|
+
|
59
|
+
* The change to how warnings templates work from the last release (i.e.
|
60
|
+
using on-wiki templates, so they can be improved or translated, or used
|
61
|
+
to look for problems via backlinks) definitely seems to have been a good
|
62
|
+
idea, so now the warnings for having an unexpected number of inception
|
63
|
+
or abolition dates have also been adjusted to work the same way.
|
64
|
+
|
3
65
|
# [1.10.0] 2020-09-13
|
4
66
|
|
5
67
|
## Enhancements
|
data/lib/query_service.rb
CHANGED
@@ -49,8 +49,16 @@ module QueryService
|
|
49
49
|
"{{Q|#{id}}}" if id
|
50
50
|
end
|
51
51
|
|
52
|
+
def qblink
|
53
|
+
"{{QB|#{id}}}" if id
|
54
|
+
end
|
55
|
+
|
52
56
|
def qlink_i
|
53
|
-
"''{
|
57
|
+
"''#{qlink}''" if qlink
|
58
|
+
end
|
59
|
+
|
60
|
+
def qblink_i
|
61
|
+
"''#{qblink}''" if qblink
|
54
62
|
end
|
55
63
|
|
56
64
|
private
|
data/lib/sparql/bio_query.rb
CHANGED
@@ -21,6 +21,22 @@ module WikidataPositionHistory
|
|
21
21
|
SPARQL
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
# Biographical data for Members for a Constituency
|
26
|
+
class ConstituencyBioQuery < ItemQuery
|
27
|
+
def raw_sparql
|
28
|
+
<<~SPARQL
|
29
|
+
# constituency-biodata
|
30
|
+
|
31
|
+
SELECT DISTINCT ?item ?image
|
32
|
+
WHERE {
|
33
|
+
?item wdt:P31 wd:Q5 ; p:P39/pq:P768 wd:%s .
|
34
|
+
OPTIONAL { ?item wdt:P18 ?image }
|
35
|
+
}
|
36
|
+
ORDER BY ?item
|
37
|
+
SPARQL
|
38
|
+
end
|
39
|
+
end
|
24
40
|
end
|
25
41
|
|
26
42
|
# Represents a single row returned from the Position query
|
@@ -25,6 +25,33 @@ module WikidataPositionHistory
|
|
25
25
|
SPARQL
|
26
26
|
end
|
27
27
|
end
|
28
|
+
|
29
|
+
# SPARQL for fetching all mandates of a single-member district
|
30
|
+
class ConstituencyMandatesQuery < ItemQuery
|
31
|
+
def raw_sparql
|
32
|
+
<<~SPARQL
|
33
|
+
# constituency-mandates
|
34
|
+
|
35
|
+
SELECT DISTINCT ?ordinal ?item ?start_date ?start_precision ?end_date ?end_precision ?party ?prev ?next ?term
|
36
|
+
WHERE {
|
37
|
+
?item wdt:P31 wd:Q5 ; p:P39 ?posn .
|
38
|
+
?posn pq:P768 wd:%s .
|
39
|
+
FILTER NOT EXISTS { ?posn wikibase:rank wikibase:DeprecatedRank }
|
40
|
+
|
41
|
+
OPTIONAL { ?posn pqv:P580 [ wikibase:timeValue ?start_date; wikibase:timePrecision ?start_precision ] }
|
42
|
+
OPTIONAL { ?posn pqv:P582 [ wikibase:timeValue ?end_date; wikibase:timePrecision ?end_precision ] }
|
43
|
+
OPTIONAL { ?posn pq:P1365 ?prev }
|
44
|
+
OPTIONAL { ?posn pq:P1366 ?next }
|
45
|
+
OPTIONAL { ?posn pq:P4100 ?party }
|
46
|
+
OPTIONAL {
|
47
|
+
?posn pq:P2937 ?term .
|
48
|
+
OPTIONAL { ?term p:P31/pq:P1545 ?ordinal }
|
49
|
+
}
|
50
|
+
}
|
51
|
+
ORDER BY DESC(?start_date) ?item
|
52
|
+
SPARQL
|
53
|
+
end
|
54
|
+
end
|
28
55
|
end
|
29
56
|
|
30
57
|
# Represents a single row returned from the Mandates query
|
@@ -37,9 +64,8 @@ module WikidataPositionHistory
|
|
37
64
|
item_from(:item)
|
38
65
|
end
|
39
66
|
|
40
|
-
|
41
|
-
|
42
|
-
officeholder.qlink
|
67
|
+
def party
|
68
|
+
item_from(:party)
|
43
69
|
end
|
44
70
|
|
45
71
|
# TODO: switch to item_from
|
@@ -11,10 +11,13 @@ module WikidataPositionHistory
|
|
11
11
|
SELECT DISTINCT ?item ?inception ?inception_precision ?abolition ?abolition_precision
|
12
12
|
?replaces ?replacedBy ?derivedReplaces ?derivedReplacedBy
|
13
13
|
?isPosition ?isLegislator
|
14
|
+
?isConstituency ?representative_count ?legislature
|
14
15
|
WHERE {
|
15
16
|
VALUES ?item { wd:%s }
|
16
17
|
BIND(EXISTS { wd:%s wdt:P279+ wd:Q4164871 } as ?isPosition)
|
17
18
|
BIND(EXISTS { wd:%s wdt:P279+ wd:Q4175034 } as ?isLegislator)
|
19
|
+
BIND(EXISTS { wd:%s wdt:P31/wdt:P279+ wd:Q192611 } as ?isConstituency)
|
20
|
+
|
18
21
|
OPTIONAL { ?item p:P571 [ a wikibase:BestRank ;
|
19
22
|
psv:P571 [ wikibase:timeValue ?inception; wikibase:timePrecision ?inception_precision ]
|
20
23
|
] }
|
@@ -25,12 +28,16 @@ module WikidataPositionHistory
|
|
25
28
|
OPTIONAL { ?item wdt:P1366 ?replacedBy }
|
26
29
|
OPTIONAL { ?derivedReplaces wdt:P1366 ?item }
|
27
30
|
OPTIONAL { ?derivedReplacedBy wdt:P1365 ?item }
|
31
|
+
|
32
|
+
OPTIONAL { # if constituency
|
33
|
+
?item p:P1410 [ a wikibase:BestRank ; ps:P1410 ?representative_count ; pq:P194 ?legislature ]
|
34
|
+
}
|
28
35
|
}
|
29
36
|
SPARQL
|
30
37
|
end
|
31
38
|
|
32
39
|
def sparql_args
|
33
|
-
[itemid] *
|
40
|
+
[itemid] * 4
|
34
41
|
end
|
35
42
|
end
|
36
43
|
end
|
@@ -72,5 +79,17 @@ module WikidataPositionHistory
|
|
72
79
|
def legislator?
|
73
80
|
raw(:isLegislator) == 'true'
|
74
81
|
end
|
82
|
+
|
83
|
+
def constituency?
|
84
|
+
raw(:isConstituency) == 'true'
|
85
|
+
end
|
86
|
+
|
87
|
+
def legislature
|
88
|
+
item_from(:legislature)
|
89
|
+
end
|
90
|
+
|
91
|
+
def representative_count
|
92
|
+
raw(:representative_count).to_i
|
93
|
+
end
|
75
94
|
end
|
76
95
|
end
|
@@ -16,6 +16,18 @@ require 'date'
|
|
16
16
|
require 'mediawiki/client'
|
17
17
|
require 'mediawiki/page'
|
18
18
|
|
19
|
+
module MediaWiki
|
20
|
+
# mediawiki-page-replaceable_content does not provide a way to set a
|
21
|
+
# bot flag, so we need to monkey patch it. This should really be
|
22
|
+
# exposed somewhere in its interface.
|
23
|
+
class Client
|
24
|
+
def edit(hash)
|
25
|
+
hash['bot'] = ENV['PHH_BOT'] if ENV.key?('PHH_BOT')
|
26
|
+
wrapped_client.edit(hash)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
19
31
|
module WikidataPositionHistory
|
20
32
|
# Rewrites a Wiki page
|
21
33
|
class PageRewriter
|
@@ -17,11 +17,12 @@ module WikidataPositionHistory
|
|
17
17
|
|
18
18
|
attr_reader :later, :current, :earlier
|
19
19
|
|
20
|
-
|
20
|
+
# TODO: replace these with objects instead of strings
|
21
|
+
def successor_qlink
|
21
22
|
current.next
|
22
23
|
end
|
23
24
|
|
24
|
-
def
|
25
|
+
def predecessor_qlink
|
25
26
|
current.prev
|
26
27
|
end
|
27
28
|
|
@@ -46,7 +47,7 @@ module WikidataPositionHistory
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def possible_explanation
|
49
|
-
"#{current.
|
50
|
+
"#{current.officeholder.qlink} is missing #{missing.map { |field| "{{P|#{field_map[field]}}}" }.join(', ')}"
|
50
51
|
end
|
51
52
|
|
52
53
|
def missing
|
@@ -76,14 +77,14 @@ module WikidataPositionHistory
|
|
76
77
|
|
77
78
|
def expect_prev?
|
78
79
|
return unless earlier
|
79
|
-
return if earlier.
|
80
|
+
return if earlier.officeholder.id == current.officeholder.id # sucessive terms by same person
|
80
81
|
|
81
82
|
!current.acting?
|
82
83
|
end
|
83
84
|
|
84
85
|
def expect_next?
|
85
86
|
return unless later
|
86
|
-
return if later.
|
87
|
+
return if later.officeholder.id == current.officeholder.id # sucessive terms by same person
|
87
88
|
|
88
89
|
!current.acting?
|
89
90
|
end
|
@@ -92,7 +93,7 @@ module WikidataPositionHistory
|
|
92
93
|
# Does the 'replaces' match the previous item in the list?
|
93
94
|
class WrongPredecessor < Check
|
94
95
|
def problem?
|
95
|
-
earlier_holder? && !!
|
96
|
+
earlier_holder? && !!predecessor_qlink && (earlier.officeholder.qlink != predecessor_qlink)
|
96
97
|
end
|
97
98
|
|
98
99
|
def headline
|
@@ -100,14 +101,14 @@ module WikidataPositionHistory
|
|
100
101
|
end
|
101
102
|
|
102
103
|
def possible_explanation
|
103
|
-
"#{current.
|
104
|
+
"#{current.officeholder.qlink} has a {{P|1365}} of #{predecessor_qlink}, but follows #{earlier.officeholder.qlink} here"
|
104
105
|
end
|
105
106
|
end
|
106
107
|
|
107
108
|
# Is there a 'replaces' but no previous item in the list?
|
108
109
|
class MissingPredecessor < Check
|
109
110
|
def problem?
|
110
|
-
|
111
|
+
predecessor_qlink && !earlier_holder?
|
111
112
|
end
|
112
113
|
|
113
114
|
def headline
|
@@ -115,14 +116,14 @@ module WikidataPositionHistory
|
|
115
116
|
end
|
116
117
|
|
117
118
|
def possible_explanation
|
118
|
-
"#{current.
|
119
|
+
"#{current.officeholder.qlink} has a {{P|1365}} of #{predecessor_qlink}, but does not follow anyone here"
|
119
120
|
end
|
120
121
|
end
|
121
122
|
|
122
123
|
# Does the 'replaced by' match the next item in the list?
|
123
124
|
class WrongSuccessor < Check
|
124
125
|
def problem?
|
125
|
-
later_holder? && !!
|
126
|
+
later_holder? && !!successor_qlink && (later.officeholder.qlink != successor_qlink)
|
126
127
|
end
|
127
128
|
|
128
129
|
def headline
|
@@ -130,14 +131,14 @@ module WikidataPositionHistory
|
|
130
131
|
end
|
131
132
|
|
132
133
|
def possible_explanation
|
133
|
-
"#{current.
|
134
|
+
"#{current.officeholder.qlink} has a {{P|1366}} of #{successor_qlink}, but is followed by #{later.officeholder.qlink} here"
|
134
135
|
end
|
135
136
|
end
|
136
137
|
|
137
138
|
# Is there a 'replaced by' but no next item in the list?
|
138
139
|
class MissingSuccessor < Check
|
139
140
|
def problem?
|
140
|
-
|
141
|
+
successor_qlink && !later_holder?
|
141
142
|
end
|
142
143
|
|
143
144
|
def headline
|
@@ -145,7 +146,7 @@ module WikidataPositionHistory
|
|
145
146
|
end
|
146
147
|
|
147
148
|
def possible_explanation
|
148
|
-
"#{current.
|
149
|
+
"#{current.officeholder.qlink} has a {{P|1366}} of #{successor_qlink}, but is not followed by anyone here"
|
149
150
|
end
|
150
151
|
end
|
151
152
|
|
@@ -167,7 +168,8 @@ module WikidataPositionHistory
|
|
167
168
|
end
|
168
169
|
|
169
170
|
def possible_explanation
|
170
|
-
|
171
|
+
format('%s has a {{P|582}} of %s, which %s the {{P|580}} of %s for %s',
|
172
|
+
current.officeholder.qlink, current.end_date, overlap_explanation, later.start_date, later.officeholder.qlink)
|
171
173
|
end
|
172
174
|
|
173
175
|
protected
|
@@ -22,8 +22,12 @@ module WikidataPositionHistory
|
|
22
22
|
"#{ordinal}."
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
current.
|
25
|
+
def party
|
26
|
+
current.party
|
27
|
+
end
|
28
|
+
|
29
|
+
def officeholder
|
30
|
+
current.officeholder
|
27
31
|
end
|
28
32
|
|
29
33
|
def dates
|
@@ -62,8 +66,8 @@ module WikidataPositionHistory
|
|
62
66
|
|
63
67
|
attr_reader :metadata
|
64
68
|
|
65
|
-
def
|
66
|
-
metadata.position.
|
69
|
+
def position_id
|
70
|
+
metadata.position.id
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
@@ -72,10 +76,9 @@ module WikidataPositionHistory
|
|
72
76
|
def warnings
|
73
77
|
count = dates.count
|
74
78
|
return [] if count == 1
|
79
|
+
return [Warning.new('Missing field', "{{PositionHolderHistory/warning_no_inception_date|item=#{position_id}}}")] if count.zero?
|
75
80
|
|
76
|
-
|
77
|
-
|
78
|
-
[Warning.new('Multiple values', "#{qlink} has more than one {{P|571}}")]
|
81
|
+
[Warning.new('Multiple values', "{{PositionHolderHistory/warning_multiple_inception_dates|item=#{position_id}}}")]
|
79
82
|
end
|
80
83
|
|
81
84
|
private
|
@@ -90,7 +93,7 @@ module WikidataPositionHistory
|
|
90
93
|
def warnings
|
91
94
|
return [] unless dates.count > 1
|
92
95
|
|
93
|
-
[Warning.new('Multiple values', "
|
96
|
+
[Warning.new('Multiple values', "{{PositionHolderHistory/warning_multiple_abolition_dates|item=#{position_id}}}")]
|
94
97
|
end
|
95
98
|
|
96
99
|
private
|
@@ -109,7 +112,10 @@ module WikidataPositionHistory
|
|
109
112
|
def position
|
110
113
|
return if implied_list.empty?
|
111
114
|
|
112
|
-
(implied_list.direct.map(&:
|
115
|
+
list = (implied_list.direct.map(&:qblink) + implied_list.indirect_only.map(&:qblink_i))
|
116
|
+
return list.first if list.count == 1
|
117
|
+
|
118
|
+
list.map { |item| "\n* #{item}" }.join
|
113
119
|
end
|
114
120
|
|
115
121
|
def warnings
|
@@ -1,5 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'report/abstract'
|
4
|
+
require_relative 'report/legislator'
|
5
|
+
require_relative 'report/mandate'
|
6
|
+
require_relative 'report/constituency'
|
7
|
+
require_relative 'report/position'
|
8
|
+
|
3
9
|
module WikidataPositionHistory
|
4
10
|
# A list made up of both direct and indirect claims, where we
|
5
11
|
# can tell which came from which, when required
|
@@ -68,6 +74,15 @@ module WikidataPositionHistory
|
|
68
74
|
rows.map(&:legislator?).first
|
69
75
|
end
|
70
76
|
|
77
|
+
def constituency?
|
78
|
+
# this should be the same everywhere
|
79
|
+
rows.map(&:constituency?).first
|
80
|
+
end
|
81
|
+
|
82
|
+
def representative_count
|
83
|
+
rows.map(&:representative_count).max
|
84
|
+
end
|
85
|
+
|
71
86
|
def replaces_combined
|
72
87
|
@replaces_combined ||= ImpliedList.new(uniq_by_id(:replaces), uniq_by_id(:derived_replaces))
|
73
88
|
end
|
@@ -95,84 +110,30 @@ module WikidataPositionHistory
|
|
95
110
|
|
96
111
|
# The entire wikitext generated for this report
|
97
112
|
class Report
|
98
|
-
def initialize(position_id
|
113
|
+
def initialize(position_id)
|
99
114
|
@position_id = position_id
|
100
115
|
@template_class = template_class
|
101
116
|
end
|
102
117
|
|
103
118
|
attr_reader :position_id, :template_class
|
104
119
|
|
105
|
-
def wikitext
|
106
|
-
return legislator_template if metadata.legislator?
|
107
|
-
return no_items_output if mandates.empty?
|
108
|
-
|
109
|
-
template_class.new(template_params).output
|
110
|
-
end
|
111
|
-
|
112
|
-
def header
|
113
|
-
"== {{Q|#{position_id}}} officeholders #{position_dates} =="
|
114
|
-
end
|
115
|
-
|
116
|
-
def position_dates
|
117
|
-
dates = [metadata.inception.date, metadata.abolition.date]
|
118
|
-
return '' if dates.compact.empty?
|
119
|
-
|
120
|
-
format('(%s)', dates.join(' – '))
|
121
|
-
end
|
122
|
-
|
123
|
-
def wikitext_with_header
|
124
|
-
[header, wikitext].join("\n")
|
125
|
-
end
|
126
|
-
|
127
|
-
def template_params
|
128
|
-
{
|
129
|
-
metadata: metadata,
|
130
|
-
table_rows: table_rows,
|
131
|
-
sparql_url: sparql.wdqs_url,
|
132
|
-
}
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
120
|
def metadata
|
138
121
|
@metadata ||= Metadata.new(SPARQL::PositionQuery.new(position_id).results_as(PositionRow))
|
139
122
|
end
|
140
123
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
def biodata_for(officeholder)
|
146
|
-
biodata.select { |bio| bio.person.id == officeholder.id }
|
147
|
-
end
|
148
|
-
|
149
|
-
def padded_mandates
|
150
|
-
[nil, mandates, nil].flatten(1)
|
151
|
-
end
|
152
|
-
|
153
|
-
def sparql
|
154
|
-
@sparql ||= SPARQL::MandatesQuery.new(position_id)
|
155
|
-
end
|
156
|
-
|
157
|
-
def mandates
|
158
|
-
@mandates ||= sparql.results_as(MandateRow)
|
159
|
-
end
|
124
|
+
def report
|
125
|
+
return Report::Legislator.new(metadata) if metadata.legislator?
|
126
|
+
return Report::Constituency.new(metadata) if metadata.constituency?
|
160
127
|
|
161
|
-
|
162
|
-
"\n{{PositionHolderHistory/error_no_holders|id=#{position_id}}}\n"
|
128
|
+
Report::Position.new(metadata)
|
163
129
|
end
|
164
130
|
|
165
|
-
def
|
166
|
-
|
131
|
+
def template_params
|
132
|
+
report.template_params
|
167
133
|
end
|
168
134
|
|
169
|
-
def
|
170
|
-
|
171
|
-
{
|
172
|
-
mandate: OutputRow::Mandate.new(later, current, earlier),
|
173
|
-
bio: biodata_for(current.officeholder),
|
174
|
-
}
|
175
|
-
end
|
135
|
+
def wikitext
|
136
|
+
report.wikitext
|
176
137
|
end
|
177
138
|
end
|
178
139
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WikidataPositionHistory
|
4
|
+
class Report
|
5
|
+
# Abstract base class for Reports
|
6
|
+
class Abstract
|
7
|
+
def initialize(metadata)
|
8
|
+
@metadata = metadata
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
attr_reader :metadata
|
14
|
+
|
15
|
+
def position_id
|
16
|
+
metadata.position.id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WikidataPositionHistory
|
4
|
+
class Report
|
5
|
+
# Report of representatives for a single-member consttuency
|
6
|
+
class Constituency < Mandate
|
7
|
+
def wikitext
|
8
|
+
return multimember_error_template unless metadata.representative_count == 1
|
9
|
+
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def mandates_query
|
14
|
+
SPARQL::ConstituencyMandatesQuery
|
15
|
+
end
|
16
|
+
|
17
|
+
def biodata_query
|
18
|
+
SPARQL::ConstituencyBioQuery
|
19
|
+
end
|
20
|
+
|
21
|
+
def multimember_error_template
|
22
|
+
"\n{{PositionHolderHistory/error_multimember}}\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WikidataPositionHistory
|
4
|
+
class Report
|
5
|
+
# Report for a (presumed multi-member) legislative position
|
6
|
+
class Legislator < Abstract
|
7
|
+
def wikitext
|
8
|
+
"\n{{PositionHolderHistory/error_legislator|id=#{position_id}}}\n"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WikidataPositionHistory
|
4
|
+
class Report
|
5
|
+
# base report where each row is one person holding an office for a period
|
6
|
+
class Mandate < Abstract
|
7
|
+
def wikitext
|
8
|
+
return no_items_output if mandates.empty?
|
9
|
+
|
10
|
+
ReportTemplate.new(template_params).output
|
11
|
+
end
|
12
|
+
|
13
|
+
def template_params
|
14
|
+
{
|
15
|
+
metadata: metadata,
|
16
|
+
table_rows: table_rows,
|
17
|
+
sparql_url: sparql.wdqs_url,
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def biodata
|
24
|
+
@biodata ||= biodata_sparql.results_as(BioRow)
|
25
|
+
end
|
26
|
+
|
27
|
+
def biodata_for(officeholder)
|
28
|
+
biodata.select { |bio| bio.person.id == officeholder.id }
|
29
|
+
end
|
30
|
+
|
31
|
+
def padded_mandates
|
32
|
+
[nil, mandates, nil].flatten(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
def sparql
|
36
|
+
@sparql ||= mandates_query.new(position_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def biodata_sparql
|
40
|
+
biodata_query.new(position_id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def mandates
|
44
|
+
@mandates ||= sparql.results_as(MandateRow)
|
45
|
+
end
|
46
|
+
|
47
|
+
def no_items_output
|
48
|
+
"\n{{PositionHolderHistory/error_no_holders|id=#{position_id}}}\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
def table_rows
|
52
|
+
padded_mandates.each_cons(3).map do |later, current, earlier|
|
53
|
+
{
|
54
|
+
mandate: OutputRow::Mandate.new(later, current, earlier),
|
55
|
+
bio: biodata_for(current.officeholder),
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WikidataPositionHistory
|
4
|
+
class Report
|
5
|
+
# The default single-person-at-a-time position
|
6
|
+
class Position < Mandate
|
7
|
+
def mandates_query
|
8
|
+
SPARQL::MandatesQuery
|
9
|
+
end
|
10
|
+
|
11
|
+
def biodata_query
|
12
|
+
SPARQL::BioQuery
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -33,8 +33,8 @@ module WikidataPositionHistory
|
|
33
33
|
<% end -%>
|
34
34
|
<% if metadata.successor.position -%>
|
35
35
|
|-
|
36
|
-
| colspan="2" style="border: none; background: #fff; font-size: 1.15em; text-align: right;" | '''Replaced by''':
|
37
|
-
| style=" border: none; background: #fff; text-align: left;" | <%= metadata.successor.position %>
|
36
|
+
| colspan="2" style="border: none; background: #fff; font-size: 1.15em; vertical-align: baseline; text-align: right;" | '''Replaced by''':
|
37
|
+
| style=" border: none; background: #fff; vertical-align: baseline; text-align: left;" | <%= metadata.successor.position %>
|
38
38
|
| style=" border: none; background: #fff; text-align: left;" | \
|
39
39
|
<% metadata.successor.warnings.each do |warning| -%>
|
40
40
|
<span style="display: block">[[File:Pictogram voting comment.svg|15px|link=]] <span style="color: #d33; font-weight: bold; vertical-align: middle;"><%= warning.headline %></span> <ref><%= warning.explanation %></ref></span>\
|
@@ -49,7 +49,10 @@ module WikidataPositionHistory
|
|
49
49
|
|-
|
50
50
|
| style="padding:0.5em 2em" | <%= mandate.ordinal_string %>
|
51
51
|
| style="padding:0.5em 2em" | <%= bio.map(&:image_link).first %>
|
52
|
-
| style="padding:0.5em 2em" | <span style="font-size: <%= mandate.acting? ? '1.25em; font-style: italic;' : '1.5em' %>; display: block;"><%= mandate.
|
52
|
+
| style="padding:0.5em 2em" | <span style="font-size: <%= mandate.acting? ? '1.25em; font-style: italic;' : '1.5em' %>; display: block;"><%= mandate.officeholder.qlink %></span> <%= mandate.dates %>
|
53
|
+
<% if metadata.constituency? -%>
|
54
|
+
| style="padding:0.5em 1em" | <% if mandate.party %><%= mandate.party.qlink %><% end %>
|
55
|
+
<% end -%>
|
53
56
|
| style="padding:0.5em 2em 0.5em 1em; border: none; background: #fff; text-align: left;" | \
|
54
57
|
<% mandate.warnings.each do |warning| -%>
|
55
58
|
<span style="display: block">[[File:Pictogram voting comment.svg|15px|link=]] <span style="color: #d33; font-weight: bold; vertical-align: middle;"><%= warning.headline %></span> <ref><%= warning.explanation %></ref></span>\
|
@@ -60,7 +63,7 @@ module WikidataPositionHistory
|
|
60
63
|
| colspan="3" style="padding:0.5em; border: none; background: #fff"> |
|
61
64
|
| colspan="1" style="padding:0.5em; border: none; background: #fff"> |
|
62
65
|
<% end -%>
|
63
|
-
<% if metadata.inception.date -%>
|
66
|
+
<% if metadata.inception.date || metadata.inception.warnings.any? -%>
|
64
67
|
|-
|
65
68
|
| colspan="2" style="border: none; background: #fff; font-size: 1.15em; text-align: right;" | '''Position created''':
|
66
69
|
| style="border: none; background: #fff; text-align: left;" | <%= metadata.inception.date %>
|
@@ -36,5 +36,5 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency 'rubocop-performance', '~> 1.8.0'
|
37
37
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.43.2'
|
38
38
|
spec.add_development_dependency 'warning', '~> 1.1'
|
39
|
-
spec.add_development_dependency 'webmock', '~> 3.
|
39
|
+
spec.add_development_dependency 'webmock', '~> 3.9.1'
|
40
40
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wikidata_position_history
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Bowden
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-10-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mediawiki-replaceable-content
|
@@ -171,14 +171,14 @@ dependencies:
|
|
171
171
|
requirements:
|
172
172
|
- - "~>"
|
173
173
|
- !ruby/object:Gem::Version
|
174
|
-
version: 3.
|
174
|
+
version: 3.9.1
|
175
175
|
type: :development
|
176
176
|
prerelease: false
|
177
177
|
version_requirements: !ruby/object:Gem::Requirement
|
178
178
|
requirements:
|
179
179
|
- - "~>"
|
180
180
|
- !ruby/object:Gem::Version
|
181
|
-
version: 3.
|
181
|
+
version: 3.9.1
|
182
182
|
description:
|
183
183
|
email:
|
184
184
|
- tony@tmtm.com
|
@@ -212,6 +212,11 @@ files:
|
|
212
212
|
- lib/wikidata_position_history/checks.rb
|
213
213
|
- lib/wikidata_position_history/output_row.rb
|
214
214
|
- lib/wikidata_position_history/report.rb
|
215
|
+
- lib/wikidata_position_history/report/abstract.rb
|
216
|
+
- lib/wikidata_position_history/report/constituency.rb
|
217
|
+
- lib/wikidata_position_history/report/legislator.rb
|
218
|
+
- lib/wikidata_position_history/report/mandate.rb
|
219
|
+
- lib/wikidata_position_history/report/position.rb
|
215
220
|
- lib/wikidata_position_history/template.rb
|
216
221
|
- lib/wikidata_position_history/version.rb
|
217
222
|
- wikidata_position_history.gemspec
|