wikidata_position_history 1.3.4 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: