reality 0.0.2 → 0.0.3
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/.dokaz +1 -0
- data/LICENSE.txt +22 -0
- data/README.md +538 -66
- data/bin/reality +9 -0
- data/config/demo.yml +3 -0
- data/data/wikidata-predicates.json +1 -0
- data/data/wikidata-predicates.yaml +2089 -0
- data/lib/reality.rb +26 -7
- data/lib/reality/config.rb +46 -0
- data/lib/reality/definitions/dictionaries.rb +67 -0
- data/lib/reality/definitions/helpers.rb +34 -0
- data/lib/reality/definitions/wikidata.rb +105 -0
- data/lib/reality/definitions/wikipedia_character.rb +17 -0
- data/lib/reality/definitions/wikipedia_city.rb +19 -0
- data/lib/reality/definitions/wikipedia_continent.rb +21 -0
- data/lib/reality/definitions/wikipedia_country.rb +23 -0
- data/lib/reality/definitions/wikipedia_musical_artist.rb +15 -0
- data/lib/reality/definitions/wikipedia_person.rb +17 -0
- data/lib/reality/entity.rb +152 -0
- data/lib/reality/entity/coercion.rb +76 -0
- data/lib/reality/entity/wikidata_predicates.rb +31 -0
- data/lib/reality/entity/wikipedia_type.rb +73 -0
- data/lib/reality/extras/geonames.rb +29 -0
- data/lib/reality/extras/open_weather_map.rb +63 -0
- data/lib/reality/geo.rb +122 -0
- data/lib/reality/infoboxer_templates.rb +8 -0
- data/lib/reality/list.rb +95 -0
- data/lib/reality/measure.rb +18 -12
- data/lib/reality/measure/unit.rb +5 -1
- data/lib/reality/methods.rb +16 -0
- data/lib/reality/pretty_inspect.rb +11 -0
- data/lib/reality/refinements.rb +26 -0
- data/lib/reality/shortcuts.rb +11 -0
- data/lib/reality/tz_offset.rb +64 -0
- data/lib/reality/util/formatters.rb +35 -0
- data/lib/reality/util/parsers.rb +53 -0
- data/lib/reality/version.rb +6 -0
- data/lib/reality/wikidata.rb +310 -0
- data/reality.gemspec +12 -3
- data/script/extract_wikidata_properties.rb +23 -0
- data/script/lib/nokogiri_more.rb +175 -0
- metadata +137 -7
- data/examples/all_countries.rb +0 -16
- data/lib/reality/country.rb +0 -283
data/lib/reality.rb
CHANGED
@@ -1,15 +1,34 @@
|
|
1
1
|
require 'infoboxer'
|
2
|
+
require 'yaml'
|
2
3
|
|
3
4
|
module Reality
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require_relative "reality/#{mod}"
|
5
|
+
def self.require_(*modules)
|
6
|
+
modules.flatten.flat_map{|pattern|
|
7
|
+
Dir[File.expand_path("../reality/#{pattern}.rb", __FILE__)]
|
8
|
+
}.each(&Kernel.method(:require))
|
9
9
|
end
|
10
10
|
|
11
|
+
# basic functionality
|
12
|
+
require_ %w[version refinements config measure geo tz_offset]
|
13
|
+
require_ %w[util/parsers util/formatters]
|
14
|
+
|
15
|
+
# engines
|
16
|
+
require_ %w[infoboxer_templates wikidata]
|
17
|
+
Infoboxer.user_agent = "Reality/#{VERSION} (https://github.com/molybdenum-99/reality; zverok.offline@gmail.com)"
|
18
|
+
|
11
19
|
# entities
|
12
|
-
%w[
|
13
|
-
|
20
|
+
require_ %w[entity list]
|
21
|
+
require_ %w[definitions/*]
|
22
|
+
require_ %w[methods]
|
23
|
+
|
24
|
+
extend Methods
|
25
|
+
|
26
|
+
def self.reload!
|
27
|
+
require_ %w[definitions/*]
|
14
28
|
end
|
29
|
+
|
30
|
+
# extras
|
31
|
+
require_ %w[extras/open_weather_map extras/geonames]
|
32
|
+
include Extras::OpenWeatherMap
|
33
|
+
include Extras::Geonames
|
15
34
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
module Reality
|
4
|
+
class Config
|
5
|
+
attr_reader :keys, :data
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@keys = {}
|
9
|
+
@data = {}.extend Hashie::Extensions::DeepFetch
|
10
|
+
end
|
11
|
+
|
12
|
+
def load(str)
|
13
|
+
if File.exists?(str)
|
14
|
+
str = File.read(str)
|
15
|
+
end
|
16
|
+
|
17
|
+
@data.update(YAML.load(str))
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch(*path)
|
21
|
+
data.deep_fetch(*path){
|
22
|
+
if (known = @keys[path])
|
23
|
+
fail KeyError, "Expected #{path.join('.')} to exist in config. It is #{known[:desc]}"
|
24
|
+
else
|
25
|
+
fail KeyError, "Expected #{path.join('.')} to exist in config."
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def register(*path, **opts)
|
31
|
+
@keys[path] = opts
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def Reality.config
|
36
|
+
@config ||= Config.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def Reality.configure(cfg)
|
40
|
+
if cfg == :demo
|
41
|
+
config.load(File.expand_path('../../../config/demo.yml', __FILE__))
|
42
|
+
else
|
43
|
+
config.load(cfg)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Reality
|
2
|
+
module Dictionaries
|
3
|
+
module_function
|
4
|
+
|
5
|
+
using Reality::Refinements
|
6
|
+
|
7
|
+
def countries
|
8
|
+
List.new(*countries_by_continents_cache.keys)
|
9
|
+
end
|
10
|
+
|
11
|
+
def continents
|
12
|
+
@continents ||=
|
13
|
+
Infoboxer.wp.get('Continent').
|
14
|
+
sections('Area and population').tables.first.
|
15
|
+
lookup(:TableHeading, index: 0).lookup(:Wikilink).
|
16
|
+
derp{|links| Entity::Coercion.coerce(links, [:entity])}
|
17
|
+
end
|
18
|
+
|
19
|
+
CITY_SYNONYMS = [
|
20
|
+
'City',
|
21
|
+
'Municipality',
|
22
|
+
'Commune', # France
|
23
|
+
'GCCSA/SUA' # Australia
|
24
|
+
]
|
25
|
+
|
26
|
+
CITIES_PAGE_BY_COUNTRY =
|
27
|
+
Hash.new{|_, name| 'List of cities in %s' % name}.
|
28
|
+
merge(
|
29
|
+
'United States' => 'List of United States cities by population',
|
30
|
+
'Australia' => 'List of cities in Australia by population'
|
31
|
+
)
|
32
|
+
|
33
|
+
def cities_by_country(name)
|
34
|
+
page = Infoboxer.wp.get(CITIES_PAGE_BY_COUNTRY[name]) or
|
35
|
+
return Entity::List.new()
|
36
|
+
|
37
|
+
page.tables.map{|t|
|
38
|
+
t.heading_row or next []
|
39
|
+
|
40
|
+
idx = t.heading_row.children.
|
41
|
+
index{|c| c.text =~ /\bname\b/i || CITY_SYNONYMS.any?{|s| c.text.strip.start_with?(s)}} or next []
|
42
|
+
|
43
|
+
t.lookup(:TableCell, index: idx).lookup(:Wikilink)
|
44
|
+
}.flatten.
|
45
|
+
derp{|links| Entity::Coercion.coerce(links, [:entity])}
|
46
|
+
end
|
47
|
+
|
48
|
+
def countries_by_continent(name)
|
49
|
+
countries_by_continents_cache.select{|k, v| v == name}.map(&:first).
|
50
|
+
derp{|names| List.new(*names)}
|
51
|
+
end
|
52
|
+
|
53
|
+
def countries_by_continents_cache
|
54
|
+
@by_continents ||= Infoboxer.wp.
|
55
|
+
get('List of countries by continent').
|
56
|
+
sections.first.
|
57
|
+
sections.map{|s|
|
58
|
+
continent = s.heading.text_
|
59
|
+
s.tables.first.
|
60
|
+
lookup(:Wikilink, :bold?).map(&:link).
|
61
|
+
map{|country| [country, continent]}
|
62
|
+
}.flatten(1).
|
63
|
+
reject{|country, continent| country == 'Holy See'}. # it has [Vatican City]/[Holy See]
|
64
|
+
to_h
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'time_boots'
|
2
|
+
|
3
|
+
module Reality
|
4
|
+
# Just assorted "cool things", included into all entities
|
5
|
+
# Subject to change/refactor
|
6
|
+
module Helpers
|
7
|
+
def alive?
|
8
|
+
!birthday.nil? && date_of_death.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def dead?
|
12
|
+
!date_of_death.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def age_at(tm)
|
16
|
+
# TimeBoots fail with Time vs Date :(
|
17
|
+
#birthday && TimeBoots.year.measure(birthday, tm)
|
18
|
+
|
19
|
+
from = birthday || created_at || published_at
|
20
|
+
|
21
|
+
if from.month < tm.month || from.month == tm.month && from.day <= tm.day
|
22
|
+
tm.year - from.year
|
23
|
+
else
|
24
|
+
tm.year - from.year - 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def age
|
29
|
+
age_at(Date.today)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Reality::Entity.include Helpers
|
34
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Reality
|
2
|
+
Entity::WikidataPredicates.define do
|
3
|
+
# Generic relations ------------------------------------------------
|
4
|
+
predicate 'P361', :part_of, [:entity]
|
5
|
+
predicate 'P527', :parts, [:entity] # aliases: :members
|
6
|
+
|
7
|
+
predicate 'P155', :follows, :entity
|
8
|
+
predicate 'P156', :precedes, :entity
|
9
|
+
predicate 'P571', :created_at, :date # TODO: aliases: :founded_at, :incepted_at
|
10
|
+
|
11
|
+
predicate 'P740', :location, :entity
|
12
|
+
|
13
|
+
predicate 'P737', :influenced_by, [:entity]
|
14
|
+
|
15
|
+
# Object features --------------------------------------------------
|
16
|
+
predicate 'P2048', :height, :measure, unit: 'm'
|
17
|
+
|
18
|
+
# Geography --------------------------------------------------------
|
19
|
+
predicate 'P625', :coord, :coord
|
20
|
+
|
21
|
+
predicate 'P30' , :continent, :entity
|
22
|
+
predicate 'P17' , :country, :entity
|
23
|
+
predicate 'P610', :highest_point, :entity
|
24
|
+
|
25
|
+
predicate 'P36' , :capital, :entity
|
26
|
+
predicate 'P150', :adm_divisions, [:entity]
|
27
|
+
|
28
|
+
predicate 'P47' , :neighbours, [:entity]
|
29
|
+
|
30
|
+
predicate 'P2046', :area, :measure, unit: 'km²'
|
31
|
+
predicate 'P2044', :elevation, :measure, unit: 'm'
|
32
|
+
|
33
|
+
# Economy and socilogy ---------------------------------------------
|
34
|
+
predicate 'P38', :currency, :entity
|
35
|
+
predicate 'P463', :organizations, [:entity]
|
36
|
+
predicate 'P2131', :gdp_nominal, :measure, unit: '$'
|
37
|
+
predicate 'P1082',:population, :measure, unit: 'person'
|
38
|
+
|
39
|
+
predicate 'P35', :head_of_state, :entity
|
40
|
+
|
41
|
+
# References -------------------------------------------------------
|
42
|
+
predicate 'P297', :iso2_code, :string
|
43
|
+
predicate 'P298', :iso3_code, :string
|
44
|
+
predicate 'P78', :tld, :string
|
45
|
+
predicate 'P474', :calling_code, :string
|
46
|
+
predicate 'P421', :tz_offset, :tz_offset
|
47
|
+
|
48
|
+
# People -----------------------------------------------------------
|
49
|
+
# personal
|
50
|
+
predicate 'P19', :birth_place, :entity
|
51
|
+
predicate 'P569', :birthday, :date
|
52
|
+
predicate 'P570', :date_of_death, :date
|
53
|
+
predicate 'P20', :place_of_death, :entity
|
54
|
+
predicate 'P21', :sex, :string
|
55
|
+
predicate 'P735', :given_name, :string
|
56
|
+
|
57
|
+
# family
|
58
|
+
predicate 'P26', :spouse, :entity
|
59
|
+
predicate 'P40', :children, [:entity]
|
60
|
+
predicate 'P22', :father, :entity
|
61
|
+
|
62
|
+
# social
|
63
|
+
predicate 'P551', :residence, :entity
|
64
|
+
predicate 'P27', :citizenship, :entity
|
65
|
+
predicate 'P39', :position, :string
|
66
|
+
predicate 'P106', :occupations, [:string]
|
67
|
+
|
68
|
+
# General creative works & workers ---------------------------------
|
69
|
+
predicate 'P577', :published_at, :date
|
70
|
+
predicate 'P136', :genres, [:string]
|
71
|
+
predicate 'P166', :awards, [:entity]
|
72
|
+
predicate 'P1411', :nominations, [:entity]
|
73
|
+
predicate 'P921', :work_subjects, [:string]
|
74
|
+
predicate 'P364', :original_languages, [:string]
|
75
|
+
|
76
|
+
# Music album ------------------------------------------------------
|
77
|
+
predicate 'P658', :tracks, [:string]
|
78
|
+
predicate 'P175', :performer, :entity
|
79
|
+
#predicate 'P175', :performers, [:entity] - TODO
|
80
|
+
|
81
|
+
# Companies --------------------------------------------------------
|
82
|
+
predicate 'P112', :founders, [:entity]
|
83
|
+
predicate 'P127', :owners, [:entity]
|
84
|
+
predicate 'P169', :ceo, :entity
|
85
|
+
predicate 'P1128', :employees_count, :measure, unit: 'person'
|
86
|
+
predicate 'P452', :industry, :string
|
87
|
+
|
88
|
+
# Software ---------------------------------------------------------
|
89
|
+
predicate 'P178', :developers, [:entity]
|
90
|
+
predicate 'P275', :licenses, [:string]
|
91
|
+
predicate 'P348', :version, :string
|
92
|
+
|
93
|
+
# Movies -----------------------------------------------------------
|
94
|
+
predicate 'P57', :directors, [:entity]
|
95
|
+
predicate 'P162', :producers, [:entity]
|
96
|
+
predicate 'P161', :actors, [:entity]
|
97
|
+
|
98
|
+
# Wehicles ---------------------------------------------------------
|
99
|
+
predicate 'P1029', :crew_members, [:entity]
|
100
|
+
|
101
|
+
# Fictional entities -----------------------------------------------
|
102
|
+
predicate 'P1080', :fictional_universe, :string
|
103
|
+
predicate 'P1441', :present_in_works, [:entity]
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Reality
|
2
|
+
module Character
|
3
|
+
extend Entity::WikipediaType
|
4
|
+
|
5
|
+
infobox_name 'Infobox character'
|
6
|
+
|
7
|
+
# FIXME: Both should be auto-parsed
|
8
|
+
infobox 'species', :species, :entity,
|
9
|
+
parse: ->(var){var.lookup(:Wikilink).first}
|
10
|
+
|
11
|
+
infobox 'affiliation', :affiliations, [:entity],
|
12
|
+
parse: ->(var){var.lookup(:Wikilink)}
|
13
|
+
|
14
|
+
infobox 'portrayer', :portrayer, :entity,
|
15
|
+
parse: ->(var){var.lookup(:Wikilink).first}
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Reality
|
2
|
+
module City
|
3
|
+
extend Entity::WikipediaType
|
4
|
+
|
5
|
+
infobox_name 'Infobox settlement',
|
6
|
+
'Infobox city Japan',
|
7
|
+
'Infobox Russian city', 'Infobox Russian town',
|
8
|
+
'Infobox Russian inhabited locality',
|
9
|
+
'Infobox Russian federal subject'
|
10
|
+
|
11
|
+
infobox 'name', :long_name, :string
|
12
|
+
|
13
|
+
infobox 'area_km2', :area, :measure, unit: 'km²'
|
14
|
+
infobox 'area_total_km2', :area, :measure, unit: 'km²'
|
15
|
+
|
16
|
+
infobox 'population_total', :population, :measure, unit: 'person'
|
17
|
+
infobox 'population_metro', :population_metro, :measure, unit: 'person'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Reality
|
2
|
+
module Continent
|
3
|
+
extend Entity::WikipediaType
|
4
|
+
|
5
|
+
infobox_name 'Infobox continent', 'Infobox Continent' # FIXME: Infoboxer is a bit dumb about this
|
6
|
+
|
7
|
+
infobox 'area', :area, :measure, unit: 'km²',
|
8
|
+
parse: ->(var){
|
9
|
+
str = var.children.
|
10
|
+
templates(name: /^Convert$/i). # Infoboxer is dumb here, tooo :(
|
11
|
+
fetch('1').text
|
12
|
+
|
13
|
+
str = var.children.text if str.empty?
|
14
|
+
Util::Parse.scaled_number(str)
|
15
|
+
}
|
16
|
+
|
17
|
+
def countries
|
18
|
+
@countries ||= Dictionaries.countries_by_continent(name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Reality
|
2
|
+
module Country
|
3
|
+
extend Entity::WikipediaType
|
4
|
+
|
5
|
+
infobox_name 'Infobox country'
|
6
|
+
|
7
|
+
infobox 'conventional_long_name', :long_name, :string
|
8
|
+
infobox 'area_km2', :area, :measure, unit: 'km²'
|
9
|
+
|
10
|
+
infobox 'GDP_PPP', :gdp_ppp, :measure, unit: '$',
|
11
|
+
parse: ->(var){
|
12
|
+
str = var.text.strip.sub(/^((Int|US)?\$|USD)/, '')
|
13
|
+
Util::Parse.scaled_number(str)
|
14
|
+
}
|
15
|
+
|
16
|
+
infobox 'population_census', :population, :measure, unit: 'person'
|
17
|
+
infobox 'population_estimate', :population, :measure, unit: 'person'
|
18
|
+
|
19
|
+
def cities
|
20
|
+
@cities ||= Dictionaries.cities_by_country(name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Reality
|
2
|
+
module MusicalArtist
|
3
|
+
extend Entity::WikipediaType
|
4
|
+
|
5
|
+
infobox_name 'Infobox musical artist'
|
6
|
+
|
7
|
+
parse :albums, [:entity] do |page|
|
8
|
+
if (sec = page.sections('Discography').first)
|
9
|
+
sec.lookup(:UnorderedList).first.lookup(:Wikilink, :italic?)
|
10
|
+
else
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Reality
|
2
|
+
module Person
|
3
|
+
extend Entity::WikipediaType
|
4
|
+
|
5
|
+
infobox_name 'Infobox person'
|
6
|
+
|
7
|
+
# Singular artists, like Bjork or David Bowie
|
8
|
+
# TODO: should not repeat code from musical artist, but include it from module?
|
9
|
+
parse :albums, [:entity] do |page|
|
10
|
+
if (sec = page.sections('Discography').first)
|
11
|
+
sec.lookup(:UnorderedList).first.lookup(:Wikilink, :italic?)
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Reality
|
2
|
+
require_ %w[entity/coercion entity/wikidata_predicates entity/wikipedia_type]
|
3
|
+
|
4
|
+
class Entity
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
attr_reader :wikipage, :wikidata, :wikidata_id
|
8
|
+
attr_reader :values, :wikipedia_type
|
9
|
+
|
10
|
+
def initialize(name, wikipage: nil, wikidata: nil, wikidata_id: nil, load: false)
|
11
|
+
@name = name
|
12
|
+
@wikipage, @wikidata, @wikidata_id = wikipage, wikidata, wikidata_id
|
13
|
+
@values = {}
|
14
|
+
|
15
|
+
load! if load
|
16
|
+
after_load if @wikipage
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
@wikipage ? @wikipage.title : @name
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
if @wikipedia_type && @wikipedia_type.symbol
|
25
|
+
"#<#{self.class}#{loaded? ? '' : '?'}(#{name}):#{@wikipedia_type.symbol}>"
|
26
|
+
else
|
27
|
+
"#<#{self.class}#{loaded? ? '' : '?'}(#{name})>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def _describe
|
32
|
+
load! unless loaded?
|
33
|
+
Util::Format.describe(inspect, values.map{|k,v| [k, v.inspect]})
|
34
|
+
end
|
35
|
+
|
36
|
+
def describe
|
37
|
+
puts _describe
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
name
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s?
|
46
|
+
# FIXME: fuuuuuuuu
|
47
|
+
"#{name.include?(',') ? '"' + name + '"' : name}#{loaded? ? '' : '?'}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def load!
|
51
|
+
if @wikidata_id
|
52
|
+
@wikidata = Wikidata::Entity.fetch_by_id(@wikidata_id)
|
53
|
+
if @wikidata && @wikidata.en_wikipage
|
54
|
+
@wikipage = Infoboxer.wikipedia.get(@wikidata.en_wikipage)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
@wikipage = Infoboxer.wikipedia.get(name)
|
58
|
+
if @wikipage
|
59
|
+
@wikidata = Wikidata::Entity.fetch(@wikipage.title).first
|
60
|
+
end
|
61
|
+
end
|
62
|
+
after_load
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup!(wikipage: nil, wikidata: nil)
|
67
|
+
@wikipage, @wikidata = wikipage, wikidata
|
68
|
+
after_load if @wikipage
|
69
|
+
end
|
70
|
+
|
71
|
+
def loaded?
|
72
|
+
!!@wikipage
|
73
|
+
end
|
74
|
+
|
75
|
+
# Don't try to convert me!
|
76
|
+
UNSUPPORTED_METHODS = [:to_hash, :to_ary, :to_a, :to_str, :to_int]
|
77
|
+
|
78
|
+
def method_missing(sym, *arg, **opts, &block)
|
79
|
+
if arg.empty? && opts.empty? && !block && sym !~ /[=?!]/ &&
|
80
|
+
!UNSUPPORTED_METHODS.include?(sym)
|
81
|
+
|
82
|
+
load! unless loaded?
|
83
|
+
|
84
|
+
# now some new method COULD emerge while loading
|
85
|
+
if methods.include?(sym)
|
86
|
+
send(sym)
|
87
|
+
else
|
88
|
+
values[sym]
|
89
|
+
end
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def respond_to?(sym)
|
96
|
+
sym !~ /[=?!]/ && !UNSUPPORTED_METHODS.include?(sym) || super
|
97
|
+
end
|
98
|
+
|
99
|
+
class << self
|
100
|
+
def load(name, type = nil)
|
101
|
+
Entity.new(name, load: true).tap{|entity|
|
102
|
+
return nil if entity.instance_variable_get('@wikipage').nil?
|
103
|
+
return nil if type && entity.wikipedia_type != type
|
104
|
+
}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#def to_h
|
109
|
+
#if respond_to?(:properties)
|
110
|
+
#properties.map{|sym|
|
111
|
+
#[sym, to_simple_type(self.send(sym))]
|
112
|
+
#}.to_h
|
113
|
+
#else
|
114
|
+
#{}
|
115
|
+
#end
|
116
|
+
#end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
def after_load
|
121
|
+
if @wikipage && !@wikipedia_type
|
122
|
+
if (@wikipedia_type = WikipediaType.for(self))
|
123
|
+
extend(@wikipedia_type)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
if @wikidata
|
127
|
+
@values.update(WikidataPredicates.parse(@wikidata))
|
128
|
+
end
|
129
|
+
(@values.keys - methods).each do |sym|
|
130
|
+
define_singleton_method(sym){@values[sym]}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_simple_type(val)
|
135
|
+
case val
|
136
|
+
when nil, Numeric, String, Symbol
|
137
|
+
val
|
138
|
+
when Array
|
139
|
+
val.map{|v| to_simple_type(v)}
|
140
|
+
when Hash
|
141
|
+
val.map{|k, v| [to_simple_type(k), to_simple_type(v)]}.to_h
|
142
|
+
when Entity
|
143
|
+
val.to_s
|
144
|
+
when Reality::Measure
|
145
|
+
val.amount.to_i
|
146
|
+
else
|
147
|
+
fail ArgumentError, "Non-coercible value #{val.class}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|