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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d45377b5ba871d76f191e7dafe516f308c4f1b17f166b19d0658ee15fff98745
4
- data.tar.gz: ede75c366b3cf99a417ab402f5151880a477b3aa1fc10ff0d4261fb7b7fc0d44
3
+ metadata.gz: 43d866e3ec1ab0f61a2d8d66d46757dff7ecfd66f4c39bb7a1f90125befb3586
4
+ data.tar.gz: 9ac67f8d608c4ce7cc746b4e035664cfed07c5501f117d075fb3ab11444a4a69
5
5
  SHA512:
6
- metadata.gz: 141397d38a5a771e8b2cb159bcd8db327d50f157ba93539b09bb08ff23a64a60e6aa4bdac2bf1a45bdd65dc2f8d343e1a4737a89fc939eafe7ed25e7473562ff
7
- data.tar.gz: 0a3cb133222f05d0ff46dd7810a62a72f3b19ca1f7431bf265752867b916b8ef176f04e11b65a50d2b6ed8d04ba20dc3ecf6fe73cd5fb24caf98737f401b685b
6
+ metadata.gz: 24824e0ad6207a9a3c8b3e8a547a6eda2dc7e9ee5f6503995dd330c82ecb2bab11a4c4655c3fddd1d8c0235b13bc6d607010901147f305d736e46cdd959c1688
7
+ data.tar.gz: 257e34dc5e7855720b101d33d2bbf8404f1d4486270667653d1386e077ae4fbdc631b1edba4c7439f3c5f16b4cb80e6932c53d70c136577456d758fe55963b0d
@@ -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
@@ -8,4 +8,4 @@ if ARGV.size != 1
8
8
  e.g. #{$PROGRAM_NAME} Q14211'"
9
9
  end
10
10
 
11
- puts WikidataPositionHistory::Report.new(ARGV.first).wikitext_with_header
11
+ puts WikidataPositionHistory::Report.new(ARGV.first).wikitext
@@ -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
- "''{{Q|#{id}}}''" if id
57
+ "''#{qlink}''" if qlink
58
+ end
59
+
60
+ def qblink_i
61
+ "''#{qblink}''" if qblink
54
62
  end
55
63
 
56
64
  private
@@ -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
- # TODO: rename or remove. 'item' is meaningless/ambiguous
41
- def item
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] * 3
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
- def successor
20
+ # TODO: replace these with objects instead of strings
21
+ def successor_qlink
21
22
  current.next
22
23
  end
23
24
 
24
- def predecessor
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.item} is missing #{missing.map { |field| "{{P|#{field_map[field]}}}" }.join(', ')}"
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.item == current.item # sucessive terms by same person
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.item == current.item # sucessive terms by same person
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? && !!predecessor && (earlier.item != predecessor)
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.item} has a {{P|1365}} of #{predecessor}, but follows #{earlier.item} here"
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
- predecessor && !earlier_holder?
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.item} has a {{P|1365}} of #{predecessor}, but does not follow anyone here"
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? && !!successor && (later.item != successor)
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.item} has a {{P|1366}} of #{successor}, but is followed by #{later.item} here"
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
- successor && !later_holder?
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.item} has a {{P|1366}} of #{successor}, but is not followed by anyone here"
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
- "#{current.item} has a {{P|582}} of #{current.end_date}, which #{overlap_explanation} the {{P|580}} of #{later.start_date} for #{later.item}"
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 person
26
- current.item
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 qlink
66
- metadata.position.qlink
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
- return [Warning.new('Missing field', "#{qlink} is missing {{P|571}}")] if count.zero?
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', "#{qlink} has more than one {{P|576}}")]
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(&:qlink) + implied_list.indirect_only.map(&:qlink_i)).join(', ')
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, template_class = ReportTemplate)
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 biodata
142
- @biodata ||= SPARQL::BioQuery.new(position_id).results_as(BioRow)
143
- end
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
- def no_items_output
162
- "\n{{PositionHolderHistory/error_no_holders|id=#{position_id}}}\n"
128
+ Report::Position.new(metadata)
163
129
  end
164
130
 
165
- def legislator_template
166
- "\n{{PositionHolderHistory/error_legislator|id=#{position_id}}}\n"
131
+ def template_params
132
+ report.template_params
167
133
  end
168
134
 
169
- def table_rows
170
- padded_mandates.each_cons(3).map do |later, current, earlier|
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=]]&nbsp;<span style="color: #d33; font-weight: bold; vertical-align: middle;"><%= warning.headline %></span>&nbsp;<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.person %></span> <%= mandate.dates %>
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=]]&nbsp;<span style="color: #d33; font-weight: bold; vertical-align: middle;"><%= warning.headline %></span>&nbsp;<ref><%= warning.explanation %></ref></span>\
@@ -60,7 +63,7 @@ module WikidataPositionHistory
60
63
  | colspan="3" style="padding:0.5em; border: none; background: #fff"> |&nbsp;
61
64
  | colspan="1" style="padding:0.5em; border: none; background: #fff"> |&nbsp;
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 %>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WikidataPositionHistory
4
- VERSION = '1.10.0'
4
+ VERSION = '2.3.0'
5
5
  end
@@ -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.8.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: 1.10.0
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-09-13 00:00:00.000000000 Z
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.8.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.8.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