wikidata_position_history 1.4.3 → 1.9.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 +81 -1
- data/lib/query_service.rb +17 -6
- data/lib/sparql/{bio_data.rb → bio_query.rb} +2 -2
- data/lib/sparql/item_query.rb +5 -1
- data/lib/sparql/{mandates.rb → mandates_query.rb} +3 -3
- data/lib/sparql/position_query.rb +106 -0
- data/lib/wikidata_position_history.rb +3 -3
- data/lib/wikidata_position_history/checks.rb +34 -4
- data/lib/wikidata_position_history/report.rb +106 -17
- data/lib/wikidata_position_history/template.rb +50 -4
- data/lib/wikidata_position_history/version.rb +1 -1
- metadata +5 -5
- data/lib/sparql/position_data.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a2bc5a49d34a368363b7e92ec9e1b0d08b141d96babd15eccf2913d99e9b7b0
|
4
|
+
data.tar.gz: 87594145f811917672fd4772722e086907d508479d73b43bfb21a0aac24e5d27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6eb361e602c3a34c97bd8b584b4029135d9bb8e14c1f99b2ed513ce049f8df780c9b09ac31941c31a7ebea544d0a6cc0065cb2210bc4af4448de66cfb40800c0
|
7
|
+
data.tar.gz: 1b07fb333e1f13d25985420ec6700f2b0dc81dc98a5c4a762713bcf8426c532b48e28f6d80646d7c5ea85692f63e921748a603708e4d9e7286f254bc8c665e21
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,86 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
# [1.
|
3
|
+
# [1.9.0] 2020-09-11
|
4
|
+
|
5
|
+
## Enhancements
|
6
|
+
|
7
|
+
* If a position has any successor or predecessor offices (in "replaces"
|
8
|
+
(P1365) or "replaced by" (P1366)) the report will now display those.
|
9
|
+
|
10
|
+
# [1.8.0] 2020-09-09
|
11
|
+
|
12
|
+
## Enhancements
|
13
|
+
|
14
|
+
* If the very latest person we know of having held this position also
|
15
|
+
has a 'replaced by' qualifier, that’s a sign that the successor should
|
16
|
+
really also have a suitable P39, and actually appear here too. So we
|
17
|
+
want to display a warning in such cases. Likewise if the earliest person
|
18
|
+
we know if also has a 'replaces'
|
19
|
+
|
20
|
+
* This report is meant to be used with positions that are held by only a
|
21
|
+
single person at a time. Using it to produce a report of everyone who
|
22
|
+
has been, say, a Member of the UK Parliament, is the sort of thing that
|
23
|
+
will cause all manner of havoc, as it will try to display tens of
|
24
|
+
thousands of people, all of whom have overlaps with other members etc.
|
25
|
+
So we now sanity-check first of all that the position isn't legislative,
|
26
|
+
and produce a nice "Don’t do that!" message in such cases.
|
27
|
+
|
28
|
+
* It seems that the recent ability to handle dates that are only know at
|
29
|
+
decade-level precision isn’t actually enough, as we have some that we
|
30
|
+
only know at century-level precision! (For example, that the position of
|
31
|
+
Lord Chancellor of Ireland was created some time in the 12th Century.)
|
32
|
+
Such dates will now appear in a nicer format.
|
33
|
+
|
34
|
+
* Sometimes updating the table looks like something has changed, but
|
35
|
+
really the only difference is that a few of people who have no dates
|
36
|
+
are shuffled around a bit in the list. This is because we previously
|
37
|
+
only sorted by date order, so people with no dates were effectively in a
|
38
|
+
random order. Now we sort those people by ID too, which should minimise
|
39
|
+
the number of times an update will appear in your watchlist, only to
|
40
|
+
discover nothing significant actually happened.
|
41
|
+
|
42
|
+
# [1.7.0] 2020-09-08
|
43
|
+
|
44
|
+
## Enchancements
|
45
|
+
|
46
|
+
* Yesterday’s future, when we said we’d do something a little better
|
47
|
+
with positions that have multiple inception or abolition dates, has
|
48
|
+
arrived. Now we display all of them (with a warning), rather than just
|
49
|
+
picking one semi-randomly.
|
50
|
+
|
51
|
+
## Improvements
|
52
|
+
|
53
|
+
* A query like https://w.wiki/bVz is taking about 6 seconds to run.
|
54
|
+
Changing that to https://w.wiki/bW3 drops that to about half a second.
|
55
|
+
If you were to guess that the first has now been replaced by the
|
56
|
+
second, you’d be entirely correct.
|
57
|
+
|
58
|
+
# [1.6.0] 2020-09-07
|
59
|
+
|
60
|
+
## Enhancements
|
61
|
+
|
62
|
+
* If a position has an inception date and/or abolition date, those will
|
63
|
+
now also be displayed. (If a position has more than one of either of
|
64
|
+
those — which really shouldn’t happen, but sometimes does — then the
|
65
|
+
behaviour may not be particularly sensible. Later evolutions of this
|
66
|
+
feature will hopefully handle that better.)
|
67
|
+
|
68
|
+
## Fixes
|
69
|
+
|
70
|
+
* Previously, any warnings would be displayed at the bottom of the page,
|
71
|
+
which was fine if this table was the only thing on the page, but would
|
72
|
+
be slightly odd if there was other discussion after it. Now the
|
73
|
+
footnotes are explicitly displayed immediately after the table.
|
74
|
+
|
75
|
+
# [1.5.0] 2020-09-06
|
76
|
+
|
77
|
+
## Enhancements
|
78
|
+
|
79
|
+
* When showing the results for a position from long long ago (such as
|
80
|
+
the High Kings of Ireland), display the dates as "862 – 879" not as
|
81
|
+
"0862 – 0879"
|
82
|
+
* If we only know that someone took (or left) office sometime in a given
|
83
|
+
decade (i.e. at date precision 8), display that as (say) "1930s"
|
4
84
|
|
5
85
|
## Fixes
|
6
86
|
|
data/lib/query_service.rb
CHANGED
@@ -54,6 +54,8 @@ module QueryService
|
|
54
54
|
class WikidataDate
|
55
55
|
include Comparable
|
56
56
|
|
57
|
+
DATELEN = { '11' => 10, '10' => 7, '9' => 4, '8' => 4, '7' => 2 }.freeze
|
58
|
+
|
57
59
|
def initialize(str, precision)
|
58
60
|
@str = str
|
59
61
|
@raw_precision = precision.to_s
|
@@ -66,12 +68,7 @@ module QueryService
|
|
66
68
|
end
|
67
69
|
|
68
70
|
def to_s
|
69
|
-
|
70
|
-
return str[0..6] if precision == '10'
|
71
|
-
return str[0..3] if precision == '9'
|
72
|
-
|
73
|
-
warn "Cannot handle precision #{precision} for #{str}"
|
74
|
-
str
|
71
|
+
precisioned_string.delete_prefix('0')
|
75
72
|
end
|
76
73
|
|
77
74
|
def empty?
|
@@ -99,5 +96,19 @@ module QueryService
|
|
99
96
|
def parts
|
100
97
|
to_s.split('-')
|
101
98
|
end
|
99
|
+
|
100
|
+
def truncated_string
|
101
|
+
return str[0...DATELEN[precision]] if DATELEN.key?(precision)
|
102
|
+
|
103
|
+
warn "Cannot handle precision #{precision} for #{str}"
|
104
|
+
str
|
105
|
+
end
|
106
|
+
|
107
|
+
def precisioned_string
|
108
|
+
return "#{truncated_string}. century" if precision == '7'
|
109
|
+
return "#{truncated_string}s" if precision == '8'
|
110
|
+
|
111
|
+
truncated_string
|
112
|
+
end
|
102
113
|
end
|
103
114
|
end
|
@@ -7,7 +7,7 @@ module WikidataPositionHistory
|
|
7
7
|
# This is distinct from the mandate query itself to avoid complex
|
8
8
|
# GROUP BY scenarios where people have multiple values for
|
9
9
|
# biographical properties.
|
10
|
-
class
|
10
|
+
class BioQuery < ItemQuery
|
11
11
|
def raw_sparql
|
12
12
|
<<~SPARQL
|
13
13
|
# holder-biodata
|
@@ -24,7 +24,7 @@ module WikidataPositionHistory
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Represents a single row returned from the Position query
|
27
|
-
class
|
27
|
+
class BioRow
|
28
28
|
def initialize(row)
|
29
29
|
@row = row
|
30
30
|
end
|
data/lib/sparql/item_query.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module WikidataPositionHistory
|
4
4
|
module SPARQL
|
5
5
|
# SPARQL for fetching all officeholdings of a position
|
6
|
-
class
|
6
|
+
class MandatesQuery < ItemQuery
|
7
7
|
def raw_sparql
|
8
8
|
<<~SPARQL
|
9
9
|
# position-mandates
|
@@ -21,14 +21,14 @@ module WikidataPositionHistory
|
|
21
21
|
OPTIONAL { ?posn pq:P1545 ?ordinal }
|
22
22
|
OPTIONAL { ?posn pq:P5102 ?nature }
|
23
23
|
}
|
24
|
-
ORDER BY DESC(?start_date)
|
24
|
+
ORDER BY DESC(?start_date) ?item
|
25
25
|
SPARQL
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
# Represents a single row returned from the Mandates query
|
31
|
-
class
|
31
|
+
class MandateRow
|
32
32
|
def initialize(row)
|
33
33
|
@row = row
|
34
34
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WikidataPositionHistory
|
4
|
+
module SPARQL
|
5
|
+
# SPARQL for fetching metadata about a position
|
6
|
+
class PositionQuery < ItemQuery
|
7
|
+
def raw_sparql
|
8
|
+
<<~SPARQL
|
9
|
+
# position-metadata
|
10
|
+
|
11
|
+
SELECT DISTINCT ?item ?inception ?inception_precision ?abolition ?abolition_precision
|
12
|
+
?replaces ?replacedBy
|
13
|
+
?isPosition ?isLegislator
|
14
|
+
WHERE {
|
15
|
+
VALUES ?item { wd:%s }
|
16
|
+
BIND(EXISTS { wd:%s wdt:P279+ wd:Q4164871 } as ?isPosition)
|
17
|
+
BIND(EXISTS { wd:%s wdt:P279+ wd:Q4175034 } as ?isLegislator)
|
18
|
+
OPTIONAL { ?item p:P571 [ a wikibase:BestRank ;
|
19
|
+
psv:P571 [ wikibase:timeValue ?inception; wikibase:timePrecision ?inception_precision ]
|
20
|
+
] }
|
21
|
+
OPTIONAL { ?item p:P576 [ a wikibase:BestRank ;
|
22
|
+
psv:P576 [ wikibase:timeValue ?abolition; wikibase:timePrecision ?abolition_precision ]
|
23
|
+
] }
|
24
|
+
OPTIONAL { ?item wdt:P1365 ?replaces }
|
25
|
+
OPTIONAL { ?item wdt:P1366 ?replacedBy }
|
26
|
+
}
|
27
|
+
SPARQL
|
28
|
+
end
|
29
|
+
|
30
|
+
def sparql_args
|
31
|
+
[itemid] * 3
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Represents a single row returned from the Position query
|
37
|
+
class PositionRow
|
38
|
+
def initialize(row)
|
39
|
+
@row = row
|
40
|
+
end
|
41
|
+
|
42
|
+
def item
|
43
|
+
QueryService::WikidataItem.new(row.dig(:item, :value))
|
44
|
+
end
|
45
|
+
|
46
|
+
def inception_date
|
47
|
+
return if inception_date_raw.empty?
|
48
|
+
|
49
|
+
QueryService::WikidataDate.new(inception_date_raw, inception_date_precision)
|
50
|
+
end
|
51
|
+
|
52
|
+
def abolition_date
|
53
|
+
return if abolition_date_raw.empty?
|
54
|
+
|
55
|
+
QueryService::WikidataDate.new(abolition_date_raw, abolition_date_precision)
|
56
|
+
end
|
57
|
+
|
58
|
+
def replaces
|
59
|
+
return if replaces_raw.to_s.empty?
|
60
|
+
|
61
|
+
QueryService::WikidataItem.new(replaces_raw)
|
62
|
+
end
|
63
|
+
|
64
|
+
def replaced_by
|
65
|
+
return if replaced_by_raw.to_s.empty?
|
66
|
+
|
67
|
+
QueryService::WikidataItem.new(replaced_by_raw)
|
68
|
+
end
|
69
|
+
|
70
|
+
def position?
|
71
|
+
row.dig(:isPosition, :value) == 'true'
|
72
|
+
end
|
73
|
+
|
74
|
+
def legislator?
|
75
|
+
row.dig(:isLegislator, :value) == 'true'
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
attr_reader :row
|
81
|
+
|
82
|
+
def replaces_raw
|
83
|
+
row.dig(:replaces, :value)
|
84
|
+
end
|
85
|
+
|
86
|
+
def replaced_by_raw
|
87
|
+
row.dig(:replacedBy, :value)
|
88
|
+
end
|
89
|
+
|
90
|
+
def inception_date_raw
|
91
|
+
row.dig(:inception, :value).to_s[0..9]
|
92
|
+
end
|
93
|
+
|
94
|
+
def abolition_date_raw
|
95
|
+
row.dig(:abolition, :value).to_s[0..9]
|
96
|
+
end
|
97
|
+
|
98
|
+
def inception_date_precision
|
99
|
+
row.dig(:inception_precision, :value)
|
100
|
+
end
|
101
|
+
|
102
|
+
def abolition_date_precision
|
103
|
+
row.dig(:abolition_precision, :value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'query_service'
|
4
4
|
require 'sparql/item_query'
|
5
|
-
require 'sparql/
|
6
|
-
require 'sparql/
|
7
|
-
require 'sparql/
|
5
|
+
require 'sparql/position_query'
|
6
|
+
require 'sparql/bio_query'
|
7
|
+
require 'sparql/mandates_query'
|
8
8
|
require 'wikidata_position_history/checks'
|
9
9
|
require 'wikidata_position_history/template'
|
10
10
|
require 'wikidata_position_history/report'
|
@@ -25,11 +25,11 @@ module WikidataPositionHistory
|
|
25
25
|
current.prev
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
28
|
+
def later_holder?
|
29
29
|
!!later
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def earlier_holder?
|
33
33
|
!!earlier
|
34
34
|
end
|
35
35
|
end
|
@@ -92,7 +92,7 @@ module WikidataPositionHistory
|
|
92
92
|
# Does the 'replaces' match the previous item in the list?
|
93
93
|
class WrongPredecessor < Check
|
94
94
|
def problem?
|
95
|
-
|
95
|
+
earlier_holder? && !!predecessor && (earlier.item != predecessor)
|
96
96
|
end
|
97
97
|
|
98
98
|
def headline
|
@@ -104,10 +104,25 @@ module WikidataPositionHistory
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
# Is there a 'replaces' but no previous item in the list?
|
108
|
+
class MissingPredecessor < Check
|
109
|
+
def problem?
|
110
|
+
predecessor && !earlier_holder?
|
111
|
+
end
|
112
|
+
|
113
|
+
def headline
|
114
|
+
'Inconsistent predecessor'
|
115
|
+
end
|
116
|
+
|
117
|
+
def possible_explanation
|
118
|
+
"#{current.item} has a {{P|1365}} of #{predecessor}, but does not follow anyone here"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
107
122
|
# Does the 'replaced by' match the next item in the list?
|
108
123
|
class WrongSuccessor < Check
|
109
124
|
def problem?
|
110
|
-
|
125
|
+
later_holder? && !!successor && (later.item != successor)
|
111
126
|
end
|
112
127
|
|
113
128
|
def headline
|
@@ -119,6 +134,21 @@ module WikidataPositionHistory
|
|
119
134
|
end
|
120
135
|
end
|
121
136
|
|
137
|
+
# Is there a 'replaced by' but no next item in the list?
|
138
|
+
class MissingSuccessor < Check
|
139
|
+
def problem?
|
140
|
+
successor && !later_holder?
|
141
|
+
end
|
142
|
+
|
143
|
+
def headline
|
144
|
+
'Inconsistent successor'
|
145
|
+
end
|
146
|
+
|
147
|
+
def possible_explanation
|
148
|
+
"#{current.item} has a {{P|1366}} of #{successor}, but is not followed by anyone here"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
122
152
|
# Does the end date overlap with the successor's start date?
|
123
153
|
class Overlap < Check
|
124
154
|
def problem?
|
@@ -3,7 +3,9 @@
|
|
3
3
|
module WikidataPositionHistory
|
4
4
|
# Date for a single mandate row, to be passed to the report template
|
5
5
|
class MandateData
|
6
|
-
CHECKS = [Check::MissingFields, Check::
|
6
|
+
CHECKS = [Check::MissingFields, Check::Overlap,
|
7
|
+
Check::WrongPredecessor, Check::MissingPredecessor,
|
8
|
+
Check::WrongSuccessor, Check::MissingSuccessor].freeze
|
7
9
|
|
8
10
|
def initialize(later, current, earlier)
|
9
11
|
@later = later
|
@@ -40,6 +42,93 @@ module WikidataPositionHistory
|
|
40
42
|
attr_reader :later, :current, :earlier
|
41
43
|
end
|
42
44
|
|
45
|
+
# Data about the position itself, to be passed to the report template
|
46
|
+
class Metadata
|
47
|
+
# simplified version of a WikidataPositionHistory::Check
|
48
|
+
Warning = Struct.new(:headline, :explanation)
|
49
|
+
|
50
|
+
def initialize(rows)
|
51
|
+
@rows = rows
|
52
|
+
end
|
53
|
+
|
54
|
+
def item
|
55
|
+
rows.map(&:item).first
|
56
|
+
end
|
57
|
+
|
58
|
+
def replaces
|
59
|
+
return if replaces_list.empty?
|
60
|
+
|
61
|
+
replaces_list.map(&:qlink).join(', ')
|
62
|
+
end
|
63
|
+
|
64
|
+
def replaced_by
|
65
|
+
return if replaced_by_list.empty?
|
66
|
+
|
67
|
+
replaced_by_list.map(&:qlink).join(', ')
|
68
|
+
end
|
69
|
+
|
70
|
+
def inception_date
|
71
|
+
return if inception_dates.empty?
|
72
|
+
|
73
|
+
inception_dates.join(' / ')
|
74
|
+
end
|
75
|
+
|
76
|
+
def inception_warning
|
77
|
+
count = inception_dates.count
|
78
|
+
|
79
|
+
return if count == 1
|
80
|
+
return Warning.new('Missing field', "#{item_qlink} is missing {{P|571}}") if count.zero?
|
81
|
+
|
82
|
+
Warning.new('Multiple values', "#{item_qlink} has more than one {{P|571}}")
|
83
|
+
end
|
84
|
+
|
85
|
+
def abolition_date
|
86
|
+
return if abolition_dates.empty?
|
87
|
+
|
88
|
+
abolition_dates.join(' / ')
|
89
|
+
end
|
90
|
+
|
91
|
+
def abolition_warning
|
92
|
+
return unless abolition_dates.count > 1
|
93
|
+
|
94
|
+
Warning.new('Multiple values', "#{item_qlink} has more than one {{P|576}}")
|
95
|
+
end
|
96
|
+
|
97
|
+
def position?
|
98
|
+
# this should be the same everywhere
|
99
|
+
rows.map(&:position?).first
|
100
|
+
end
|
101
|
+
|
102
|
+
def legislator?
|
103
|
+
# this should be the same everywhere
|
104
|
+
rows.map(&:legislator?).first
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
attr_reader :rows
|
110
|
+
|
111
|
+
def replaces_list
|
112
|
+
rows.map(&:replaces).compact.uniq(&:id).sort_by(&:id)
|
113
|
+
end
|
114
|
+
|
115
|
+
def replaced_by_list
|
116
|
+
rows.map(&:replaced_by).compact.uniq(&:id).sort_by(&:id)
|
117
|
+
end
|
118
|
+
|
119
|
+
def inception_dates
|
120
|
+
rows.map(&:inception_date).compact.uniq(&:to_s).sort
|
121
|
+
end
|
122
|
+
|
123
|
+
def abolition_dates
|
124
|
+
rows.map(&:abolition_date).compact.uniq(&:to_s).sort
|
125
|
+
end
|
126
|
+
|
127
|
+
def item_qlink
|
128
|
+
item.qlink
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
43
132
|
# The entire wikitext generated for this report
|
44
133
|
class Report
|
45
134
|
def initialize(position_id, template_class = ReportTemplate)
|
@@ -50,9 +139,10 @@ module WikidataPositionHistory
|
|
50
139
|
attr_reader :position_id, :template_class
|
51
140
|
|
52
141
|
def wikitext
|
142
|
+
return legislator_template if metadata.legislator?
|
53
143
|
return no_items_output if mandates.empty?
|
54
144
|
|
55
|
-
output
|
145
|
+
template_class.new(template_params).output
|
56
146
|
end
|
57
147
|
|
58
148
|
def header
|
@@ -70,16 +160,22 @@ module WikidataPositionHistory
|
|
70
160
|
[header, wikitext].join("\n")
|
71
161
|
end
|
72
162
|
|
163
|
+
def template_params
|
164
|
+
{
|
165
|
+
metadata: metadata,
|
166
|
+
table_rows: table_rows,
|
167
|
+
sparql_url: sparql.wdqs_url,
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
73
171
|
private
|
74
172
|
|
75
173
|
def metadata
|
76
|
-
|
77
|
-
# multiple dates
|
78
|
-
@metadata ||= SPARQL::PositionData.new(position_id).results_as(PositionData).first
|
174
|
+
@metadata ||= Metadata.new(SPARQL::PositionQuery.new(position_id).results_as(PositionRow))
|
79
175
|
end
|
80
176
|
|
81
177
|
def biodata
|
82
|
-
@biodata ||= SPARQL::
|
178
|
+
@biodata ||= SPARQL::BioQuery.new(position_id).results_as(BioRow)
|
83
179
|
end
|
84
180
|
|
85
181
|
def biodata_for(officeholder)
|
@@ -91,26 +187,19 @@ module WikidataPositionHistory
|
|
91
187
|
end
|
92
188
|
|
93
189
|
def sparql
|
94
|
-
@sparql ||= SPARQL::
|
190
|
+
@sparql ||= SPARQL::MandatesQuery.new(position_id)
|
95
191
|
end
|
96
192
|
|
97
193
|
def mandates
|
98
|
-
@mandates ||= sparql.results_as(
|
194
|
+
@mandates ||= sparql.results_as(MandateRow)
|
99
195
|
end
|
100
196
|
|
101
197
|
def no_items_output
|
102
198
|
"\n{{PositionHolderHistory/error_no_holders|id=#{position_id}}}\n"
|
103
199
|
end
|
104
200
|
|
105
|
-
def
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
def template_params
|
110
|
-
{
|
111
|
-
table_rows: table_rows,
|
112
|
-
sparql_url: sparql.wdqs_url,
|
113
|
-
}
|
201
|
+
def legislator_template
|
202
|
+
"\n{{PositionHolderHistory/error_legislator|id=#{position_id}}}\n"
|
114
203
|
end
|
115
204
|
|
116
205
|
def table_rows
|
@@ -16,22 +16,68 @@ module WikidataPositionHistory
|
|
16
16
|
attr_reader :data
|
17
17
|
|
18
18
|
def template
|
19
|
-
@template ||= ERB.new(template_text)
|
19
|
+
@template ||= ERB.new(template_text, nil, '-')
|
20
20
|
end
|
21
21
|
|
22
22
|
def template_text
|
23
23
|
<<~ERB
|
24
24
|
{| class="wikitable" style="text-align: center; border: none;"
|
25
|
-
<%
|
25
|
+
<% if metadata.abolition_date -%>
|
26
|
+
|-
|
27
|
+
| colspan="2" style="border: none; background: #fff; font-size: 1.15em; text-align: right;" | '''Position abolished''':
|
28
|
+
| style="border: none; background: #fff; text-align: left;" | <%= metadata.abolition_date %>
|
29
|
+
| style="border: none; background: #fff; text-align: left;" | \
|
30
|
+
<% [metadata.abolition_warning].compact.each do |warning| -%>
|
31
|
+
<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>\
|
32
|
+
<% end %>
|
33
|
+
<% end -%>
|
34
|
+
<% if metadata.replaced_by -%>
|
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.replaced_by %>
|
38
|
+
| style=" border: none; background: #fff; text-align: left;" |
|
39
|
+
<% end -%>
|
40
|
+
<% if metadata.replaced_by || metadata.abolition_date -%>
|
41
|
+
|-
|
42
|
+
| colspan="3" style="padding:0.5em; border: none; background: #fff"> |
|
43
|
+
| colspan="1" style="padding:0.5em; border: none; background: #fff"> |
|
44
|
+
<% end -%>
|
45
|
+
<% table_rows.map(&:values).each do |mandate, bio| -%>
|
46
|
+
|-
|
26
47
|
| style="padding:0.5em 2em" | <%= mandate.ordinal_string %>
|
27
48
|
| style="padding:0.5em 2em" | <%= bio.map(&:image_link).first %>
|
28
49
|
| style="padding:0.5em 2em" | <span style="font-size: <%= mandate.acting? ? '1.25em; font-style: italic;' : '1.5em' %>; display: block;"><%= mandate.person %></span> <%= mandate.dates %>
|
29
|
-
| style="padding:0.5em 2em 0.5em 1em; border: none; background: #fff; text-align: left;" |
|
30
|
-
<%
|
50
|
+
| style="padding:0.5em 2em 0.5em 1em; border: none; background: #fff; text-align: left;" | \
|
51
|
+
<% mandate.warnings.each do |warning| -%>
|
52
|
+
<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>\
|
53
|
+
<% end %>
|
54
|
+
<% end -%>
|
55
|
+
<% if metadata.replaced_by || metadata.abolition_date -%>
|
56
|
+
|-
|
57
|
+
| colspan="3" style="padding:0.5em; border: none; background: #fff"> |
|
58
|
+
| colspan="1" style="padding:0.5em; border: none; background: #fff"> |
|
59
|
+
<% end -%>
|
60
|
+
<% if metadata.inception_date -%>
|
61
|
+
|-
|
62
|
+
| colspan="2" style="border: none; background: #fff; font-size: 1.15em; text-align: right;" | '''Position created''':
|
63
|
+
| style="border: none; background: #fff; text-align: left;" | <%= metadata.inception_date %>
|
64
|
+
| style="padding:0.5em 2em 0.5em 1em; border: none; background: #fff; text-align: left;" | \
|
65
|
+
<% [metadata.inception_warning].compact.each do |warning| -%>
|
66
|
+
<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>\
|
67
|
+
<% end %>
|
68
|
+
<% end -%>
|
69
|
+
<% if metadata.replaces -%>
|
70
|
+
|-
|
71
|
+
| colspan="2" style=" border: none; background: #fff; font-size: 1.15em; text-align: right;" | '''Replaces''':
|
72
|
+
| style="border: none; background: #fff; text-align: left;" | <%= metadata.replaces %>
|
73
|
+
| style="padding:0.5em 2em 0.5em 1em; border: none; background: #fff; text-align: left;" |
|
74
|
+
<% end -%>
|
75
|
+
|}
|
31
76
|
|
32
77
|
<div style="margin-bottom:5px; border-bottom:3px solid #2f74d0; font-size:8pt">
|
33
78
|
<div style="float:right">[<%= sparql_url %> WDQS]</div>
|
34
79
|
</div>
|
80
|
+
{{reflist}}
|
35
81
|
ERB
|
36
82
|
end
|
37
83
|
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: 1.
|
4
|
+
version: 1.9.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-09-
|
12
|
+
date: 2020-09-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mediawiki-replaceable-content
|
@@ -204,10 +204,10 @@ files:
|
|
204
204
|
- exe/position-history-for-item
|
205
205
|
- exe/update_wikidata_page
|
206
206
|
- lib/query_service.rb
|
207
|
-
- lib/sparql/
|
207
|
+
- lib/sparql/bio_query.rb
|
208
208
|
- lib/sparql/item_query.rb
|
209
|
-
- lib/sparql/
|
210
|
-
- lib/sparql/
|
209
|
+
- lib/sparql/mandates_query.rb
|
210
|
+
- lib/sparql/position_query.rb
|
211
211
|
- lib/wikidata_position_history.rb
|
212
212
|
- lib/wikidata_position_history/checks.rb
|
213
213
|
- lib/wikidata_position_history/report.rb
|
data/lib/sparql/position_data.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module WikidataPositionHistory
|
4
|
-
module SPARQL
|
5
|
-
# SPARQL for fetching metadata about a position
|
6
|
-
class PositionData < ItemQuery
|
7
|
-
def raw_sparql
|
8
|
-
<<~SPARQL
|
9
|
-
# position-metadata
|
10
|
-
|
11
|
-
SELECT DISTINCT ?inception ?inception_precision ?abolition ?abolition_precision ?isPosition
|
12
|
-
WHERE {
|
13
|
-
VALUES ?item { wd:%s }
|
14
|
-
BIND(EXISTS { ?item wdt:P279+ wd:Q4164871 } as ?isPosition)
|
15
|
-
OPTIONAL { ?item p:P571/psv:P571 [ wikibase:timeValue ?inception; wikibase:timePrecision ?inception_precision ] }
|
16
|
-
OPTIONAL { ?item p:P576/psv:P576 [ wikibase:timeValue ?abolition; wikibase:timePrecision ?abolition_precision ] }
|
17
|
-
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
|
18
|
-
}
|
19
|
-
SPARQL
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Represents a single row returned from the Position query
|
25
|
-
class PositionData
|
26
|
-
def initialize(row)
|
27
|
-
@row = row
|
28
|
-
end
|
29
|
-
|
30
|
-
def inception_date
|
31
|
-
QueryService::WikidataDate.new(inception_date_raw, inception_date_precision)
|
32
|
-
end
|
33
|
-
|
34
|
-
def abolition_date
|
35
|
-
QueryService::WikidataDate.new(abolition_date_raw, abolition_date_precision)
|
36
|
-
end
|
37
|
-
|
38
|
-
def position?
|
39
|
-
row.dig(:isPosition, :value) == 'true'
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
attr_reader :row
|
45
|
-
|
46
|
-
def inception_date_raw
|
47
|
-
row.dig(:inception, :value).to_s[0..9]
|
48
|
-
end
|
49
|
-
|
50
|
-
def abolition_date_raw
|
51
|
-
row.dig(:abolition, :value).to_s[0..9]
|
52
|
-
end
|
53
|
-
|
54
|
-
def inception_date_precision
|
55
|
-
row.dig(:inception_precision, :value)
|
56
|
-
end
|
57
|
-
|
58
|
-
def abolition_date_precision
|
59
|
-
row.dig(:abolition_precision, :value)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|