reality 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|