wikidatum 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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::DataType
7
+ class Base
8
+ # Represents the type for this instance.
9
+ #
10
+ # Possible values for the `type` attribute are:
11
+ #
12
+ # - `:no_value`: No value
13
+ # - `:some_value`: Unknown value
14
+ # - `:globe_coordinate`: {DataType::GlobeCoordinate}
15
+ # - `:monolingual_text`: {DataType::MonolingualText}
16
+ # - `:quantity`: {DataType::Quantity}
17
+ # - `:string`: {DataType::WikibaseString}
18
+ # - `:time`: {DataType::Time}
19
+ # - `:wikibase_item`: {DataType::WikibaseItem}
20
+ #
21
+ # @return [Symbol]
22
+ attr_reader :type
23
+
24
+ # The value of the "content" attribute in the response.
25
+ #
26
+ # If the `type` is `novalue` or `somevalue`, this returns `nil`.
27
+ #
28
+ # @return [DataType::GlobeCoordinate, DataType::MonolingualText, DataType::Quantity, DataType::WikibaseString, DataType::Time, DataType::WikibaseItem, nil]
29
+ attr_reader :content
30
+
31
+ # @param type [Symbol]
32
+ # @param content [DataType::GlobeCoordinate, DataType::MonolingualText, DataType::Quantity, DataType::WikibaseString, DataType::Time, DataType::WikibaseItem, nil] nil if type is no_value or some_value
33
+ # @return [void]
34
+ def initialize(type:, content:)
35
+ @type = type
36
+ @content = content
37
+ end
38
+
39
+ # @return [Hash]
40
+ def to_h
41
+ {
42
+ type: @type,
43
+ content: @content&.to_h
44
+ }
45
+ end
46
+
47
+ # @!visibility private
48
+ #
49
+ # @param data_type [String] The value of `data-type` for the given Statement or Qualifier's property.
50
+ # @param data_value_json [Hash] The `content` part of value object.
51
+ # @return [Wikidatum::DataType::Base] An instance of Base.
52
+ def self.marshal_load(data_type, data_value_json)
53
+ unless Wikidatum::DataType::DATA_TYPES.keys.include?(data_type.to_sym)
54
+ puts "WARNING: Unsupported data type (#{data_type})"
55
+ return nil
56
+ end
57
+
58
+ Object.const_get(Wikidatum::DataType::DATA_TYPES[data_type.to_sym]).marshal_load(data_value_json)
59
+ end
60
+ end
61
+ end
@@ -1,23 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wikidatum/data_value_type/base'
3
+ require 'wikidatum/data_type/base'
4
4
 
5
- # The Globe Coordinate type datavalue JSON looks like this:
5
+ # The Globe Coordinate type JSON looks like this:
6
6
  #
7
7
  # ```json
8
8
  # {
9
- # "datavalue": {
10
- # "value": {
11
- # "latitude": 52.516666666667,
12
- # "longitude": 13.383333333333,
13
- # "precision": 0.016666666666667,
9
+ # "property": {
10
+ # "id": "P740",
11
+ # "data-type": "globe-coordinate"
12
+ # },
13
+ # "value": {
14
+ # "type": "value",
15
+ # "content": {
16
+ # "latitude": 38.8977,
17
+ # "longitude": -77.0365,
18
+ # "precision": 0.0001,
14
19
  # "globe": "http://www.wikidata.org/entity/Q2"
15
- # },
16
- # "type": "globecoordinate"
20
+ # }
17
21
  # }
18
22
  # }
19
23
  # ```
20
- class Wikidatum::DataValueType::GlobeCoordinate
24
+ class Wikidatum::DataType::GlobeCoordinate
21
25
  # @return [Float]
22
26
  attr_reader :latitude
23
27
 
@@ -56,22 +60,19 @@ class Wikidatum::DataValueType::GlobeCoordinate
56
60
  #
57
61
  # @return [String]
58
62
  def wikibase_type
59
- 'globecoordinate'
63
+ 'globe-coordinate'
60
64
  end
61
65
 
62
- # The "datatype" value used by Wikibase, usually identical to wikibase_type
63
- # but not always.
64
- #
65
- # @return [String]
66
- def wikibase_datatype
67
- 'globe-coordinate' # yes, really
66
+ # @return [Symbol]
67
+ def self.symbolized_name
68
+ :monolingual_text
68
69
  end
69
70
 
70
71
  # @!visibility private
71
72
  def self.marshal_load(data_value_json)
72
- Wikidatum::DataValueType::Base.new(
73
- type: :globe_coordinate,
74
- value: new(
73
+ Wikidatum::DataType::Base.new(
74
+ type: symbolized_name,
75
+ content: new(
75
76
  latitude: data_value_json['latitude'],
76
77
  longitude: data_value_json['longitude'],
77
78
  precision: data_value_json['precision'],
@@ -1,21 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wikidatum/data_value_type/base'
3
+ require 'wikidatum/data_type/base'
4
4
 
5
- # The Monolingual Text type datavalue JSON looks like this:
5
+ # The Monolingual Text type JSON looks like this:
6
6
  #
7
7
  # ```json
8
8
  # {
9
- # "datavalue": {
10
- # "value": {
11
- # "text": "South Pole Telescope eyes birth of first massive galaxies",
12
- # "language": "en"
13
- # },
14
- # "type": "monolingualtext"
9
+ # "property": {
10
+ # "id": "P13432",
11
+ # "data-type": "monolingualtext"
12
+ # },
13
+ # "value": {
14
+ # "type": "value",
15
+ # "content": {
16
+ # "text": "foo",
17
+ # "language": "en-gb"
18
+ # }
15
19
  # }
16
20
  # }
17
21
  # ```
18
- class Wikidatum::DataValueType::MonolingualText
22
+ class Wikidatum::DataType::MonolingualText
19
23
  # @return [String] the language code, e.g. 'en'
20
24
  attr_reader :language
21
25
 
@@ -45,19 +49,16 @@ class Wikidatum::DataValueType::MonolingualText
45
49
  'monolingualtext'
46
50
  end
47
51
 
48
- # The "datatype" value used by Wikibase, usually identical to wikibase_type
49
- # but not always.
50
- #
51
- # @return [String]
52
- def wikibase_datatype
53
- wikibase_type
52
+ # @return [Symbol]
53
+ def self.symbolized_name
54
+ :monolingual_text
54
55
  end
55
56
 
56
57
  # @!visibility private
57
58
  def self.marshal_load(data_value_json)
58
- Wikidatum::DataValueType::Base.new(
59
- type: :monolingual_text,
60
- value: new(
59
+ Wikidatum::DataType::Base.new(
60
+ type: symbolized_name,
61
+ content: new(
61
62
  language: data_value_json['language'],
62
63
  text: data_value_json['text']
63
64
  )
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wikidatum/data_value_type/base'
3
+ require 'wikidatum/data_type/base'
4
4
 
5
5
  # The NoValue type actually has no datavalue key in the blob at all. We work
6
6
  # around this by just passing nil to the serializer.
7
7
 
8
8
  # Represents "no value".
9
- class Wikidatum::DataValueType::NoValue < Wikidatum::DataValueType::Base
9
+ class Wikidatum::DataType::NoValue < Wikidatum::DataType::Base
10
10
  # The "type" value used by Wikibase, for use when creating/updating statements.
11
11
  #
12
12
  # @return [String]
@@ -14,16 +14,8 @@ class Wikidatum::DataValueType::NoValue < Wikidatum::DataValueType::Base
14
14
  'string'
15
15
  end
16
16
 
17
- # The "datatype" value used by Wikibase, usually identical to wikibase_type
18
- # but not always.
19
- #
20
- # @return [String]
21
- def wikibase_datatype
22
- wikibase_type
23
- end
24
-
25
17
  # @!visibility private
26
18
  def self.marshal_load(_data_value_json)
27
- new(type: :no_value, value: nil)
19
+ new(type: :no_value, content: nil)
28
20
  end
29
21
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wikidatum/data_type/base'
4
+
5
+ # The Quantity type JSON looks like this:
6
+ #
7
+ # ```json
8
+ # {
9
+ # "property": {
10
+ # "id": "P937",
11
+ # "data-type": "quantity"
12
+ # },
13
+ # "value": {
14
+ # "type": "value",
15
+ # "content": {
16
+ # "amount": "+15",
17
+ # "unit": "1"
18
+ # }
19
+ # }
20
+ # }
21
+ # ```
22
+ class Wikidatum::DataType::Quantity
23
+ # @return [String] A string value like "+2", usually an integer but not always.
24
+ attr_reader :amount
25
+
26
+ # @return [String] a URL describing the unit for this quantity, e.g. "meter", "kilometer", "pound", "chapter", "section", etc.
27
+ attr_reader :unit
28
+
29
+ # @param amount [String]
30
+ # @param unit [String]
31
+ # @return [void]
32
+ def initialize(amount:, unit:)
33
+ @amount = amount
34
+ @unit = unit
35
+ end
36
+
37
+ # @return [Hash]
38
+ def to_h
39
+ {
40
+ amount: @amount,
41
+ unit: @unit
42
+ }
43
+ end
44
+
45
+ # The "type" value used by Wikibase, for use when creating/updating statements.
46
+ #
47
+ # @return [String]
48
+ def wikibase_type
49
+ 'quantity'
50
+ end
51
+
52
+ # @return [Symbol]
53
+ def self.symbolized_name
54
+ :quantity
55
+ end
56
+
57
+ # @!visibility private
58
+ def self.marshal_load(data_value_json)
59
+ Wikidatum::DataType::Base.new(
60
+ type: symbolized_name,
61
+ content: new(
62
+ amount: data_value_json['amount'],
63
+ unit: data_value_json['unit']
64
+ )
65
+ )
66
+ end
67
+
68
+ # @!visibility private
69
+ def marshal_dump
70
+ {
71
+ amount: @amount,
72
+ unit: @unit
73
+ }
74
+ end
75
+ end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wikidatum/data_value_type/base'
3
+ require 'wikidatum/data_type/base'
4
4
 
5
5
  # The SomeValue type actually has no datavalue key in the blob at all. We work
6
6
  # around this by just passing nil to the serializer.
7
7
 
8
8
  # Represents a value of "unknown value".
9
- class Wikidatum::DataValueType::SomeValue < Wikidatum::DataValueType::Base
9
+ class Wikidatum::DataType::SomeValue < Wikidatum::DataType::Base
10
10
  # The "type" value used by Wikibase, for use when creating/updating statements.
11
11
  #
12
12
  # @return [String]
@@ -14,16 +14,8 @@ class Wikidatum::DataValueType::SomeValue < Wikidatum::DataValueType::Base
14
14
  'string'
15
15
  end
16
16
 
17
- # The "datatype" value used by Wikibase, usually identical to wikibase_type
18
- # but not always.
19
- #
20
- # @return [String]
21
- def wikibase_datatype
22
- wikibase_type
23
- end
24
-
25
17
  # @!visibility private
26
18
  def self.marshal_load(_data_value_json)
27
- new(type: :some_value, value: nil)
19
+ new(type: :some_value, content: nil)
28
20
  end
29
21
  end
@@ -1,33 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wikidatum/data_value_type/base'
3
+ require 'wikidatum/data_type/base'
4
4
 
5
- # The time type datavalue JSON looks like this:
5
+ # The time type JSON looks like this:
6
6
  #
7
7
  # ```json
8
8
  # {
9
- # "datavalue": {
10
- # "value": {
9
+ # "property": {
10
+ # "id": "P761",
11
+ # "data-type": "time"
12
+ # },
13
+ # "value": {
14
+ # "type": "value",
15
+ # "content": {
11
16
  # "time": "+2019-11-14T00:00:00Z",
12
- # "timezone": 0,
13
- # "before": 0,
14
- # "after": 0,
15
17
  # "precision": 11,
16
18
  # "calendarmodel": "http://www.wikidata.org/entity/Q1985727"
17
- # },
18
- # "type": "time"
19
+ # }
19
20
  # }
20
21
  # }
21
22
  # ```
22
23
  #
23
- # We do not include before and after because the documentation states that
24
- # they're unused and "may be removed in the future".
25
- #
26
- # NOTE: For consistency with Ruby snake_case attribute names, `timezone` from
27
- # the API is represented as `time_zone` and `calendarmodel` is
28
- # `calendar_model`. However, we expose aliases so `timezone` and
24
+ # NOTE: For consistency with Ruby snake_case attribute names, `calendarmodel`
25
+ # in the API is `calendar_model`. However, we expose an alias so
29
26
  # `calendarmodel` will still work.
30
- class Wikidatum::DataValueType::Time
27
+ class Wikidatum::DataType::Time
31
28
  # A string representing the time in a format that is very similar to ISO 8601.
32
29
  #
33
30
  # For example, here are what dates look like for the most common precisions:
@@ -48,11 +45,6 @@ class Wikidatum::DataValueType::Time
48
45
  # @return [String] the time value, in a format like "+2022-01-01T00:00:00Z", though how this should be interpreted depends on the precision.
49
46
  attr_reader :time
50
47
 
51
- # @return [Integer] an integer for the offset (in minutes) from UTC. 0 means
52
- # UTC, will currently always be 0 but the Wikibase backend may change that
53
- # in the future.
54
- attr_reader :time_zone
55
-
56
48
  # An integer representing the precision of the date, where the integers correspond to the following:
57
49
  #
58
50
  # - 0: 1 Gigayear
@@ -91,13 +83,11 @@ class Wikidatum::DataValueType::Time
91
83
  attr_reader :calendar_model
92
84
 
93
85
  # @param time [String]
94
- # @param time_zone [Integer]
95
86
  # @param precision [Integer]
96
87
  # @param calendar_model [String]
97
88
  # @return [void]
98
- def initialize(time:, time_zone:, precision:, calendar_model:)
89
+ def initialize(time:, precision:, calendar_model:)
99
90
  @time = time
100
- @time_zone = time_zone
101
91
  @precision = precision
102
92
  @calendar_model = calendar_model
103
93
  end
@@ -106,7 +96,6 @@ class Wikidatum::DataValueType::Time
106
96
  def to_h
107
97
  {
108
98
  time: @time,
109
- time_zone: @time_zone,
110
99
  precision: @precision,
111
100
  pretty_precision: pretty_precision,
112
101
  calendar_model: @calendar_model
@@ -120,21 +109,17 @@ class Wikidatum::DataValueType::Time
120
109
  'time'
121
110
  end
122
111
 
123
- # The "datatype" value used by Wikibase, usually identical to wikibase_type
124
- # but not always.
125
- #
126
- # @return [String]
127
- def wikibase_datatype
128
- wikibase_type
112
+ # @return [Symbol]
113
+ def self.symbolized_name
114
+ :time
129
115
  end
130
116
 
131
117
  # @!visibility private
132
118
  def self.marshal_load(data_value_json)
133
- Wikidatum::DataValueType::Base.new(
134
- type: :time,
135
- value: new(
119
+ Wikidatum::DataType::Base.new(
120
+ type: symbolized_name,
121
+ content: new(
136
122
  time: data_value_json['time'],
137
- time_zone: data_value_json['timezone'],
138
123
  precision: data_value_json['precision'],
139
124
  calendar_model: data_value_json['calendarmodel']
140
125
  )
@@ -145,7 +130,6 @@ class Wikidatum::DataValueType::Time
145
130
  def marshal_dump
146
131
  {
147
132
  time: @time,
148
- timezone: @time_zone,
149
133
  precision: @precision,
150
134
  calendarmodel: @calendar_model
151
135
  }
@@ -182,6 +166,5 @@ class Wikidatum::DataValueType::Time
182
166
 
183
167
  # Aliases to match the name returned by the REST API.
184
168
 
185
- alias timezone time_zone
186
169
  alias calendarmodel calendar_model
187
170
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wikidatum/data_type/base'
4
+
5
+ # The Wikibase Item type JSON looks like this:
6
+ #
7
+ # ```json
8
+ # {
9
+ # "property": {
10
+ # "id": "P963",
11
+ # "data-type": "wikibase-item"
12
+ # },
13
+ # "value": {
14
+ # "type": "value",
15
+ # "content": "Q524026"
16
+ # }
17
+ # }
18
+ # ```
19
+ class Wikidatum::DataType::WikibaseItem
20
+ # @return [String] in the format "Q123".
21
+ attr_reader :id
22
+
23
+ # @param id [String]
24
+ # @return [void]
25
+ def initialize(id:)
26
+ @id = id
27
+ end
28
+
29
+ # @return [Hash]
30
+ def to_h
31
+ {
32
+ id: @id
33
+ }
34
+ end
35
+
36
+ # The "type" value used by Wikibase, for use when creating/updating statements.
37
+ #
38
+ # @return [String]
39
+ def wikibase_type
40
+ 'wikibase-item'
41
+ end
42
+
43
+ # @return [Symbol]
44
+ def self.symbolized_name
45
+ :wikibase_item
46
+ end
47
+
48
+ # @!visibility private
49
+ def self.marshal_load(id)
50
+ Wikidatum::DataType::Base.new(
51
+ type: symbolized_name,
52
+ content: new(
53
+ id: id
54
+ )
55
+ )
56
+ end
57
+
58
+ # @!visibility private
59
+ def marshal_dump
60
+ {
61
+ id: @id
62
+ }
63
+ end
64
+ end
@@ -1,18 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wikidatum/data_value_type/base'
3
+ require 'wikidatum/data_type/base'
4
4
 
5
- # The String type datavalue JSON looks like this:
5
+ # The String type JSON looks like this:
6
6
  #
7
7
  # ```json
8
8
  # {
9
- # "datavalue": {
10
- # "value": "Foobar",
11
- # "type": "string"
9
+ # "property": {
10
+ # "id": "P143",
11
+ # "data-type": "string"
12
+ # },
13
+ # "value": {
14
+ # "type": "value",
15
+ # "content": "foo"
12
16
  # }
13
17
  # }
14
18
  # ```
15
- class Wikidatum::DataValueType::WikibaseString
19
+ class Wikidatum::DataType::WikibaseString
16
20
  # @return [String] the value for the string.
17
21
  attr_reader :string
18
22
 
@@ -36,19 +40,16 @@ class Wikidatum::DataValueType::WikibaseString
36
40
  'string'
37
41
  end
38
42
 
39
- # The "datatype" value used by Wikibase, usually identical to wikibase_type
40
- # but not always.
41
- #
42
- # @return [String]
43
- def wikibase_datatype
44
- wikibase_type
43
+ # @return [Symbol]
44
+ def self.symbolized_name
45
+ :string
45
46
  end
46
47
 
47
48
  # @!visibility private
48
49
  def self.marshal_load(string)
49
- Wikidatum::DataValueType::Base.new(
50
- type: :string,
51
- value: new(
50
+ Wikidatum::DataType::Base.new(
51
+ type: symbolized_name,
52
+ content: new(
52
53
  string: string
53
54
  )
54
55
  )
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wikidatum/data_type/base'
4
+ require 'wikidatum/data_type/globe_coordinate'
5
+ require 'wikidatum/data_type/monolingual_text'
6
+ require 'wikidatum/data_type/no_value'
7
+ require 'wikidatum/data_type/quantity'
8
+ require 'wikidatum/data_type/some_value'
9
+ require 'wikidatum/data_type/time'
10
+ require 'wikidatum/data_type/wikibase_item'
11
+ require 'wikidatum/data_type/wikibase_string'
@@ -186,8 +186,8 @@ class Wikidatum::Item
186
186
  statements = item_json['statements'].to_a.flat_map do |_property_id, st_arr|
187
187
  st_arr.map { |statement| Wikidatum::Statement.marshal_load(statement) }
188
188
  end
189
- sitelinks = item_json['sitelinks'].to_a.map do |_name, sitelink|
190
- Wikidatum::Sitelink.new(site: sitelink['site'], title: sitelink['title'], badges: sitelink['badges'])
189
+ sitelinks = item_json['sitelinks'].to_a.map do |site, sitelink|
190
+ Wikidatum::Sitelink.new(site: site, title: sitelink['title'], badges: sitelink['badges'])
191
191
  end
192
192
 
193
193
  Wikidatum::Item.new(
@@ -1,7 +1,55 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'wikidatum/snak'
3
+ class Wikidatum::Qualifier
4
+ # @return [String] ID of the property for this Qualifier, in the format 'P123'.
5
+ attr_reader :property_id
4
6
 
5
- # Wikidatum::Qualifier is actually just an alias for snak, because qualifiers
6
- # are effectively just snaks.
7
- Wikidatum::Qualifier = Wikidatum::Snak
7
+ # @return [String]
8
+ attr_reader :data_type
9
+
10
+ # For more information on the possible types that can be returned by
11
+ # datavalues, see the official documentation:
12
+ # https://doc.wikimedia.org/Wikibase/master/php/md_docs_topics_json.html#json_datavalues
13
+ #
14
+ # @return [Wikidatum::DataType::Base] the value of the statement, can take various forms
15
+ attr_reader :value
16
+
17
+ # @!visibility private
18
+ # @param property_id [String] ID of the property for this Qualifier, in the format 'P123'.
19
+ # @param data_type [String]
20
+ # @param value [DataType::GlobeCoordinate, DataType::MonolingualText, DataType::Quantity, DataType::WikibaseString, DataType::Time, DataType::WikibaseItem, DataType::NoValue, DataType::SomeValue]
21
+ def initialize(property_id:, data_type:, value:)
22
+ @property_id = property_id
23
+ @data_type = data_type
24
+ @value = value
25
+ end
26
+
27
+ # @return [Hash]
28
+ def to_h
29
+ {
30
+ property_id: @property_id,
31
+ data_type: @data_type,
32
+ value: @value.to_h
33
+ }
34
+ end
35
+
36
+ # @return [String]
37
+ def inspect
38
+ "<Wikidatum::Qualifier property_id=#{@property_id.inspect} data_type=#{@data_type.inspect} value=#{@value.inspect}>"
39
+ end
40
+
41
+ # @!visibility private
42
+ #
43
+ # This takes in the JSON blob (as a hash) that is output for a given
44
+ # qualifier the API and turns it into an actual instance of a Qualifier.
45
+ #
46
+ # @param qualifier_json [Hash]
47
+ # @return [Wikidatum::Qualifier]
48
+ def self.marshal_load(qualifier_json)
49
+ Wikidatum::Qualifier.new(
50
+ property_id: qualifier_json.dig('property', 'id'),
51
+ data_type: qualifier_json.dig('property', 'data-type'),
52
+ value: Wikidatum::Utils.ingest_snak(qualifier_json)
53
+ )
54
+ end
55
+ end