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/bin/reality
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
|
2
3
|
require 'rubygems'
|
3
4
|
require 'reality'
|
4
|
-
require 'reality/
|
5
|
-
require 'reality/shortcuts'
|
5
|
+
require 'reality/command_line'
|
6
6
|
|
7
|
-
Reality.
|
7
|
+
reality_runner = Reality::CommandLine.new
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
if reality_runner.interactive?
|
10
|
+
reality_runner.run_interactive_shell
|
11
|
+
else
|
12
|
+
puts reality_runner.results
|
12
13
|
end
|
13
|
-
|
14
|
-
require 'irb'
|
15
|
-
ARGV.shift until ARGV.empty?
|
16
|
-
IRB.start
|
data/config/demo.yml
CHANGED
data/lib/reality.rb
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
require 'infoboxer'
|
2
2
|
require 'yaml'
|
3
3
|
|
4
|
+
# Reality is library for accessing all world data, starting from Wikipedia.
|
5
|
+
#
|
6
|
+
# Look at {Entity} for good starting point.
|
7
|
+
#
|
8
|
+
# You also may want to navigate [Getting started](https://github.com/molybdenum-99/reality/wiki/Getting-started)
|
9
|
+
# page in our wiki.
|
4
10
|
module Reality
|
11
|
+
# @private
|
5
12
|
def self.require_(*modules)
|
6
13
|
modules.flatten.flat_map{|pattern|
|
7
14
|
Dir[File.expand_path("../reality/#{pattern}.rb", __FILE__)]
|
@@ -19,16 +26,14 @@ module Reality
|
|
19
26
|
# entities
|
20
27
|
require_ %w[entity list]
|
21
28
|
require_ %w[definitions/*]
|
22
|
-
require_ %w[methods]
|
29
|
+
require_ %w[methods names]
|
23
30
|
|
31
|
+
include Methods
|
24
32
|
extend Methods
|
25
33
|
|
26
|
-
def self.reload!
|
27
|
-
require_ %w[definitions/*]
|
28
|
-
end
|
29
|
-
|
30
34
|
# extras
|
31
|
-
require_ %w[extras/open_weather_map extras/geonames]
|
35
|
+
require_ %w[extras/open_weather_map extras/geonames extras/quandl]
|
32
36
|
include Extras::OpenWeatherMap
|
33
37
|
include Extras::Geonames
|
38
|
+
include Extras::Quandl
|
34
39
|
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'reality/pretty_inspect'
|
3
|
+
|
4
|
+
module Reality
|
5
|
+
# This module contains services used from `bin/reality`, you typically
|
6
|
+
# don't need to think of it.
|
7
|
+
class CommandLine
|
8
|
+
attr_accessor :search_term, :article, :commands, :options, :errors
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
parse_arguments
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.display_usage
|
15
|
+
puts "usage: reality \"[search-string]\" [entity-command] [chained-command(s) ...]"
|
16
|
+
end
|
17
|
+
|
18
|
+
def interactive?
|
19
|
+
!!self.options[:interactive]
|
20
|
+
end
|
21
|
+
|
22
|
+
def article_found?
|
23
|
+
!self.article.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def subcommand_for(object, subcommand)
|
27
|
+
if object.respond_to?(subcommand.to_sym)
|
28
|
+
puts "Calling #{subcommand} on #{object.inspect}" if ENV['DEBUG']
|
29
|
+
object.send(subcommand.to_sym)
|
30
|
+
else
|
31
|
+
self.errors << "#{object} doesn't respond to #{subcommand}"
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def results
|
37
|
+
return "Nothing found for: #{self.search_term}" unless self.article_found?
|
38
|
+
puts "Attempting entity chain: #{self.commands} on #{self.article.inspect}" if ENV['DEBUG']
|
39
|
+
|
40
|
+
result = subcommand_for(self.article, self.commands.shift)
|
41
|
+
|
42
|
+
while subcommand = self.commands.shift
|
43
|
+
result = subcommand_for(result, subcommand)
|
44
|
+
end
|
45
|
+
|
46
|
+
if self.errors.any?
|
47
|
+
"Error: #{ self.errors.join("\n") }"
|
48
|
+
else
|
49
|
+
result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def run_interactive_shell
|
54
|
+
require 'irb'
|
55
|
+
require 'reality/shortcuts'
|
56
|
+
::ARGV.clear
|
57
|
+
|
58
|
+
# FIXME: can't see better means to have everything accessible & included
|
59
|
+
#IRB::ExtendCommandBundle.include(Reality)
|
60
|
+
TOPLEVEL_BINDING.receiver.send(:include, Reality)
|
61
|
+
|
62
|
+
IRB.setup nil
|
63
|
+
|
64
|
+
IRB.conf[:IRB_NAME] = 'reality'
|
65
|
+
|
66
|
+
IRB.conf[:PROMPT] = {}
|
67
|
+
IRB.conf[:PROMPT][:REALITY] = {
|
68
|
+
:PROMPT_I => '%N:%03n:%i> ',
|
69
|
+
:PROMPT_S => '%N:%03n:%i%l ',
|
70
|
+
:PROMPT_C => '%N:%03n:%i* ',
|
71
|
+
:RETURN => "# => %s\n"
|
72
|
+
}
|
73
|
+
IRB.conf[:PROMPT_MODE] = :REALITY
|
74
|
+
IRB.conf[:RC] = false
|
75
|
+
|
76
|
+
IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context
|
77
|
+
|
78
|
+
require 'irb/ext/multi-irb'
|
79
|
+
IRB.irb nil, TOPLEVEL_BINDING
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def parse_options
|
85
|
+
self.options = {}
|
86
|
+
|
87
|
+
OptionParser.new do |opts|
|
88
|
+
opts.banner = "Usage: reality [options] [search-string] [entity-command] [chained-command(s) ...]"
|
89
|
+
|
90
|
+
opts.on_tail("-i", "--interactive", "Run an interactive IRB session with Reality pre-configured for querying.") do
|
91
|
+
self.options[:interactive] = true
|
92
|
+
end
|
93
|
+
|
94
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
95
|
+
puts opts
|
96
|
+
exit
|
97
|
+
end
|
98
|
+
end.parse!
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse_arguments
|
102
|
+
parse_options
|
103
|
+
self.search_term = "#{::ARGV.shift}"
|
104
|
+
|
105
|
+
if self.options[:interactive]
|
106
|
+
Reality.configure :demo
|
107
|
+
elsif self.search_term.length > 0
|
108
|
+
self.article = Reality::Entity(self.search_term)
|
109
|
+
self.errors = []
|
110
|
+
|
111
|
+
if ::ARGV.count > 0
|
112
|
+
self.commands = ::ARGV.map(&:to_sym)
|
113
|
+
else
|
114
|
+
self.commands = [:describe]
|
115
|
+
end
|
116
|
+
|
117
|
+
Reality.configure :demo
|
118
|
+
else
|
119
|
+
self.class.display_usage
|
120
|
+
exit
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/reality/config.rb
CHANGED
@@ -32,15 +32,22 @@ module Reality
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# @private
|
35
36
|
def Reality.config
|
36
37
|
@config ||= Config.new
|
37
38
|
end
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
# Allows to configure Reality.
|
41
|
+
#
|
42
|
+
# @param path [String] Path to config. See `config/demo.yml` for config
|
43
|
+
# sample. Also, you can use `:demo` value for config Reality with
|
44
|
+
# demo keys.
|
45
|
+
#
|
46
|
+
def Reality.configure(path)
|
47
|
+
if path == :demo
|
41
48
|
config.load(File.expand_path('../../../config/demo.yml', __FILE__))
|
42
49
|
else
|
43
|
-
config.load(
|
50
|
+
config.load(path)
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
@@ -9,6 +9,7 @@ module Reality
|
|
9
9
|
predicate 'P571', :created_at, :date # TODO: aliases: :founded_at, :incepted_at
|
10
10
|
|
11
11
|
predicate 'P740', :location, :entity
|
12
|
+
predicate 'P585', :date , :date # TODO: maybe :datetime?
|
12
13
|
|
13
14
|
predicate 'P737', :influenced_by, [:entity]
|
14
15
|
|
@@ -30,13 +31,17 @@ module Reality
|
|
30
31
|
predicate 'P2046', :area, :measure, unit: 'km²'
|
31
32
|
predicate 'P2044', :elevation, :measure, unit: 'm'
|
32
33
|
|
33
|
-
|
34
|
+
predicate 'P969', :street_address, :string
|
35
|
+
predicate 'P131', :located_in, :entity
|
36
|
+
|
37
|
+
# Economy and sociology ---------------------------------------------
|
34
38
|
predicate 'P38', :currency, :entity
|
35
39
|
predicate 'P463', :organizations, [:entity]
|
36
40
|
predicate 'P2131', :gdp_nominal, :measure, unit: '$'
|
37
41
|
predicate 'P1082',:population, :measure, unit: 'person'
|
38
42
|
|
39
43
|
predicate 'P35', :head_of_state, :entity
|
44
|
+
predicate 'P6', :head_of_government, :entity
|
40
45
|
|
41
46
|
# References -------------------------------------------------------
|
42
47
|
predicate 'P297', :iso2_code, :string
|
@@ -101,5 +106,9 @@ module Reality
|
|
101
106
|
# Fictional entities -----------------------------------------------
|
102
107
|
predicate 'P1080', :fictional_universe, :string
|
103
108
|
predicate 'P1441', :present_in_works, [:entity]
|
109
|
+
|
110
|
+
# Internet ---------------------------------------------------------
|
111
|
+
predicate 'P856', :official_website, :string
|
112
|
+
predicate 'P2002', :twitter_username, :string
|
104
113
|
end
|
105
114
|
end
|
data/lib/reality/entity.rb
CHANGED
@@ -1,25 +1,120 @@
|
|
1
1
|
module Reality
|
2
2
|
require_ %w[entity/coercion entity/wikidata_predicates entity/wikipedia_type]
|
3
|
-
|
3
|
+
|
4
|
+
# Reality::Entity is a main concept of the library. It represents errr
|
5
|
+
# well, some entity from real world. You can think of it as of rough
|
6
|
+
# equivalent of Wikipedia article.
|
7
|
+
#
|
8
|
+
# Wiki has more details about entity [concept](https://github.com/molybdenum-99/reality/wiki/Entity)
|
9
|
+
# and [internals](https://github.com/molybdenum-99/reality/wiki/Entity%20internals).
|
10
|
+
#
|
11
|
+
# The easiest way to have an entity is to instantiate is as {Entity.load}
|
12
|
+
# (also aliased as `Reality.Entity()` method): you'll just have your
|
13
|
+
# entity already _loaded_ from all possible data sources (or `nil` if
|
14
|
+
# neither of them knows about it):
|
15
|
+
#
|
16
|
+
# ```ruby
|
17
|
+
# argentina = Reality::Entity('Argentina')
|
18
|
+
# # => #<Reality::Entity(Argentina):country>
|
19
|
+
# ```
|
20
|
+
# Then, you can use {#describe} to see what properties entity has, and
|
21
|
+
# call any of them by name, like `argentina.capital`.
|
22
|
+
#
|
23
|
+
# Or you can create not loaded entities with just {#initialize} (it
|
24
|
+
# may be useful when you want to further batch-load several of them
|
25
|
+
# through {List#load!}).
|
26
|
+
#
|
4
27
|
class Entity
|
5
28
|
using Refinements
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
29
|
+
|
30
|
+
# Instance of Infoboxer's [page](http://www.rubydoc.info/gems/infoboxer/Infoboxer/MediaWiki/Page).
|
31
|
+
#
|
32
|
+
# Pretty useful on its own:
|
33
|
+
#
|
34
|
+
# ```ruby
|
35
|
+
# puts Reality::Entity('Argentina').wikipage.intro
|
36
|
+
# # Argentina (ˌɑrdʒənˈtiːnə; aɾxenˈtina), officially the Argentine Republic (República Argentina), is a federal republic....
|
37
|
+
# ```
|
38
|
+
#
|
39
|
+
# Refer to [Infoboxer's documentation](http://www.rubydoc.info/gems/infoboxer/Infoboxer/MediaWiki/Page)
|
40
|
+
# for details.
|
41
|
+
#
|
42
|
+
# @return [Infoboxer::MediaWiki::Page]
|
43
|
+
attr_reader :wikipage
|
44
|
+
|
45
|
+
# All values extracted from data sources, in structured form.
|
46
|
+
# You can pretty-previes them via {#describe}, as well as work with
|
47
|
+
# separate values with method call (see {#method_missing}).
|
48
|
+
#
|
49
|
+
# @return [Hash<Symbol, Object>]
|
50
|
+
attr_reader :values
|
51
|
+
|
52
|
+
# @private
|
53
|
+
attr_reader :wikipedia_type, :wikidata, :wikidata_id
|
54
|
+
|
55
|
+
# Creates new entity. Initially, entity is _not_ loaded from datasources,
|
56
|
+
# it's just a name. If you want to receive a loaded entity with one
|
57
|
+
# statement, take a look at {Entity.load}, which does `new` + `load!`
|
58
|
+
# under the hoods.
|
59
|
+
#
|
60
|
+
# ```
|
61
|
+
# e = Reality::Entity.new('Mississippi')
|
62
|
+
# # => #<Reality::Entity?(Mississippi)>
|
63
|
+
# e.loaded?
|
64
|
+
# # => false
|
65
|
+
# e.values
|
66
|
+
# # => {}
|
67
|
+
# ```
|
68
|
+
#
|
69
|
+
# @param name [String] Name of the entity you want. Basically, it's
|
70
|
+
# Wikipedia page name for some concept. Not-so-basically, please
|
71
|
+
# refer to [names explanation](https://github.com/molybdenum-99/reality/wiki/Entity#entity-names)
|
72
|
+
# in our wiki.
|
73
|
+
# @param wikidata_id [String] Used mostly internally (when not only
|
74
|
+
# entity name, but also wikidata id is known; this happens on loading
|
75
|
+
# entities by references from other entities).
|
76
|
+
def initialize(name, wikidata_id: nil)
|
11
77
|
@name = name
|
12
|
-
@
|
78
|
+
@wikidata_id = wikidata_id
|
13
79
|
@values = {}
|
14
|
-
|
15
|
-
load! if load
|
16
|
-
after_load if @wikipage
|
17
80
|
end
|
18
81
|
|
82
|
+
# Entity name string. For not loaded entity returns the name by which it
|
83
|
+
# was created. For loaded, it's correct name of Wikipedia page:
|
84
|
+
#
|
85
|
+
# ```ruby
|
86
|
+
# e = Reality::Entity.new('Einstein')
|
87
|
+
# # => #<Reality::Entity?(Einstein)>
|
88
|
+
# e.name
|
89
|
+
# # => "Einstein"
|
90
|
+
# e.load!
|
91
|
+
# # => #<Reality::Entity(Albert Einstein)>
|
92
|
+
# e.name
|
93
|
+
# # => "Albert Einstein"
|
94
|
+
# ```
|
95
|
+
#
|
96
|
+
# @return [String]
|
19
97
|
def name
|
20
98
|
@wikipage ? @wikipage.title : @name
|
21
99
|
end
|
22
100
|
|
101
|
+
# Returns entity brief representation. Things to note:
|
102
|
+
#
|
103
|
+
# ```
|
104
|
+
# #<Reality::Entity?(Argentina)>
|
105
|
+
# ^ ^
|
106
|
+
# | Entity name
|
107
|
+
# Sign of not
|
108
|
+
# loaded entity
|
109
|
+
#
|
110
|
+
# #<Reality::Entity(Argentina):country>
|
111
|
+
# ^ ^
|
112
|
+
# | Name of "additional type" (to be documented...)
|
113
|
+
# No question mark:
|
114
|
+
# entity is loaded
|
115
|
+
# ```
|
116
|
+
#
|
117
|
+
# @return [String]
|
23
118
|
def inspect
|
24
119
|
if @wikipedia_type && @wikipedia_type.symbol
|
25
120
|
"#<#{self.class}#{loaded? ? '' : '?'}(#{name}):#{@wikipedia_type.symbol}>"
|
@@ -28,11 +123,27 @@ module Reality
|
|
28
123
|
end
|
29
124
|
end
|
30
125
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
126
|
+
# Prints general object state and all properties with values
|
127
|
+
#
|
128
|
+
# Example:
|
129
|
+
#
|
130
|
+
# ```
|
131
|
+
# $> Reality::Entity.new('Mississippi').describe
|
132
|
+
# Output:
|
133
|
+
# -------------------------------
|
134
|
+
# <Reality::Entity(Mississippi)>
|
135
|
+
# -------------------------------
|
136
|
+
# capital: #<Reality::Entity?(Jackson)>
|
137
|
+
# coord: #<Reality::Geo::Coord(33°0′0″N,90°0′0″W)>
|
138
|
+
# country: #<Reality::Entity?(United States of America)>
|
139
|
+
# created_at: Wed, 10 Dec 1817
|
140
|
+
# located_in: #<Reality::Entity?(United States of America)>
|
141
|
+
# neighbours: #<Reality::List[Alabama?, Tennessee?, Louisiana?, Arkansas?]>
|
142
|
+
# official_website: "http://www.mississippi.gov"
|
143
|
+
# tz_offset: #<Reality::TZOffset(UTC-06:00)>
|
144
|
+
# ```
|
145
|
+
#
|
146
|
+
# @return [nil]
|
36
147
|
def describe
|
37
148
|
puts _describe
|
38
149
|
nil
|
@@ -42,39 +153,70 @@ module Reality
|
|
42
153
|
name
|
43
154
|
end
|
44
155
|
|
156
|
+
# @private
|
45
157
|
def to_s?
|
46
158
|
# FIXME: fuuuuuuuu
|
47
159
|
"#{name.include?(',') ? '"' + name + '"' : name}#{loaded? ? '' : '?'}"
|
48
160
|
end
|
49
161
|
|
162
|
+
# Loads entity data from all external sources.
|
163
|
+
#
|
164
|
+
# Note that this method is called implicitly on {#method_missing},
|
165
|
+
# {#describe} or {#to_h}.
|
166
|
+
#
|
167
|
+
# Note also that if you need several entities to be loaded, its much
|
168
|
+
# more effective to have them grouped into {List} and batch-loaded
|
169
|
+
# via {List#load!}.
|
170
|
+
#
|
171
|
+
# @return [self]
|
50
172
|
def load!
|
51
173
|
if @wikidata_id
|
52
|
-
@wikidata = Wikidata::Entity.
|
174
|
+
@wikidata = Wikidata::Entity.one_by_id(@wikidata_id)
|
53
175
|
if @wikidata && @wikidata.en_wikipage
|
54
176
|
@wikipage = Infoboxer.wikipedia.get(@wikidata.en_wikipage)
|
55
177
|
end
|
56
178
|
else
|
57
179
|
@wikipage = Infoboxer.wikipedia.get(name)
|
58
|
-
if @wikipage
|
59
|
-
|
180
|
+
@wikidata = if @wikipage
|
181
|
+
Wikidata::Entity.one_by_wikititle(@wikipage.title)
|
182
|
+
else
|
183
|
+
Wikidata::Entity.one_by_label(name)
|
60
184
|
end
|
61
185
|
end
|
62
186
|
after_load
|
63
187
|
self
|
64
188
|
end
|
65
189
|
|
190
|
+
# @private
|
66
191
|
def setup!(wikipage: nil, wikidata: nil)
|
67
192
|
@wikipage, @wikidata = wikipage, wikidata
|
68
|
-
after_load if @wikipage
|
193
|
+
after_load if @wikipage || @wikidata
|
194
|
+
self
|
69
195
|
end
|
70
196
|
|
197
|
+
# Returns `true` if entity is loaded already.
|
198
|
+
#
|
199
|
+
# @return [Boolean]
|
71
200
|
def loaded?
|
72
|
-
|
201
|
+
!!(@wikipage || @wikidata)
|
73
202
|
end
|
74
203
|
|
204
|
+
# @private
|
75
205
|
# Don't try to convert me!
|
76
206
|
UNSUPPORTED_METHODS = [:to_hash, :to_ary, :to_a, :to_str, :to_int]
|
77
207
|
|
208
|
+
# Entity handles `method_missing` this way:
|
209
|
+
#
|
210
|
+
# * loads itself if it was not loaded;
|
211
|
+
# * returns one of {values} by method name.
|
212
|
+
#
|
213
|
+
# Note, that even if there's no value with required key, `method_missing`
|
214
|
+
# will return `nil` (and not through `NoMethodError` as someone may
|
215
|
+
# expect). That's because even supposedly homogenous entities may have different
|
216
|
+
# property sets, and typically you want to do something like
|
217
|
+
# `cities.map(&:area).compact.inject(:+)`, not handling exceptions
|
218
|
+
# about "this city has no 'area' property".
|
219
|
+
#
|
78
220
|
def method_missing(sym, *arg, **opts, &block)
|
79
221
|
if arg.empty? && opts.empty? && !block && sym !~ /[=?!]/ &&
|
80
222
|
!UNSUPPORTED_METHODS.include?(sym)
|
@@ -92,28 +234,87 @@ module Reality
|
|
92
234
|
end
|
93
235
|
end
|
94
236
|
|
95
|
-
|
96
|
-
|
237
|
+
# @private
|
238
|
+
def respond_to?(sym, include_all = false)
|
239
|
+
sym !~ /[=?!]/ && !UNSUPPORTED_METHODS.include?(sym) || super(sym)
|
97
240
|
end
|
98
241
|
|
99
242
|
class << self
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
243
|
+
# Loads Entity from all datasources. Returns either loaded entity
|
244
|
+
# or `nil` if entity not found.
|
245
|
+
#
|
246
|
+
# @param name [String] See {#initialize} for explanations about
|
247
|
+
# entity names.
|
248
|
+
#
|
249
|
+
# @return [Entity, nil]
|
250
|
+
def load(name)
|
251
|
+
Entity.new(name).load!.tap{|entity|
|
252
|
+
return nil if !entity.loaded?
|
104
253
|
}
|
105
254
|
end
|
106
255
|
end
|
107
256
|
|
108
|
-
#
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
#
|
257
|
+
# Converts Entity to hash, preserving only _core types_ (so, you can
|
258
|
+
# store this hash in YAML or JSON, for example). Some notes on conversion:
|
259
|
+
# * Entity name goes to `:name` key;
|
260
|
+
# * Rational values became floating point;
|
261
|
+
# * {Measure} and {Geo::Coord} became hashes;
|
262
|
+
# * other entities became: when loaded - hashes, when not loaded -
|
263
|
+
# just strings of entity name
|
264
|
+
#
|
265
|
+
# Example:
|
266
|
+
#
|
267
|
+
# ```ruby
|
268
|
+
# argentina = Reality::Entity('Argentina')
|
269
|
+
# # => #<Reality::Entity(Argentina):country>
|
270
|
+
# argentina.head_of_government.load!
|
271
|
+
# # => #<Reality::Entity(Mauricio Macri)>
|
272
|
+
# agentina.to_h
|
273
|
+
# # {:name=>"Argentina",
|
274
|
+
# # :long_name=>"Argentine Republic",
|
275
|
+
# # :area=>{:amount=>2780400.0, :unit=>"km²"},
|
276
|
+
# # :gdp_ppp=>{:amount=>964279000000.0, :unit=>"$"},
|
277
|
+
# # :population=>{:amount=>43417000.0, :unit=>"person"},
|
278
|
+
# # :head_of_government=>
|
279
|
+
# # {:name=>"Mauricio Macri",
|
280
|
+
# # :birthday=>"1959-02-08",
|
281
|
+
# # ....},
|
282
|
+
# # :country=>"Argentina",
|
283
|
+
# # :continent=>"South America",
|
284
|
+
# # :head_of_state=>"Mauricio Macri",
|
285
|
+
# # :capital=>"Buenos Aires",
|
286
|
+
# # :currency=>"peso",
|
287
|
+
# # :neighbours=>["Uruguay", "Brazil", "Chile", "Paraguay", "Bolivia"],
|
288
|
+
# # :tld=>".ar",
|
289
|
+
# # :adm_divisions=>["Buenos Aires", "Buenos Aires Province", ....],
|
290
|
+
# # :iso2_code=>"AR",
|
291
|
+
# # :iso3_code=>"ARG",
|
292
|
+
# # :part_of=>["Latin America"],
|
293
|
+
# # :tz_offset=>"-03:00",
|
294
|
+
# # :organizations=>["United Nations","Union of South American Nations","Mercosur",...],
|
295
|
+
# # :calling_code=>"+54",
|
296
|
+
# # :created_at=>"1816-01-01",
|
297
|
+
# # :highest_point=>"Aconcagua",
|
298
|
+
# # :coord=>{:lat=>-34.0, :lng=>-64.0},
|
299
|
+
# # :official_website=>"http://www.argentina.gob.ar/",
|
300
|
+
# # :gdp_nominal=>{:amount=>537659972702.0, :unit=>"$"}}
|
301
|
+
# #
|
302
|
+
# ```
|
303
|
+
#
|
304
|
+
# @return [Hash]
|
305
|
+
def to_h
|
306
|
+
load! unless loaded?
|
307
|
+
{name: name}.merge \
|
308
|
+
values.map{|k, v| [k.to_sym, Coercion.to_simple_type(v)]}.to_h
|
309
|
+
end
|
310
|
+
|
311
|
+
# Converts entity to JSON (same as `entity.to_h.to_json`)
|
312
|
+
#
|
313
|
+
# @see #to_h
|
314
|
+
# @return [String]
|
315
|
+
def to_json
|
316
|
+
to_h.to_json
|
317
|
+
end
|
117
318
|
|
118
319
|
protected
|
119
320
|
|
@@ -131,22 +332,9 @@ module Reality
|
|
131
332
|
end
|
132
333
|
end
|
133
334
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
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
|
335
|
+
def _describe
|
336
|
+
load! unless loaded?
|
337
|
+
Util::Format.describe(inspect, values.map{|k,v| [k, v.inspect]})
|
149
338
|
end
|
150
|
-
|
151
339
|
end
|
152
340
|
end
|