wikidata_position_history 1.3.4 → 1.4.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: '018cdd5d51eee83b0738a0b84f32d92259bf4665fe25894b2d005f308c033466'
4
- data.tar.gz: bf630179eacfe1e68b88dacd268ae4c1e35efdabfc0149963338cf9de3a20567
3
+ metadata.gz: 0ef4815c74d73d50bd3d74a70af9d9b47177d5f3c00e35748892cad201150bed
4
+ data.tar.gz: fdd1e8b5fa7fe220da78daabdcdc016e8ee729c57648103bbc384860e2ef0ce6
5
5
  SHA512:
6
- metadata.gz: cb6dd44e9a746bf425a5ef8199d7bd10891ea887d3f61dab6fff676ecdb21ceec19da22ac585c0ac3c61d70a4deeb26c5fd1f602ab45d49aaa6595ca4aa0dccd
7
- data.tar.gz: 583747329e14ed0f7292c5f7e71e1e4bafe63ca83dd028786449fa582af0b68880e90287e1028b249eeef28f125f54d3b7ae0d6940048cc122901f57b52e2aa5
6
+ metadata.gz: fe138774ce37cf9258c7f11bfc3bc95cbaafa3811507a2b963d006d1e5982e9257ce754ea46fe47fe7e3eabb95520ae534549badcc6a7c8335ee3ff4368cef82
7
+ data.tar.gz: 2e266bd52f9bef2e8736bcf566c1ec5e4b7ad10a90f13d4a31f6613411797ff01e4a528263db3b15cce573de10c4c41eb36ea46838f7d16c30748a3a58585564
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ # [1.4.0] 2020-09-04
4
+
5
+ ## Enhancements
6
+
7
+ * Add an image column.
8
+ * Improve the warning for inconsistent successor/predecessor values.
9
+
3
10
  # [1.3.4] - 2020-09-01
4
11
 
5
12
  ## Fixes
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WikidataPositionHistory
4
+ module SPARQL
5
+ # SPARQL for fetching biographical about all holders of a position
6
+ #
7
+ # This is distinct from the mandate query itself to avoid complex
8
+ # GROUP BY scenarios where people have multiple values for
9
+ # biographical properties.
10
+ class BioData < ItemQuery
11
+ def raw_sparql
12
+ <<~SPARQL
13
+ # holder-biodata
14
+
15
+ SELECT DISTINCT ?item ?image
16
+ WHERE {
17
+ ?item wdt:P31 wd:Q5 ; p:P39/ps:P39 wd:%s .
18
+ OPTIONAL { ?item wdt:P18 ?image }
19
+ }
20
+ ORDER BY ?item
21
+ SPARQL
22
+ end
23
+ end
24
+ end
25
+
26
+ # Represents a single row returned from the Position query
27
+ class BioData
28
+ def initialize(row)
29
+ @row = row
30
+ end
31
+
32
+ def person
33
+ QueryService::WikidataItem.new(row.dig(:item, :value))
34
+ end
35
+
36
+ def image_title
37
+ return if image_url.to_s.empty?
38
+
39
+ image_url.split('/').last
40
+ end
41
+
42
+ def image_link(size = 75)
43
+ return '' unless image_title
44
+
45
+ "[[File:#{image_title}|#{size}px]]"
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :row
51
+
52
+ def image_url
53
+ row.dig(:image, :value)
54
+ end
55
+ end
56
+ end
@@ -7,6 +7,7 @@ module WikidataPositionHistory
7
7
  def raw_sparql
8
8
  <<~SPARQL
9
9
  # position-mandates
10
+
10
11
  SELECT DISTINCT ?ordinal ?item ?start_date ?start_precision ?end_date ?end_precision ?prev ?next ?nature
11
12
  WHERE {
12
13
  ?item wdt:P31 wd:Q5 ; p:P39 ?posn .
@@ -19,7 +20,6 @@ module WikidataPositionHistory
19
20
  OPTIONAL { ?posn pq:P1366|pq:P156 ?next }
20
21
  OPTIONAL { ?posn pq:P1545 ?ordinal }
21
22
  OPTIONAL { ?posn pq:P5102 ?nature }
22
- OPTIONAL { ?posn pq:P5102 ?nature }
23
23
  }
24
24
  ORDER BY DESC(?start_date)
25
25
  SPARQL
@@ -37,8 +37,13 @@ module WikidataPositionHistory
37
37
  row.dig(:ordinal, :value)
38
38
  end
39
39
 
40
+ def officeholder
41
+ QueryService::WikidataItem.new(row.dig(:item, :value))
42
+ end
43
+
44
+ # TODO: rename or remove. 'item' is meaningless/ambiguous
40
45
  def item
41
- QueryService::WikidataItem.new(row.dig(:item, :value)).qlink
46
+ officeholder.qlink
42
47
  end
43
48
 
44
49
  def prev
@@ -3,6 +3,7 @@
3
3
  require 'query_service'
4
4
  require 'sparql/item_query'
5
5
  require 'sparql/position_data'
6
+ require 'sparql/bio_data'
6
7
  require 'sparql/mandates'
7
8
  require 'wikidata_position_history/checks'
8
9
  require 'wikidata_position_history/report'
@@ -100,7 +100,7 @@ module WikidataPositionHistory
100
100
  end
101
101
 
102
102
  def possible_explanation
103
- "#{current.item} has a {{P|1365}} of #{predecessor}, which differs from #{earlier.item}"
103
+ "#{current.item} has a {{P|1365}} of #{predecessor}, but follows #{earlier.item} here"
104
104
  end
105
105
  end
106
106
 
@@ -115,7 +115,7 @@ module WikidataPositionHistory
115
115
  end
116
116
 
117
117
  def possible_explanation
118
- "#{current.item} has a {{P|1366}} of #{successor}, which differs from #{later.item}"
118
+ "#{current.item} has a {{P|1366}} of #{successor}, but is followed by #{later.item} here"
119
119
  end
120
120
  end
121
121
 
@@ -1,95 +1,87 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WikidataPositionHistory
4
- # A single output row of Wikitext for an officeholding
5
- class MandateReport
4
+ # Date for a single mandate row, to be passed to the report template
5
+ class MandateData
6
6
  def initialize(later, current, earlier)
7
7
  @later = later
8
8
  @current = current
9
9
  @earlier = earlier
10
10
  end
11
11
 
12
- def output
13
- [row_start, ordinal_cell, member_cell, warnings_cell].join("\n")
12
+ def ordinal_string
13
+ ordinal = current.ordinal or return ''
14
+ "#{ordinal}."
14
15
  end
15
16
 
16
- private
17
-
18
- CHECKS = [Check::MissingFields, Check::WrongPredecessor, Check::WrongSuccessor, Check::Overlap].freeze
19
-
20
- WARNING_LAYOUT = [
21
- '<span style="display: block">[[File:Pictogram voting comment.svg|15px|link=]]&nbsp;',
22
- '<span style="color: #d33; font-weight: bold; vertical-align: middle;">%s</span>&nbsp;',
23
- '<ref>%s</ref></span>'
24
- ].join
17
+ def person
18
+ current.item
19
+ end
25
20
 
26
- attr_reader :later, :current, :earlier
21
+ def dates
22
+ dates = [current.start_date, current.end_date]
23
+ # compact doesn't work here, even if we add #nil? to WikidataDate
24
+ return '' if dates.reject(&:empty?).empty?
27
25
 
28
- def row_start
29
- '|-'
26
+ dates.join(' – ')
30
27
  end
31
28
 
32
- def ordinal_cell
33
- %(| style="padding:0.5em 2em" | #{ordinal_string})
29
+ def acting?
30
+ current.acting?
34
31
  end
35
32
 
36
- def ordinal_string
37
- ordinal = current.ordinal or return ''
38
- ordinal.concat('.')
33
+ def warnings
34
+ CHECKS.map { |klass| klass.new(later, current, earlier) }.select(&:problem?)
39
35
  end
40
36
 
41
- def member_style
42
- return 'font-size: 1.25em; display: block; font-style: italic;' if current.acting?
37
+ private
43
38
 
44
- 'font-size: 1.5em; display: block;'
45
- end
39
+ CHECKS = [Check::MissingFields, Check::WrongPredecessor, Check::WrongSuccessor, Check::Overlap].freeze
46
40
 
47
- def member_cell
48
- format('| style="padding:0.5em 2em" | <span style="%s">%s</span> %s',
49
- member_style, membership_person, membership_dates)
50
- end
41
+ attr_reader :later, :current, :earlier
42
+ end
51
43
 
52
- def warnings_cell
53
- format('| style="padding:0.5em 2em 0.5em 1em; border: none; background: #fff; text-align: left;" | %s',
54
- combined_warnings)
44
+ # Interface to the ERB Template for the output
45
+ class ReportTemplate
46
+ def initialize(file, data)
47
+ @file = file
48
+ @data = data
55
49
  end
56
50
 
57
- def combined_warnings
58
- CHECKS.map do |check_class|
59
- check = check_class.new(later, current, earlier)
60
- format(WARNING_LAYOUT, check.headline, check.explanation) if check.problem?
61
- end.join
51
+ def output
52
+ template.result_with_hash(data)
62
53
  end
63
54
 
64
- def membership_person
65
- current.item
66
- end
55
+ private
67
56
 
68
- def membership_dates
69
- dates = [current.start_date, current.end_date]
70
- # compact doesn't work here, even if we add #nil? to WikidataDate
71
- return '' if dates.reject(&:empty?).empty?
57
+ def template_path
58
+ Pathname.new(file)
59
+ end
72
60
 
73
- dates.join(' – ')
61
+ def template
62
+ @template ||= ERB.new(template_path.read)
74
63
  end
64
+
65
+ attr_reader :file, :data
75
66
  end
76
67
 
77
68
  # The entire wikitext generated for this report
78
69
  class Report
79
- def initialize(subject_item_id)
80
- @subject_item_id = subject_item_id
70
+ def initialize(position_id, template_file = 'report.erb')
71
+ @position_id = position_id
72
+ @template_file = template_file
81
73
  end
82
74
 
83
- attr_reader :subject_item_id
75
+ attr_reader :position_id, :template_file
84
76
 
85
77
  def wikitext
86
78
  return no_items_output if mandates.empty?
87
79
 
88
- [table_header, table_rows, table_footer, wdqs_section].compact.join("\n")
80
+ output
89
81
  end
90
82
 
91
83
  def header
92
- "== {{Q|#{subject_item_id}}} officeholders #{position_dates} =="
84
+ "== {{Q|#{position_id}}} officeholders #{position_dates} =="
93
85
  end
94
86
 
95
87
  def position_dates
@@ -108,7 +100,15 @@ module WikidataPositionHistory
108
100
  def metadata
109
101
  # TODO: we might get more than one response, if a position has
110
102
  # multiple dates
111
- @metadata ||= SPARQL::PositionData.new(subject_item_id).results_as(PositionData).first
103
+ @metadata ||= SPARQL::PositionData.new(position_id).results_as(PositionData).first
104
+ end
105
+
106
+ def biodata
107
+ @biodata ||= SPARQL::BioData.new(position_id).results_as(BioData)
108
+ end
109
+
110
+ def biodata_for(officeholder)
111
+ biodata.select { |bio| bio.person.id == officeholder.id }
112
112
  end
113
113
 
114
114
  def padded_mandates
@@ -116,7 +116,7 @@ module WikidataPositionHistory
116
116
  end
117
117
 
118
118
  def sparql
119
- @sparql ||= SPARQL::Mandates.new(subject_item_id)
119
+ @sparql ||= SPARQL::Mandates.new(position_id)
120
120
  end
121
121
 
122
122
  def mandates
@@ -124,32 +124,26 @@ module WikidataPositionHistory
124
124
  end
125
125
 
126
126
  def no_items_output
127
- "\n{{PositionHolderHistory/error_no_holders|id=#{subject_item_id}}}\n"
127
+ "\n{{PositionHolderHistory/error_no_holders|id=#{position_id}}}\n"
128
128
  end
129
129
 
130
- def table_header
131
- '{| class="wikitable" style="text-align: center; border: none;"'
132
- end
133
-
134
- def table_footer
135
- "|}\n"
136
- end
137
-
138
- def wdqs_section
139
- wdqs_div % sparql.wdqs_url
130
+ def output
131
+ ReportTemplate.new(template_file, template_params).output
140
132
  end
141
133
 
142
- def wdqs_div
143
- <<~HTML
144
- <div style="margin-bottom:5px; border-bottom:3px solid #2f74d0; font-size:8pt">
145
- <div style="float:right">[%s WDQS]</div>
146
- </div>
147
- HTML
134
+ def template_params
135
+ {
136
+ table_rows: table_rows,
137
+ sparql_url: sparql.wdqs_url,
138
+ }
148
139
  end
149
140
 
150
141
  def table_rows
151
142
  padded_mandates.each_cons(3).map do |later, current, earlier|
152
- MandateReport.new(later, current, earlier).output
143
+ {
144
+ mandate: MandateData.new(later, current, earlier),
145
+ bio: biodata_for(current.officeholder),
146
+ }
153
147
  end
154
148
  end
155
149
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WikidataPositionHistory
4
- VERSION = '1.3.4'
4
+ VERSION = '1.4.0'
5
5
  end
@@ -0,0 +1,11 @@
1
+ {| class="wikitable" style="text-align: center; border: none;"
2
+ <% table_rows.map(&:values).each do |mandate, bio| %>|-
3
+ | style="padding:0.5em 2em" | <%= mandate.ordinal_string %>
4
+ | style="padding:0.5em 2em" | <%= bio.map(&:image_link).first %>
5
+ | 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 %>
6
+ | style="padding:0.5em 2em 0.5em 1em; border: none; background: #fff; text-align: left;" | <% mandate.warnings.each do |warning| %><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><% end %>
7
+ <% end %>|}
8
+
9
+ <div style="margin-bottom:5px; border-bottom:3px solid #2f74d0; font-size:8pt">
10
+ <div style="float:right">[<%= sparql_url %> WDQS]</div>
11
+ </div>
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.3.4
4
+ version: 1.4.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-01 00:00:00.000000000 Z
12
+ date: 2020-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mediawiki-replaceable-content
@@ -176,6 +176,7 @@ files:
176
176
  - exe/position-history-for-item
177
177
  - exe/update_wikidata_page
178
178
  - lib/query_service.rb
179
+ - lib/sparql/bio_data.rb
179
180
  - lib/sparql/item_query.rb
180
181
  - lib/sparql/mandates.rb
181
182
  - lib/sparql/position_data.rb
@@ -183,6 +184,7 @@ files:
183
184
  - lib/wikidata_position_history/checks.rb
184
185
  - lib/wikidata_position_history/report.rb
185
186
  - lib/wikidata_position_history/version.rb
187
+ - report.erb
186
188
  - wikidata_position_history.gemspec
187
189
  homepage: https://github.com/everypolitician/wikidata-position-history/
188
190
  licenses: