wikidatum 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +14 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +28 -1
- data/README.md +38 -3
- data/Rakefile +1 -1
- data/lib/wikidatum/client.rb +356 -8
- data/lib/wikidatum/data_value_type/base.rb +61 -0
- data/lib/wikidatum/data_value_type/globe_coordinate.rb +92 -0
- data/lib/wikidatum/data_value_type/monolingual_text.rb +74 -0
- data/lib/wikidatum/data_value_type/no_value.rb +29 -0
- data/lib/wikidatum/data_value_type/quantity.rb +92 -0
- data/lib/wikidatum/data_value_type/some_value.rb +29 -0
- data/lib/wikidatum/data_value_type/time.rb +187 -0
- data/lib/wikidatum/data_value_type/wikibase_entity_id.rb +83 -0
- data/lib/wikidatum/data_value_type/wikibase_string.rb +61 -0
- data/lib/wikidatum/data_value_type.rb +11 -0
- data/lib/wikidatum/item.rb +118 -12
- data/lib/wikidatum/qualifier.rb +5 -2
- data/lib/wikidatum/reference.rb +43 -0
- data/lib/wikidatum/sitelink.rb +15 -1
- data/lib/wikidatum/snak.rb +75 -0
- data/lib/wikidatum/statement.rb +73 -0
- data/lib/wikidatum/term.rb +13 -0
- data/lib/wikidatum/version.rb +1 -1
- data/lib/wikidatum.rb +48 -0
- data/wikidatum.gemspec +2 -2
- metadata +29 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8f1ec02cd83bf3ea3e432868a8283474f810bfd55740b5759c820d880f95e31
|
4
|
+
data.tar.gz: a5af62f917570a29ceceb6e420377154775d9820dec8abb02eb84e037f0bab89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6c46eacdb7d7455ee5e96d3cf7c0970bd85ffc3abd1dc09c856b0f92062beaede5d451c9587ab72afc14d3b3c3a4e800c9685b435fbb4074b7d5e0b77cda463
|
7
|
+
data.tar.gz: bf4810fc7384b5b5cecf2db956758a1125a1664b62b8f7275d77347c7e0b78d64fbd76d011375914162c7a3a687bb4b679fd2ace7e8addcda2ad84775b88503f
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
|
7
7
|
## Unreleased
|
8
8
|
|
9
|
+
## 0.2.0 - 2022-08-13
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- Add ability to serialize most of an item response from the Beta REST API into a usable `Wikidatum::Item` instance.
|
13
|
+
- This enables basic functionality like `client.item(id: 'Q123')` and `client.item(id: 'Q123').statements(properties: ['P123'])`.
|
14
|
+
- Add `Client#add_statement` method for creating new statements on an item.
|
15
|
+
- Add `Client#delete_statement` method for deleting statements from an item.
|
16
|
+
- Add support for reading and writing all statement types: `novalue`, `somevalue`, `string`, `time`, `quantity`, `globecoordinate`, `monolingualtext`, and `wikibase-entityid`.
|
17
|
+
|
18
|
+
### Internal
|
19
|
+
|
20
|
+
- Add YARD docs and auto-deploy them with GitHub Pages.
|
21
|
+
- Add comprehensive unit tests for the gem.
|
22
|
+
|
9
23
|
## 0.1.0 - 2022-06-20
|
10
24
|
### Added
|
11
25
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,16 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
wikidatum (0.
|
4
|
+
wikidatum (0.2.0)
|
5
|
+
faraday (~> 2.4)
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
8
9
|
specs:
|
10
|
+
addressable (2.8.0)
|
11
|
+
public_suffix (>= 2.0.2, < 5.0)
|
9
12
|
ast (2.4.2)
|
13
|
+
crack (0.4.5)
|
14
|
+
rexml
|
15
|
+
docile (1.4.0)
|
16
|
+
faraday (2.4.0)
|
17
|
+
faraday-net_http (~> 2.0)
|
18
|
+
ruby2_keywords (>= 0.0.4)
|
19
|
+
faraday-net_http (2.1.0)
|
20
|
+
hashdiff (1.0.1)
|
10
21
|
minitest (5.16.0)
|
11
22
|
parallel (1.22.1)
|
12
23
|
parser (3.1.2.0)
|
13
24
|
ast (~> 2.4.1)
|
25
|
+
public_suffix (4.0.7)
|
14
26
|
rainbow (3.1.1)
|
15
27
|
rake (13.0.6)
|
16
28
|
regexp_parser (2.5.0)
|
@@ -27,18 +39,33 @@ GEM
|
|
27
39
|
rubocop-ast (1.18.0)
|
28
40
|
parser (>= 3.1.1.0)
|
29
41
|
ruby-progressbar (1.11.0)
|
42
|
+
ruby2_keywords (0.0.5)
|
43
|
+
simplecov (0.21.2)
|
44
|
+
docile (~> 1.1)
|
45
|
+
simplecov-html (~> 0.11)
|
46
|
+
simplecov_json_formatter (~> 0.1)
|
47
|
+
simplecov-html (0.12.3)
|
48
|
+
simplecov_json_formatter (0.1.4)
|
30
49
|
unicode-display_width (2.1.0)
|
50
|
+
webmock (3.17.1)
|
51
|
+
addressable (>= 2.8.0)
|
52
|
+
crack (>= 0.3.2)
|
53
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
31
54
|
webrick (1.7.0)
|
32
55
|
yard (0.9.28)
|
33
56
|
webrick (~> 1.7.0)
|
34
57
|
|
35
58
|
PLATFORMS
|
59
|
+
arm64-darwin-21
|
36
60
|
x86_64-darwin-21
|
61
|
+
x86_64-linux
|
37
62
|
|
38
63
|
DEPENDENCIES
|
39
64
|
minitest (~> 5.16)
|
40
65
|
rake (~> 13.0)
|
41
66
|
rubocop (~> 1.30)
|
67
|
+
simplecov (~> 0.21)
|
68
|
+
webmock (~> 3.17)
|
42
69
|
wikidatum!
|
43
70
|
yard (~> 0.9)
|
44
71
|
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Wikidatum
|
2
2
|
|
3
|
-
This gem
|
3
|
+
This gem supports making requests to the [new Wikidata/Wikibase REST API](https://doc.wikimedia.org/Wikibase/master/js/rest-api/).
|
4
4
|
|
5
|
-
**
|
5
|
+
**The gem is currently in very early development and is not ready for production usage**.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -22,7 +22,42 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
You can view the YARD docs on GitHub Pages [here](https://connorshea.github.io/wikidatum/index.html).
|
26
|
+
|
27
|
+
Currently, the gem is able to hit a few GET endpoints, and currently has no way to provide authentication and perform POST/PUT/DELETE requests. The additional features will be added later.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'wikidatum'
|
31
|
+
|
32
|
+
wikidatum_client = Wikidatum::Client.new(
|
33
|
+
user_agent: 'REPLACE ME WITH THE NAME OF YOUR BOT!',
|
34
|
+
# Currently only the beta site has the API available, you'll
|
35
|
+
# likely want to use wikidata.org once it's stable.
|
36
|
+
wikibase_url: 'https://wikidata.beta.wmflabs.org',
|
37
|
+
bot: true
|
38
|
+
)
|
39
|
+
|
40
|
+
# Get an item from the Wikibase instance.
|
41
|
+
item = wikidatum_client.item(id: 'Q2') #=> Wikidatum::Item
|
42
|
+
|
43
|
+
# Get the statements from the item.
|
44
|
+
item.statements #=> Array<Wikidatum::Statement>
|
45
|
+
|
46
|
+
# Get the statments for property P123 on the item.
|
47
|
+
item.statements(properties: ['P123']) #=> Array<Wikidatum::Statement>
|
48
|
+
|
49
|
+
# Get all the labels for the item.
|
50
|
+
item.labels #=> Array<Wikidatum::Term>
|
51
|
+
|
52
|
+
# Get the English label for the item.
|
53
|
+
item.label(lang: :en) #=> Wikidatum::Term
|
54
|
+
|
55
|
+
# Get the actual value for the label.
|
56
|
+
item.label(lang: :en).value #=> "Earth"
|
57
|
+
|
58
|
+
# Get the values for all English aliases on this item.
|
59
|
+
item.aliases(langs: [:en]).map(&:value) #=> ["Planet Earth", "Pale Blue Dot"]
|
60
|
+
```
|
26
61
|
|
27
62
|
## Development
|
28
63
|
|
data/Rakefile
CHANGED
data/lib/wikidatum/client.rb
CHANGED
@@ -1,22 +1,370 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'faraday'
|
4
|
+
require 'faraday/net_http'
|
5
|
+
|
3
6
|
class Wikidatum::Client
|
4
|
-
|
5
|
-
|
7
|
+
ITEM_REGEX = /^Q?\d+$/.freeze
|
8
|
+
STATEMENT_REGEX = /^Q?\d+\$[\w-]+$/.freeze
|
9
|
+
|
10
|
+
# @return [String] the root URL of the Wikibase instance we want to interact
|
11
|
+
# with. If not provided, will default to Wikidata.
|
6
12
|
attr_reader :wikibase_url
|
7
13
|
|
8
|
-
# @return [Boolean]
|
9
|
-
#
|
14
|
+
# @return [Boolean] whether this client instance should identify itself
|
15
|
+
# as a bot when making requests.
|
10
16
|
attr_reader :bot
|
11
17
|
|
18
|
+
# @return [String] the UserAgent header to send with all requests to the
|
19
|
+
# Wikibase API.
|
20
|
+
attr_reader :user_agent
|
21
|
+
|
22
|
+
# Create a new Wikidatum::Client to interact with the Wikibase REST API.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# wikidatum_client = Wikidatum::Client.new(
|
26
|
+
# user_agent: 'REPLACE ME WITH THE NAME OF YOUR BOT!',
|
27
|
+
# wikibase_url: 'https://www.wikidata.org',
|
28
|
+
# bot: true
|
29
|
+
# )
|
30
|
+
#
|
31
|
+
# @param user_agent [String] The UserAgent header to send with all requests
|
32
|
+
# to the Wikibase API.
|
12
33
|
# @param wikibase_url [String] The root URL of the Wikibase instance we want
|
13
|
-
#
|
14
|
-
#
|
34
|
+
# to interact with. If not provided, will default to
|
35
|
+
# `https://www.wikidata.org`. Do not include a `/` at the end of the URL.
|
15
36
|
# @param bot [Boolean] Whether requests sent by this client instance should
|
16
|
-
#
|
37
|
+
# be registered as bot requests. Defaults to `true`.
|
17
38
|
# @return [Wikidatum::Client]
|
18
|
-
def initialize(wikibase_url: 'https://www.wikidata.org', bot: true)
|
39
|
+
def initialize(user_agent:, wikibase_url: 'https://www.wikidata.org', bot: true)
|
40
|
+
raise ArgumentError, "Wikibase URL must not end with a `/`, got #{wikibase_url.inspect}." if wikibase_url.end_with?('/')
|
41
|
+
|
42
|
+
# TODO: Add the Ruby gem version to the UserAgent automatically, and
|
43
|
+
# restrict the ability for end-users to actually set the UserAgent?
|
44
|
+
@user_agent = user_agent
|
19
45
|
@wikibase_url = wikibase_url
|
20
46
|
@bot = bot
|
47
|
+
|
48
|
+
Faraday.default_adapter = :net_http
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get an item from the Wikibase API based on its QID.
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# wikidatum_client.item(id: 'Q123')
|
55
|
+
# wikidatum_client.item(id: 123)
|
56
|
+
# wikidatum_client.item(id: '123')
|
57
|
+
#
|
58
|
+
# @param id [String, Integer] Either a string or integer representation of
|
59
|
+
# the item's QID, e.g. `"Q123"`, `"123"`, or `123`.
|
60
|
+
# @return [Wikidatum::Item]
|
61
|
+
def item(id:)
|
62
|
+
raise ArgumentError, "#{id.inspect} is an invalid Wikibase QID. Must be an integer, a string representation of an integer, or in the format 'Q123'." unless id.is_a?(Integer) || id.match?(ITEM_REGEX)
|
63
|
+
|
64
|
+
id = coerce_item_id(id)
|
65
|
+
|
66
|
+
response = get_request("/entities/items/#{id}")
|
67
|
+
|
68
|
+
puts JSON.pretty_generate(response) if ENV['DEBUG']
|
69
|
+
|
70
|
+
Wikidatum::Item.marshal_load(response)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Get a statement from the Wikibase API based on its ID.
|
74
|
+
#
|
75
|
+
# @example
|
76
|
+
# wikidatum_client.statement(id: 'Q123$f004ec2b-4857-3b69-b370-e8124f5bd3ac')
|
77
|
+
#
|
78
|
+
# @param id [String] A string representation of the statement's ID.
|
79
|
+
# @return [Wikidatum::Statement]
|
80
|
+
def statement(id:)
|
81
|
+
raise ArgumentError, "#{id.inspect} is an invalid Wikibase Statement ID. Must be a string in the format 'Q123$f004ec2b-4857-3b69-b370-e8124f5bd3ac'." unless id.match?(STATEMENT_REGEX)
|
82
|
+
|
83
|
+
response = get_request("/statements/#{id}")
|
84
|
+
|
85
|
+
puts JSON.pretty_generate(response) if ENV['DEBUG']
|
86
|
+
|
87
|
+
Wikidatum::Statement.marshal_load(response)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Add a statement to an item.
|
91
|
+
#
|
92
|
+
# NOTE: Adding references/qualifiers with `add_statement` is untested and
|
93
|
+
# effectively unsupported for now.
|
94
|
+
#
|
95
|
+
# @example Add a string statement.
|
96
|
+
# wikidatum_client.add_statement(
|
97
|
+
# id: 'Q123',
|
98
|
+
# property: 'P23',
|
99
|
+
# datavalue: Wikidatum::DataValueType::WikibaseString.new(string: 'Foo'),
|
100
|
+
# comment: 'Adding something or another.'
|
101
|
+
# )
|
102
|
+
#
|
103
|
+
# @example Add a 'no value' statement.
|
104
|
+
# wikidatum_client.add_statement(
|
105
|
+
# id: 'Q123',
|
106
|
+
# property: 'P124',
|
107
|
+
# datavalue: Wikidatum::DataValueType::NoValue.new(
|
108
|
+
# type: :no_value,
|
109
|
+
# value: nil
|
110
|
+
# )
|
111
|
+
# )
|
112
|
+
#
|
113
|
+
# @example Add an 'unknown value' statement.
|
114
|
+
# wikidatum_client.add_statement(
|
115
|
+
# id: 'Q123',
|
116
|
+
# property: 'P124',
|
117
|
+
# datavalue: Wikidatum::DataValueType::SomeValue.new(
|
118
|
+
# type: :some_value,
|
119
|
+
# value: nil
|
120
|
+
# )
|
121
|
+
# )
|
122
|
+
#
|
123
|
+
# @example Add a globe coordinate statement.
|
124
|
+
# wikidatum_client.add_statement(
|
125
|
+
# id: 'Q123',
|
126
|
+
# property: 'P124',
|
127
|
+
# datavalue: Wikidatum::DataValueType::GlobeCoordinate.new(
|
128
|
+
# latitude: 52.51666,
|
129
|
+
# longitude: 13.3833,
|
130
|
+
# precision: 0.01666,
|
131
|
+
# globe: 'https://wikidata.org/entity/Q2'
|
132
|
+
# )
|
133
|
+
# )
|
134
|
+
#
|
135
|
+
# @example Add a monolingual text statement.
|
136
|
+
# wikidatum_client.add_statement(
|
137
|
+
# id: 'Q123',
|
138
|
+
# property: 'P124',
|
139
|
+
# datavalue: Wikidatum::DataValueType::MonolingualText.new(
|
140
|
+
# language: 'en',
|
141
|
+
# text: 'Foobar'
|
142
|
+
# )
|
143
|
+
# )
|
144
|
+
#
|
145
|
+
# @example Add a quantity statement.
|
146
|
+
# wikidatum_client.add_statement(
|
147
|
+
# id: 'Q123',
|
148
|
+
# property: 'P124',
|
149
|
+
# datavalue: Wikidatum::DataValueType::Quantity.new(
|
150
|
+
# amount: '+12',
|
151
|
+
# upper_bound: nil,
|
152
|
+
# lower_bound: nil,
|
153
|
+
# unit: 'https://wikidata.org/entity/Q1234'
|
154
|
+
# )
|
155
|
+
# )
|
156
|
+
#
|
157
|
+
# @example Add a time statement.
|
158
|
+
# wikidatum_client.add_statement(
|
159
|
+
# id: 'Q123',
|
160
|
+
# property: 'P124',
|
161
|
+
# datavalue: Wikidatum::DataValueType::Time.new(
|
162
|
+
# time: '+2022-08-12T00:00:00Z',
|
163
|
+
# time_zone: 0,
|
164
|
+
# precision: 11,
|
165
|
+
# calendar_model: 'https://wikidata.org/entity/Q1234'
|
166
|
+
# )
|
167
|
+
# )
|
168
|
+
#
|
169
|
+
# @example Add a Wikibase item statement.
|
170
|
+
# wikidatum_client.add_statement(
|
171
|
+
# id: 'Q123',
|
172
|
+
# property: 'P124',
|
173
|
+
# datavalue: Wikidatum::DataValueType::WikibaseEntityId.new(
|
174
|
+
# entity_type: 'item',
|
175
|
+
# numeric_id: 1234,
|
176
|
+
# id: 'Q1234'
|
177
|
+
# )
|
178
|
+
# )
|
179
|
+
#
|
180
|
+
# @param id [String] the ID of the item on which the statement will be added.
|
181
|
+
# @param property [String] property ID in the format 'P123'.
|
182
|
+
# @param datavalue [Wikidatum::DataValueType::GlobeCoordinate, Wikidatum::DataValueType::MonolingualText, Wikidatum::DataValueType::Quantity, Wikidatum::DataValueType::WikibaseString, Wikidatum::DataValueType::Time, Wikidatum::DataValueType::WikibaseEntityId, Wikidatum::DataValueType::NoValue, Wikidatum::DataValueType::SomeValue] the datavalue of the statement being created.
|
183
|
+
# @param datatype [String, nil] if nil, it'll determine the type based on what was passed for the statement argument. This may differ from the type of the Statement's datavalue (for example with the 'url' type).
|
184
|
+
# @param qualifiers [Hash<String, Array<Wikidatum::Snak>>]
|
185
|
+
# @param references [Array<Wikidatum::Reference>]
|
186
|
+
# @param rank [String]
|
187
|
+
# @param tags [Array<String>]
|
188
|
+
# @param comment [String, nil]
|
189
|
+
# @return [Boolean] True if the request succeeded.
|
190
|
+
def add_statement(id:, property:, datavalue:, datatype: nil, qualifiers: {}, references: [], rank: 'normal', tags: [], comment: nil)
|
191
|
+
raise ArgumentError, "#{id.inspect} is an invalid Wikibase QID. Must be an integer, a string representation of an integer, or in the format 'Q123'." unless id.is_a?(Integer) || id.match?(ITEM_REGEX)
|
192
|
+
|
193
|
+
id = coerce_item_id(id)
|
194
|
+
|
195
|
+
# Unless datatype is set explicitly by the caller, just assume we can pull the
|
196
|
+
# default from the datavalue class.
|
197
|
+
datatype ||= datavalue.wikibase_datatype
|
198
|
+
|
199
|
+
case datavalue.class.to_s
|
200
|
+
when 'Wikidatum::DataValueType::NoValue'
|
201
|
+
statement_hash = {
|
202
|
+
mainsnak: {
|
203
|
+
snaktype: 'novalue',
|
204
|
+
property: property,
|
205
|
+
datatype: datatype
|
206
|
+
}
|
207
|
+
}
|
208
|
+
when 'Wikidatum::DataValueType::SomeValue'
|
209
|
+
statement_hash = {
|
210
|
+
mainsnak: {
|
211
|
+
snaktype: 'somevalue',
|
212
|
+
property: property,
|
213
|
+
datatype: datatype
|
214
|
+
}
|
215
|
+
}
|
216
|
+
when 'Wikidatum::DataValueType::GlobeCoordinate', 'Wikidatum::DataValueType::MonolingualText', 'Wikidatum::DataValueType::Quantity', 'Wikidatum::DataValueType::WikibaseString', 'Wikidatum::DataValueType::Time', 'Wikidatum::DataValueType::WikibaseEntityId'
|
217
|
+
statement_hash = {
|
218
|
+
mainsnak: {
|
219
|
+
snaktype: 'value',
|
220
|
+
property: property,
|
221
|
+
datatype: datatype,
|
222
|
+
datavalue: {
|
223
|
+
type: datavalue.wikibase_type,
|
224
|
+
value: datavalue.marshal_dump
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
else
|
229
|
+
raise ArgumentError, "Expected an instance of one of Wikidatum::DataValueType's subclasses for datavalue, but got #{datavalue.inspect}."
|
230
|
+
end
|
231
|
+
|
232
|
+
body = { statement: statement_hash.merge({ qualifiers: qualifiers, references: references, rank: rank, type: "statement" }) }
|
233
|
+
|
234
|
+
response = post_request("/entities/items/#{id}/statements", body, tags: tags, comment: comment)
|
235
|
+
|
236
|
+
puts JSON.pretty_generate(response) if ENV['DEBUG']
|
237
|
+
|
238
|
+
response.success?
|
239
|
+
end
|
240
|
+
|
241
|
+
# Delete a statement from an item.
|
242
|
+
#
|
243
|
+
# @example
|
244
|
+
# wikidatum_client.delete_statement(
|
245
|
+
# id: 'Q123$4543523c-1d1d-1111-1e1e-11b11111b1f1',
|
246
|
+
# comment: "Deleting this statement because it's bad."
|
247
|
+
# )
|
248
|
+
#
|
249
|
+
# @param id [String] the ID of the statemnt being deleted.
|
250
|
+
# @param tags [Array<String>]
|
251
|
+
# @param comment [String, nil]
|
252
|
+
# @return [Boolean] True if the request succeeded.
|
253
|
+
def delete_statement(id:, tags: [], comment: nil)
|
254
|
+
raise ArgumentError, "#{id.inspect} is an invalid Wikibase Statement ID. Must be a string in the format 'Q123$f004ec2b-4857-3b69-b370-e8124f5bd3ac'." unless id.match?(STATEMENT_REGEX)
|
255
|
+
|
256
|
+
response = delete_request("/statements/#{id}", tags: tags, comment: comment)
|
257
|
+
|
258
|
+
puts JSON.pretty_generate(response) if ENV['DEBUG']
|
259
|
+
|
260
|
+
response.success?
|
261
|
+
end
|
262
|
+
|
263
|
+
private
|
264
|
+
|
265
|
+
# For now this just returns the `@wikibase_url`, but in the future the API
|
266
|
+
# routes will presumably be nested further, so this is just future-proofing
|
267
|
+
# to allow that to be easily changed later.
|
268
|
+
#
|
269
|
+
# @return [String] URL for the Wikibase API endpoint.
|
270
|
+
def api_url
|
271
|
+
@api_url ||= "#{@wikibase_url}/w/rest.php/wikibase/v0"
|
272
|
+
end
|
273
|
+
|
274
|
+
# Default headers to be sent with every request.
|
275
|
+
#
|
276
|
+
# @return [Hash] A hash of some headers that should be used when sending a request.
|
277
|
+
def universal_headers
|
278
|
+
@universal_headers ||= {
|
279
|
+
'User-Agent' => @user_agent,
|
280
|
+
'Content-Type' => 'application/json'
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
# Make a GET request to a given Wikibase endpoint.
|
285
|
+
#
|
286
|
+
# @param path [String] The relative path for the API endpoint.
|
287
|
+
# @param params [Hash] Query parameters to send with the request, if any.
|
288
|
+
# @return [Hash] JSON response, parsed into a hash.
|
289
|
+
def get_request(path, params = nil)
|
290
|
+
url = "#{api_url}#{path}"
|
291
|
+
|
292
|
+
response = Faraday.get(url, params, universal_headers)
|
293
|
+
|
294
|
+
# Error handling if it doesn't return a 200
|
295
|
+
unless response.success?
|
296
|
+
puts 'Something went wrong with this request!'
|
297
|
+
puts "Status Code: #{response.status}"
|
298
|
+
puts response.body.inspect
|
299
|
+
end
|
300
|
+
|
301
|
+
JSON.parse(response.body)
|
302
|
+
end
|
303
|
+
|
304
|
+
# Make a POST request to a given Wikibase endpoint.
|
305
|
+
#
|
306
|
+
# @param path [String] The relative path for the API endpoint.
|
307
|
+
# @param body [Hash] The body to post to the endpoint.
|
308
|
+
# @param tags [Array<String>] The tags to apply to the edit being made by this request, for PUT/POST/DELETE requests.
|
309
|
+
# @param comment [String] The edit description, for PUT/POST/DELETE requests.
|
310
|
+
# @return [Hash] JSON response, parsed into a hash.
|
311
|
+
def post_request(path, body = {}, tags: nil, comment: nil)
|
312
|
+
url = "#{api_url}#{path}"
|
313
|
+
|
314
|
+
body[:bot] = @bot
|
315
|
+
body[:tags] = tags unless tags.empty?
|
316
|
+
body[:comment] = comment unless comment.nil?
|
317
|
+
|
318
|
+
response = Faraday.post(url) do |req|
|
319
|
+
req.body = JSON.generate(body)
|
320
|
+
req.headers = universal_headers
|
321
|
+
end
|
322
|
+
|
323
|
+
puts response.body.inspect if ENV['DEBUG']
|
324
|
+
|
325
|
+
response
|
326
|
+
end
|
327
|
+
|
328
|
+
# Make a DELETE request to a given Wikibase endpoint.
|
329
|
+
#
|
330
|
+
# @param path [String] The relative path for the API endpoint.
|
331
|
+
# @param tags [Array<String>] The tags to apply to the edit being made by this request, for PUT/POST/DELETE requests.
|
332
|
+
# @param comment [String] The edit description, for PUT/POST/DELETE requests.
|
333
|
+
# @return [Hash] JSON response, parsed into a hash.
|
334
|
+
def delete_request(path, tags: [], comment: nil)
|
335
|
+
url = "#{api_url}#{path}"
|
336
|
+
|
337
|
+
body = {}
|
338
|
+
body[:bot] = @bot
|
339
|
+
body[:tags] = tags unless tags.empty?
|
340
|
+
body[:comment] = comment unless comment.nil?
|
341
|
+
|
342
|
+
response = Faraday.delete(url) do |req|
|
343
|
+
req.body = JSON.generate(body)
|
344
|
+
req.headers = universal_headers
|
345
|
+
end
|
346
|
+
|
347
|
+
puts response.body.inspect if ENV['DEBUG']
|
348
|
+
|
349
|
+
# Error handling if it doesn't return a 200
|
350
|
+
unless response.success?
|
351
|
+
puts 'Something went wrong with this request!'
|
352
|
+
puts "Status Code: #{response.status}"
|
353
|
+
puts response.body.inspect
|
354
|
+
end
|
355
|
+
|
356
|
+
response
|
357
|
+
end
|
358
|
+
|
359
|
+
# Coerce an Item ID in the formats 'Q123', '123' or 123 into a consistent
|
360
|
+
# 'Q123' format. We need to have the ID in the format 'Q123' for the API
|
361
|
+
# request, which is why coercion is necessary.
|
362
|
+
#
|
363
|
+
# @param id [String, Integer]
|
364
|
+
# @return [String]
|
365
|
+
def coerce_item_id(id)
|
366
|
+
return id if id.to_s.start_with?('Q')
|
367
|
+
|
368
|
+
"Q#{id}"
|
21
369
|
end
|
22
370
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# For more information on the possible types that can be returned by
|
4
|
+
# datavalues, see the official documentation:
|
5
|
+
# https://doc.wikimedia.org/Wikibase/master/php/md_docs_topics_json.html#json_datavalues
|
6
|
+
module Wikidatum::DataValueType
|
7
|
+
class Base
|
8
|
+
# Represents the type for this datavalue instance.
|
9
|
+
#
|
10
|
+
# Possible values for the `type` attribute are:
|
11
|
+
#
|
12
|
+
# - `:no_value`: No value
|
13
|
+
# - `:some_value`: Unknown value
|
14
|
+
# - `:globe_coordinate`: {DataValueType::GlobeCoordinate}
|
15
|
+
# - `:monolingual_text`: {DataValueType::MonolingualText}
|
16
|
+
# - `:quantity`: {DataValueType::Quantity}
|
17
|
+
# - `:string`: {DataValueType::WikibaseString}
|
18
|
+
# - `:time`: {DataValueType::Time}
|
19
|
+
# - `:wikibase_entity_id`: {DataValueType::WikibaseEntityId}
|
20
|
+
#
|
21
|
+
# @return [Symbol]
|
22
|
+
attr_reader :type
|
23
|
+
|
24
|
+
# The value of the datavalue object in the response.
|
25
|
+
#
|
26
|
+
# If the `type` is `novalue` or `somevalue`, this returns `nil`.
|
27
|
+
#
|
28
|
+
# @return [DataValueType::GlobeCoordinate, DataValueType::MonolingualText, DataValueType::Quantity, DataValueType::WikibaseString, DataValueType::Time, DataValueType::WikibaseEntityId, nil]
|
29
|
+
attr_reader :value
|
30
|
+
|
31
|
+
# @param type [Symbol]
|
32
|
+
# @param value [DataValueType::GlobeCoordinate, DataValueType::MonolingualText, DataValueType::Quantity, DataValueType::WikibaseString, DataValueType::Time, DataValueType::WikibaseEntityId, nil] nil if type is no_value or some_value
|
33
|
+
# @return [void]
|
34
|
+
def initialize(type:, value:)
|
35
|
+
@type = type
|
36
|
+
@value = value
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Hash]
|
40
|
+
def to_h
|
41
|
+
{
|
42
|
+
type: @type,
|
43
|
+
value: @value&.to_h
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# @!visibility private
|
48
|
+
#
|
49
|
+
# @param data_value_type [String] The value of `type` for the given Snak's datavalue.
|
50
|
+
# @param data_value_json [Hash] The `value` part of datavalue.
|
51
|
+
# @return [Wikidatum::DataValueType::Base] An instance of Base.
|
52
|
+
def self.marshal_load(data_value_type, data_value_json)
|
53
|
+
unless Wikidatum::DataValueType::DATA_VALUE_TYPES.keys.include?(data_value_type.to_sym)
|
54
|
+
puts 'WARNING: Unsupported datavalue type.'
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
Object.const_get(Wikidatum::DataValueType::DATA_VALUE_TYPES[data_value_type.to_sym]).marshal_load(data_value_json)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|