Class: Wikidatum::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/wikidatum/client.rb

Constant Summary collapse

ITEM_REGEX =
/^Q?\d+$/.freeze
PROPERTY_REGEX =
/^P?\d+$/.freeze
STATEMENT_REGEX =
/^Q?\d+\$[\w-]+$/.freeze
VALID_RANKS =
['preferred', 'normal', 'deprecated'].freeze
VALID_DATA_TYPES =
[
  'Wikidatum::DataType::CommonsMedia',
  'Wikidatum::DataType::ExternalId',
  'Wikidatum::DataType::GlobeCoordinate',
  'Wikidatum::DataType::MonolingualText',
  'Wikidatum::DataType::NoValue',
  'Wikidatum::DataType::Quantity',
  'Wikidatum::DataType::SomeValue',
  'Wikidatum::DataType::Time',
  'Wikidatum::DataType::WikibaseItem',
  'Wikidatum::DataType::WikibaseString',
  'Wikidatum::DataType::WikibaseUrl'
].freeze
CONTENT_DATA_TYPES =
[
  'Wikidatum::DataType::CommonsMedia',
  'Wikidatum::DataType::ExternalId',
  'Wikidatum::DataType::GlobeCoordinate',
  'Wikidatum::DataType::MonolingualText',
  'Wikidatum::DataType::Quantity',
  'Wikidatum::DataType::WikibaseString',
  'Wikidatum::DataType::Time',
  'Wikidatum::DataType::WikibaseItem',
  'Wikidatum::DataType::WikibaseUrl'
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user_agent:, wikibase_url: 'https://www.wikidata.org', bot: true, allow_ip_edits: false) ⇒ Wikidatum::Client

Create a new Wikidatum::Client to interact with the Wikibase REST API.

Examples:

wikidatum_client = Wikidatum::Client.new(
  user_agent: 'Bot Name',
  wikibase_url: 'https://www.wikidata.org',
  bot: true
)

Parameters:

  • user_agent (String)

    The UserAgent header to send with all requests to the Wikibase API. This will be prepended with the string “Wikidatum Ruby gem vX.X.X:”.

  • wikibase_url (String) (defaults to: 'https://www.wikidata.org')

    The root URL of the Wikibase instance we want to interact with. If not provided, will default to ‘www.wikidata.org`. Do not include a `/` at the end of the URL.

  • bot (Boolean) (defaults to: true)

    Whether requests sent by this client instance should be registered as bot requests. Defaults to ‘true`.

  • allow_ip_edits (Boolean) (defaults to: false)

    whether this client should allow non-GET requests if authentication hasn’t been provided. Defaults to false. If this is set to true, the IP address of the device from which the request was sent will be credited for the edit. Make sure not to allow these edits if you don’t want your IP address (and in many cases, a very close approximation of your physical location) exposed publicly.

Raises:

  • (ArgumentError)


66
67
68
69
70
71
72
73
74
75
# File 'lib/wikidatum/client.rb', line 66

def initialize(user_agent:, wikibase_url: 'https://www.wikidata.org', bot: true, allow_ip_edits: false)
  raise ArgumentError, "Wikibase URL must not end with a `/`, got #{wikibase_url.inspect}." if wikibase_url.end_with?('/')

  @user_agent = "Wikidatum Ruby gem v#{Wikidatum::VERSION}: #{user_agent}"
  @wikibase_url = wikibase_url
  @bot = bot
  @allow_ip_edits = allow_ip_edits

  Faraday.default_adapter = :net_http
end

Instance Attribute Details

#allow_ip_editsBoolean (readonly)

Returns whether this client should allow non-GET requests if authentication hasn’t been provided. Defaults to false.

Returns:

  • (Boolean)

    whether this client should allow non-GET requests if authentication hasn’t been provided. Defaults to false.



40
41
42
# File 'lib/wikidatum/client.rb', line 40

def allow_ip_edits
  @allow_ip_edits
end

#botBoolean (readonly)

Returns whether this client instance should identify itself as a bot when making requests.

Returns:

  • (Boolean)

    whether this client instance should identify itself as a bot when making requests.



32
33
34
# File 'lib/wikidatum/client.rb', line 32

def bot
  @bot
end

#user_agentString (readonly)

Returns the UserAgent header to send with all requests to the Wikibase API.

Returns:

  • (String)

    the UserAgent header to send with all requests to the Wikibase API.



36
37
38
# File 'lib/wikidatum/client.rb', line 36

def user_agent
  @user_agent
end

#wikibase_urlString (readonly)

Returns the root URL of the Wikibase instance we want to interact with. If not provided, will default to Wikidata.

Returns:

  • (String)

    the root URL of the Wikibase instance we want to interact with. If not provided, will default to Wikidata.



28
29
30
# File 'lib/wikidatum/client.rb', line 28

def wikibase_url
  @wikibase_url
end

Instance Method Details

#add_statement(id:, property:, value:, qualifiers: [], references: [], rank: 'normal', tags: [], comment: nil) ⇒ Boolean

Add a statement to an item.

NOTE: Adding references/qualifiers with ‘add_statement` is untested and effectively unsupported for now.

Examples:

Add a string statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P23',
  value: Wikidatum::DataType::WikibaseString.new(string: 'Foo'),
  comment: 'Adding something or another.'
)

Add a ‘no value’ statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::NoValue.new(
    type: :no_value,
    value: nil
  )
)

Add an ‘unknown value’ statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::SomeValue.new(
    type: :some_value,
    value: nil
  )
)

Add a globe coordinate statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::GlobeCoordinate.new(
    latitude: 52.51666,
    longitude: 13.3833,
    precision: 0.01666,
    globe: 'https://wikidata.org/entity/Q2'
  )
)

Add a monolingual text statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::MonolingualText.new(
    language: 'en',
    text: 'Foobar'
  )
)

Add a quantity statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::Quantity.new(
    amount: '+12',
    unit: 'https://wikidata.org/entity/Q1234'
  )
)

Add a time statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::Time.new(
    time: '+2022-08-12T00:00:00Z',
    precision: 11,
    calendar_model: 'https://wikidata.org/entity/Q1234'
  )
)

Add a Wikibase item statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::WikibaseItem.new(
    id: 'Q1234'
  )
)

Add a URL statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::WikibaseUrl.new(
    string: 'https://example.com'
  )
)

Add an External ID statement.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::ExternalId.new(
    string: '123'
  )
)

Add a statement for an image, video, or audio file from Wikimedia Commons.

wikidatum_client.add_statement(
  id: 'Q123',
  property: 'P124',
  value: Wikidatum::DataType::CommonsMedia.new(
    string: 'FooBar.jpg'
  )
)

Parameters:

Returns:

  • (Boolean)

    True if the request succeeded.

Raises:

  • (ArgumentError)


251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/wikidatum/client.rb', line 251

def add_statement(id:, property:, value:, qualifiers: [], references: [], rank: 'normal', tags: [], comment: nil)
  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)
  raise ArgumentError, "#{property.inspect} is an invalid Wikibase PID. Must be an integer, a string representation of an integer, or in the format 'P123'." unless property.is_a?(Integer) || property.match?(PROPERTY_REGEX)
  raise ArgumentError, "#{rank.inspect} is an invalid rank. Must be normal, preferred, or deprecated." unless VALID_RANKS.include?(rank.to_s)
  raise ArgumentError, "Expected an instance of one of Wikidatum::DataType's subclasses for value, but got #{value.inspect}." unless VALID_DATA_TYPES.include?(value.class.to_s)

  id = coerce_item_id(id)
  property = coerce_property_id(property)

  case value.class.to_s
  when 'Wikidatum::DataType::NoValue'
    statement_hash = {
      property: {
        id: property
      },
      value: {
        type: 'novalue'
      }
    }
  when 'Wikidatum::DataType::SomeValue'
    statement_hash = {
      property: {
        id: property
      },
      value: {
        type: 'somevalue'
      }
    }
  when *CONTENT_DATA_TYPES
    statement_hash = {
      property: {
        id: property
      },
      value: {
        type: 'value',
        content: value.marshal_dump
      }
    }
  end

  body = {
    statement: statement_hash.merge(
      {
        qualifiers: qualifiers,
        references: references,
        rank: rank.to_s
      }
    )
  }

  response = post_request("/entities/items/#{id}/statements", body, tags: tags, comment: comment)

  puts JSON.pretty_generate(response) if ENV['DEBUG']

  response.success?
end

#allow_ip_edits?Boolean

Does the current instance of Client allow anonymous IP-based edits?

Returns:

  • (Boolean)


342
343
344
# File 'lib/wikidatum/client.rb', line 342

def allow_ip_edits?
  @allow_ip_edits
end

#authenticated?Boolean

Is the current instance of Client authenticated as a Wikibase user?

Returns:

  • (Boolean)


333
334
335
336
337
# File 'lib/wikidatum/client.rb', line 333

def authenticated?
  # TODO: Make it possible for this to be true once authentication
  #   is implemented.
  false
end

#bot?Boolean

Is the current instance of Client editing as a bot?

Returns:

  • (Boolean)


349
350
351
# File 'lib/wikidatum/client.rb', line 349

def bot?
  @bot
end

#delete_statement(id:, tags: [], comment: nil) ⇒ Boolean

Delete a statement from an item.

Examples:

wikidatum_client.delete_statement(
  id: 'Q123$4543523c-1d1d-1111-1e1e-11b11111b1f1',
  comment: "Deleting this statement because it's bad."
)

Parameters:

  • id (String)

    the ID of the statemnt being deleted.

  • tags (Array<String>) (defaults to: [])
  • comment (String, nil) (defaults to: nil)

Returns:

  • (Boolean)

    True if the request succeeded.

Raises:

  • (ArgumentError)


320
321
322
323
324
325
326
327
328
# File 'lib/wikidatum/client.rb', line 320

def delete_statement(id:, tags: [], comment: nil)
  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)

  response = delete_request("/statements/#{id}", tags: tags, comment: comment)

  puts JSON.pretty_generate(response) if ENV['DEBUG']

  response.success?
end

#item(id:) ⇒ Wikidatum::Item

Get an item from the Wikibase API based on its QID.

Examples:

wikidatum_client.item(id: 'Q123')
wikidatum_client.item(id: 123)
wikidatum_client.item(id: '123')

Parameters:

  • id (String, Integer)

    Either a string or integer representation of the item’s QID, e.g. ‘“Q123”`, `“123”`, or `123`.

Returns:

Raises:

  • (ArgumentError)


87
88
89
90
91
92
93
94
95
96
97
# File 'lib/wikidatum/client.rb', line 87

def item(id:)
  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)

  id = coerce_item_id(id)

  response = get_request("/entities/items/#{id}")

  puts JSON.pretty_generate(response) if ENV['DEBUG']

  Wikidatum::Item.marshal_load(response)
end

#statement(id:) ⇒ Wikidatum::Statement

Get a statement from the Wikibase API based on its ID.

Examples:

wikidatum_client.statement(id: 'Q123$f004ec2b-4857-3b69-b370-e8124f5bd3ac')

Parameters:

  • id (String)

    A string representation of the statement’s ID.

Returns:

Raises:

  • (ArgumentError)


106
107
108
109
110
111
112
113
114
# File 'lib/wikidatum/client.rb', line 106

def statement(id:)
  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)

  response = get_request("/statements/#{id}")

  puts JSON.pretty_generate(response) if ENV['DEBUG']

  Wikidatum::Statement.marshal_load(response)
end