reality 0.0.3 → 0.0.4
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/.yardopts +2 -0
- data/CHANGELOG.md +20 -0
- data/README.md +104 -407
- data/bin/reality +7 -10
- data/config/demo.yml +1 -0
- data/lib/reality.rb +11 -6
- data/lib/reality/command_line.rb +124 -0
- data/lib/reality/config.rb +10 -3
- data/lib/reality/definitions/helpers.rb +1 -0
- data/lib/reality/definitions/wikidata.rb +10 -1
- data/lib/reality/definitions/wikipedia_character.rb +1 -0
- data/lib/reality/definitions/wikipedia_city.rb +1 -0
- data/lib/reality/definitions/wikipedia_continent.rb +1 -0
- data/lib/reality/definitions/wikipedia_country.rb +1 -0
- data/lib/reality/definitions/wikipedia_musical_artist.rb +1 -0
- data/lib/reality/definitions/wikipedia_person.rb +1 -0
- data/lib/reality/entity.rb +239 -51
- data/lib/reality/entity/coercion.rb +20 -0
- data/lib/reality/entity/wikidata_predicates.rb +1 -0
- data/lib/reality/entity/wikipedia_type.rb +1 -0
- data/lib/reality/extras/geonames.rb +5 -3
- data/lib/reality/extras/quandl.rb +57 -0
- data/lib/reality/geo.rb +67 -6
- data/lib/reality/list.rb +76 -6
- data/lib/reality/measure.rb +17 -9
- data/lib/reality/methods.rb +7 -3
- data/lib/reality/names.rb +46 -0
- data/lib/reality/refinements.rb +1 -0
- data/lib/reality/tz_offset.rb +57 -4
- data/lib/reality/util/formatters.rb +1 -0
- data/lib/reality/util/parsers.rb +1 -0
- data/lib/reality/version.rb +1 -1
- data/lib/reality/wikidata.rb +25 -177
- data/lib/reality/wikidata/query.rb +106 -0
- data/reality.gemspec +5 -7
- metadata +20 -56
data/lib/reality/methods.rb
CHANGED
@@ -2,12 +2,16 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
module Reality
|
4
4
|
module Methods
|
5
|
-
def Entity(name
|
6
|
-
Entity.load(name
|
5
|
+
def Entity(name)
|
6
|
+
Entity.load(name)
|
7
7
|
end
|
8
8
|
|
9
9
|
def List(*names)
|
10
|
-
|
10
|
+
List.new(*names)
|
11
|
+
end
|
12
|
+
|
13
|
+
def Measure(*arg)
|
14
|
+
Measure.new(*arg)
|
11
15
|
end
|
12
16
|
|
13
17
|
extend Forwardable
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Reality
|
2
|
+
# This optional and higly experimental module allows treat ALL objects
|
3
|
+
# available with Reality, as Ruby constants (via redefined `const_missing`).
|
4
|
+
# This practice may seem questionable, so use it wisely!
|
5
|
+
#
|
6
|
+
# You can just use this module on its own:
|
7
|
+
#
|
8
|
+
# ```ruby
|
9
|
+
# Reality::Names::Argentina
|
10
|
+
# # => #<Reality::Entity(Argentina):country>
|
11
|
+
# ```
|
12
|
+
#
|
13
|
+
# ...Or just include it elsewhere:
|
14
|
+
#
|
15
|
+
# ```ruby
|
16
|
+
# include Reality::Names
|
17
|
+
#
|
18
|
+
# Argentina
|
19
|
+
# # => #<Reality::Entity(Argentina):country>
|
20
|
+
# ```
|
21
|
+
#
|
22
|
+
# Multi-word entities can also be called:
|
23
|
+
#
|
24
|
+
# ```ruby
|
25
|
+
# BuenosAires
|
26
|
+
# # => #<Reality::Entity(Buenos Aires):city>
|
27
|
+
# ```
|
28
|
+
#
|
29
|
+
# Though, more complicated entity names (with punctuations) can't be
|
30
|
+
# accessed this way.
|
31
|
+
#
|
32
|
+
module Names
|
33
|
+
def Names.const_missing(symbol)
|
34
|
+
name = symbol.to_s.
|
35
|
+
gsub('_', ' ').
|
36
|
+
gsub(/([a-z])([A-Z])/, '\1 \2')
|
37
|
+
Reality::Entity(name) or super
|
38
|
+
end
|
39
|
+
|
40
|
+
def Names.included(other)
|
41
|
+
other.define_singleton_method(:const_missing){|name|
|
42
|
+
Reality::Names.const_missing(name)
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/reality/refinements.rb
CHANGED
data/lib/reality/tz_offset.rb
CHANGED
@@ -1,11 +1,46 @@
|
|
1
1
|
module Reality
|
2
|
+
# Simple class representing timezone offset (in minutes). Knows nothing
|
3
|
+
# about timezone name, DST or other complications, but useful when ONLY
|
4
|
+
# offset is known for some {Entity}.
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# ```ruby
|
9
|
+
# # As entity property:
|
10
|
+
# Reality::Entity('Beijing').tz_offset
|
11
|
+
# # => #<Reality::TZOffset(UTC+08:00)>
|
12
|
+
#
|
13
|
+
# # On itself:
|
14
|
+
# o = Reality::TZOffset.parse('UTC+3')
|
15
|
+
# # => #<Reality::TZOffset(UTC+03:00)>
|
16
|
+
#
|
17
|
+
# o.now
|
18
|
+
# # => 2016-04-16 19:01:40 +0300
|
19
|
+
# o.local(2016, 4, 1, 20, 30)
|
20
|
+
# # => 2016-04-01 20:30:00 +0300
|
21
|
+
# o.convert(Time.now)
|
22
|
+
# # => 2016-04-16 19:02:22 +0300
|
23
|
+
# ```
|
24
|
+
#
|
2
25
|
class TZOffset
|
3
26
|
using Refinements
|
4
|
-
|
27
|
+
|
28
|
+
# Number of minutes in offset.
|
29
|
+
#
|
30
|
+
# @return [Fixnum]
|
5
31
|
attr_reader :minutes
|
6
32
|
|
33
|
+
# @private
|
7
34
|
MINUSES = /[−—–]/
|
8
35
|
|
36
|
+
# Parses TZOffset from string. Understands several options like:
|
37
|
+
#
|
38
|
+
# * `GMT` (not all TZ names, only those Ruby itself knows about);
|
39
|
+
# * `UTC+3` (or `GMT+3`);
|
40
|
+
# * `+03:30`;
|
41
|
+
# * ..and several combinations.
|
42
|
+
#
|
43
|
+
# @return [TZOffset]
|
9
44
|
def self.parse(text)
|
10
45
|
text = text.gsub(MINUSES, '-')
|
11
46
|
|
@@ -13,24 +48,32 @@ module Reality
|
|
13
48
|
when /^[A-Z]{3}$/
|
14
49
|
Time.zone_offset(text)
|
15
50
|
when /^(?:UTC|GMT)?([+-]\d{1,2}:?\d{2})$/
|
16
|
-
|
51
|
+
offset = $1
|
52
|
+
Time.zone_offset(offset.sub(/^([+-])(\d):/, '\10\2:'))
|
17
53
|
when /^(?:UTC|GMT)?([+-]\d{1,2})/
|
18
54
|
$1.to_i * 3600
|
19
55
|
end.derp{|sec| sec && new(sec / 60)}
|
20
56
|
end
|
21
|
-
|
57
|
+
|
58
|
+
# Constructs offset from number of minutes. In most cases, you don't
|
59
|
+
# want to use it, but rather {TZOffset.parse}.
|
60
|
+
#
|
61
|
+
# @param minutes [Fixnum] Number of minutes in offset.
|
22
62
|
def initialize(minutes)
|
23
63
|
@minutes = minutes
|
24
64
|
end
|
25
65
|
|
66
|
+
# @return [String]
|
26
67
|
def inspect
|
27
68
|
'#<%s(UTC%+03i:%02i)>' % [self.class.name, *minutes.divmod(60)]
|
28
69
|
end
|
29
70
|
|
71
|
+
# @return [String]
|
30
72
|
def to_s
|
31
73
|
'%+03i:%02i' % minutes.divmod(60)
|
32
74
|
end
|
33
75
|
|
76
|
+
# @return [Boolean]
|
34
77
|
def <=>(other)
|
35
78
|
other.is_a?(TZOffset) or fail ArgumentError, "Can't compare TZOffset with #{other.class}"
|
36
79
|
minutes <=> other.minutes
|
@@ -38,18 +81,28 @@ module Reality
|
|
38
81
|
|
39
82
|
include Comparable
|
40
83
|
|
84
|
+
# Like Ruby's `Time.now`, but in desired offset.
|
85
|
+
#
|
86
|
+
# @return [Time] Current time in that offset.
|
41
87
|
def now
|
42
88
|
convert(Time.now)
|
43
89
|
end
|
44
90
|
|
91
|
+
# Like Ruby's `Time.local`, but in desired offset.
|
92
|
+
#
|
93
|
+
# @return [Time] Constructed time in that offset.
|
45
94
|
def local(*values)
|
46
95
|
values << 0 until values.count == 6
|
47
96
|
Time.new(*values, to_s)
|
48
97
|
end
|
49
98
|
|
50
|
-
#
|
99
|
+
# Converts `tm` into correct offset.
|
100
|
+
#
|
101
|
+
# @param tm [Time] Time object to convert (with any offset);
|
102
|
+
# @return [Time] Converted object.
|
51
103
|
def convert(tm)
|
52
104
|
pattern = tm.utc + minutes * 60
|
105
|
+
# FIXME: usec are lost
|
53
106
|
Time.new(
|
54
107
|
pattern.year,
|
55
108
|
pattern.month,
|
data/lib/reality/util/parsers.rb
CHANGED
data/lib/reality/version.rb
CHANGED
data/lib/reality/wikidata.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require_relative 'wikidata/query'
|
2
|
+
|
1
3
|
module Reality
|
2
4
|
using Reality::Refinements
|
3
|
-
|
5
|
+
|
6
|
+
# @private
|
4
7
|
module Wikidata
|
5
8
|
class Link
|
6
9
|
attr_reader :id, :label
|
@@ -18,198 +21,38 @@ module Reality
|
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
21
|
-
# FIXME: I should be burn in hell for this mess. But it works. Somehow.
|
22
24
|
class Entity
|
23
|
-
PREFIX = %Q{
|
24
|
-
PREFIX wikibase: <http://wikiba.se/ontology#>
|
25
|
-
PREFIX wd: <http://www.wikidata.org/entity/>
|
26
|
-
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
|
27
|
-
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
28
|
-
PREFIX p: <http://www.wikidata.org/prop/>
|
29
|
-
PREFIX v: <http://www.wikidata.org/prop/statement/>
|
30
|
-
PREFIX schema: <http://schema.org/>
|
31
|
-
}
|
32
|
-
|
33
|
-
SINGLE_QUERY = %Q{
|
34
|
-
#{PREFIX}
|
35
|
-
|
36
|
-
SELECT ?id ?p ?o ?oLabel WHERE {
|
37
|
-
<https://en.wikipedia.org/wiki/%{title}> schema:about ?id .
|
38
|
-
{
|
39
|
-
?id ?p ?o .
|
40
|
-
FILTER(STRSTARTS(STR(?p), "http://www.wikidata.org/prop/direct/"))
|
41
|
-
} union {
|
42
|
-
?id ?p ?o .
|
43
|
-
filter(langMatches(lang(?o), "EN")).
|
44
|
-
filter(?p = rdfs:label)
|
45
|
-
}
|
46
|
-
SERVICE wikibase:label {
|
47
|
-
bd:serviceParam wikibase:language "en" .
|
48
|
-
}
|
49
|
-
}
|
50
|
-
}
|
51
|
-
|
52
|
-
ID_QUERY = %Q{
|
53
|
-
#{PREFIX}
|
54
|
-
|
55
|
-
SELECT ?id ?p ?o ?oLabel WHERE {
|
56
|
-
bind(wd:%{id} as ?id)
|
57
|
-
{
|
58
|
-
?id ?p ?o .
|
59
|
-
FILTER(
|
60
|
-
STRSTARTS(STR(?p), "http://www.wikidata.org/prop/direct/") ||
|
61
|
-
(?p = rdfs:label && langMatches(lang(?o), "EN"))
|
62
|
-
)
|
63
|
-
} union {
|
64
|
-
bind(schema:about as ?p) .
|
65
|
-
?o schema:about ?id .
|
66
|
-
filter(strstarts(str(?o), "https://en.wikipedia.org/wiki/"))
|
67
|
-
}
|
68
|
-
SERVICE wikibase:label {
|
69
|
-
bd:serviceParam wikibase:language "en" .
|
70
|
-
}
|
71
|
-
}
|
72
|
-
}
|
73
|
-
|
74
|
-
MULTIPLE_QUERY = %Q{
|
75
|
-
#{PREFIX}
|
76
|
-
|
77
|
-
SELECT ?id ?p ?o ?oLabel WHERE {
|
78
|
-
%{selectors} .
|
79
|
-
{
|
80
|
-
?id ?p ?o .
|
81
|
-
FILTER(
|
82
|
-
STRSTARTS(STR(?p), "http://www.wikidata.org/prop/direct/") ||
|
83
|
-
(?p = rdfs:label && langMatches(lang(?o), "EN"))
|
84
|
-
)
|
85
|
-
} union {
|
86
|
-
bind(schema:about as ?p) .
|
87
|
-
?o schema:about ?id .
|
88
|
-
filter(strstarts(str(?o), "https://en.wikipedia.org/wiki/"))
|
89
|
-
}
|
90
|
-
SERVICE wikibase:label {
|
91
|
-
bd:serviceParam wikibase:language "en" .
|
92
|
-
}
|
93
|
-
}
|
94
|
-
}
|
95
|
-
MULTIPLE_IDS_QUERY = %Q{
|
96
|
-
#{PREFIX}
|
97
|
-
|
98
|
-
SELECT ?id ?p ?o ?oLabel WHERE {
|
99
|
-
%{selectors} .
|
100
|
-
{
|
101
|
-
?id ?p ?o .
|
102
|
-
FILTER(
|
103
|
-
STRSTARTS(STR(?p), "http://www.wikidata.org/prop/direct/") ||
|
104
|
-
(?p = rdfs:label && langMatches(lang(?o), "EN"))
|
105
|
-
)
|
106
|
-
} union {
|
107
|
-
bind(schema:about as ?p) .
|
108
|
-
?o schema:about ?id .
|
109
|
-
filter(strstarts(str(?o), "https://en.wikipedia.org/wiki/"))
|
110
|
-
}
|
111
|
-
SERVICE wikibase:label {
|
112
|
-
bd:serviceParam wikibase:language "en" .
|
113
|
-
}
|
114
|
-
}
|
115
|
-
}
|
116
|
-
SELECTOR = %Q{
|
117
|
-
{
|
118
|
-
<https://en.wikipedia.org/wiki/%{title}> schema:about ?id
|
119
|
-
}
|
120
|
-
}
|
121
|
-
IDSELECTOR = %Q{
|
122
|
-
{
|
123
|
-
BIND(wd:%{id} as ?id)
|
124
|
-
}
|
125
|
-
}
|
126
|
-
|
127
|
-
UNSAFE = Regexp.union(URI::UNSAFE, /[,()']/)
|
128
|
-
|
129
25
|
class << self
|
130
|
-
def
|
131
|
-
|
132
|
-
f.adapter Faraday.default_adapter
|
133
|
-
}
|
26
|
+
def by_wikititle(*titles)
|
27
|
+
Query.by_wikititle(*titles)
|
134
28
|
end
|
135
29
|
|
136
|
-
def
|
137
|
-
|
138
|
-
faraday.get('', query: SINGLE_QUERY % {title: title}, format: :json).
|
139
|
-
derp{|res| from_sparql(res.body, subject: 'id', predicate: 'p', object: 'o', object_label: 'oLabel')}
|
30
|
+
def by_id(*ids)
|
31
|
+
Query.by_id(*ids)
|
140
32
|
end
|
141
33
|
|
142
|
-
def
|
143
|
-
|
144
|
-
derp{|res| from_sparql(res.body, subject: 'id', predicate: 'p', object: 'o', object_label: 'oLabel')}.
|
145
|
-
first
|
34
|
+
def by_label(*labels)
|
35
|
+
Query.by_label(*labels)
|
146
36
|
end
|
147
37
|
|
148
|
-
|
149
|
-
|
150
|
-
MAX_SLICE = 20
|
151
|
-
|
152
|
-
def fetch_list(*titles)
|
153
|
-
titles.each_slice(MAX_SLICE).map{|titles_chunk|
|
154
|
-
fetch_small_list(*titles_chunk)
|
155
|
-
}.inject(:merge)
|
38
|
+
def one_by_wikititle(title)
|
39
|
+
by_wikititle(title).values.first
|
156
40
|
end
|
157
41
|
|
158
|
-
def
|
159
|
-
|
160
|
-
fetch_small_idlist(*ids_chunk)
|
161
|
-
}.inject(:merge)
|
42
|
+
def one_by_id(id)
|
43
|
+
by_id(id).values.first
|
162
44
|
end
|
163
45
|
|
164
|
-
def
|
165
|
-
|
166
|
-
map{|t| SELECTOR % {title: URI.escape(t, UNSAFE)}}.
|
167
|
-
join(' UNION ').
|
168
|
-
derp{|selectors| MULTIPLE_QUERY % {selectors: selectors}}.
|
169
|
-
derp{|query|
|
170
|
-
faraday.get('', query: query, format: :json)
|
171
|
-
}.
|
172
|
-
derp{|res|
|
173
|
-
from_sparql(
|
174
|
-
res.body,
|
175
|
-
subject: 'id',
|
176
|
-
predicate: 'p',
|
177
|
-
object: 'o',
|
178
|
-
object_label: 'oLabel')
|
179
|
-
}.
|
180
|
-
map{|e|
|
181
|
-
[e.en_wikipage, e]
|
182
|
-
}.to_h
|
46
|
+
def one_by_label(label)
|
47
|
+
by_label(label).values.first
|
183
48
|
end
|
184
49
|
|
185
|
-
|
186
|
-
def fetch_small_idlist(*ids)
|
187
|
-
ids.
|
188
|
-
map{|i| IDSELECTOR % {id: i}}.
|
189
|
-
join(' UNION ').
|
190
|
-
derp{|selectors| MULTIPLE_IDS_QUERY % {selectors: selectors}}.
|
191
|
-
derp{|query|
|
192
|
-
faraday.get('', query: query, format: :json)
|
193
|
-
}.
|
194
|
-
derp{|res|
|
195
|
-
from_sparql(
|
196
|
-
res.body,
|
197
|
-
subject: 'id',
|
198
|
-
predicate: 'p',
|
199
|
-
object: 'o',
|
200
|
-
object_label: 'oLabel')
|
201
|
-
}.
|
202
|
-
map{|e|
|
203
|
-
[e.id, e]
|
204
|
-
}.to_h
|
205
|
-
end
|
206
|
-
|
207
|
-
def from_sparql(sparql_json, subject: 'subject', predicate: 'predicate', object: 'object', object_label: 'object_label')
|
50
|
+
def from_sparql(sparql_json)
|
208
51
|
JSON.parse(sparql_json)['results']['bindings'].map{|row|
|
209
52
|
[
|
210
|
-
row[
|
211
|
-
row[
|
212
|
-
row[
|
53
|
+
row['s']['value'].sub('http://www.wikidata.org/entity/', ''),
|
54
|
+
row['p']['value'].sub('http://www.wikidata.org/prop/direct/', ''),
|
55
|
+
row['o'].merge('label' => row['oLabel']['value'])
|
213
56
|
]
|
214
57
|
}.group_by(&:first).
|
215
58
|
map{|id, rows|
|
@@ -223,6 +66,7 @@ module Reality
|
|
223
66
|
to_h
|
224
67
|
end
|
225
68
|
|
69
|
+
# FIXME: move all parse_* to util/parsers or wikidata/parsers
|
226
70
|
def parse_value(hash)
|
227
71
|
case hash['type']
|
228
72
|
when 'literal'
|
@@ -278,6 +122,10 @@ module Reality
|
|
278
122
|
@predicates[pred]
|
279
123
|
end
|
280
124
|
|
125
|
+
def id_i
|
126
|
+
id.sub('Q', '').to_i
|
127
|
+
end
|
128
|
+
|
281
129
|
def label
|
282
130
|
self['http://www.w3.org/2000/01/rdf-schema#label'].first
|
283
131
|
end
|