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