Class: Reality::Entity

Inherits:
Object
  • Object
show all
Defined in:
lib/reality/entity.rb,
lib/reality/entity/coercion.rb,
lib/reality/entity/wikipedia_type.rb,
lib/reality/entity/wikidata_predicates.rb

Overview

Reality::Entity is a main concept of the library. It represents errr well, some entity from real world. You can think of it as of rough equivalent of Wikipedia article.

Wiki has more details about entity concept and internals.

The easiest way to have an entity is to instantiate is as Entity.load (also aliased as Reality.Entity() method): you'll just have your entity already loaded from all possible data sources (or nil if neither of them knows about it):

argentina = Reality::Entity('Argentina')
# => #<Reality::Entity(Argentina):country>

Then, you can use #describe to see what properties entity has, and call any of them by name, like argentina.capital.

Or you can create not loaded entities with just #initialize (it may be useful when you want to further batch-load several of them through List#load!).

Defined Under Namespace

Modules: Coercion

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, wikidata_id: nil) ⇒ Entity

Creates new entity. Initially, entity is not loaded from datasources, it's just a name. If you want to receive a loaded entity with one statement, take a look at load, which does new + load! under the hoods.

e = Reality::Entity.new('Mississippi')
# => #<Reality::Entity?(Mississippi)>
e.loaded?
# => false
e.values
# => {}

Parameters:

  • name (String)

    Name of the entity you want. Basically, it's Wikipedia page name for some concept. Not-so-basically, please refer to names explanation in our wiki.

  • wikidata_id (String) (defaults to: nil)

    Used mostly internally (when not only entity name, but also wikidata id is known; this happens on loading entities by references from other entities).



76
77
78
79
80
# File 'lib/reality/entity.rb', line 76

def initialize(name, wikidata_id: nil)
  @name = name
  @wikidata_id = wikidata_id
  @values = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *arg, **opts, &block) ⇒ Object

Entity handles method_missing this way:

  • loads itself if it was not loaded;
  • returns one of #values by method name.

Note, that even if there's no value with required key, method_missing will return nil (and not through NoMethodError as someone may expect). That's because even supposedly homogenous entities may have different property sets, and typically you want to do something like cities.map(&:area).compact.inject(:+), not handling exceptions about "this city has no 'area' property".



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/reality/entity.rb', line 220

def method_missing(sym, *arg, **opts, &block)
  if arg.empty? && opts.empty? && !block && sym !~ /[=?!]/ &&
    !UNSUPPORTED_METHODS.include?(sym)
    
    load! unless loaded?

    # now some new method COULD emerge while loading
    if methods.include?(sym)
      send(sym)
    else
      values[sym]
    end
  else
    super
  end
end

Instance Attribute Details

#valuesHash<Symbol, Object> (readonly)

All values extracted from data sources, in structured form. You can pretty-previes them via #describe, as well as work with separate values with method call (see #method_missing).

Returns:

  • (Hash<Symbol, Object>)


50
51
52
# File 'lib/reality/entity.rb', line 50

def values
  @values
end

#wikipageInfoboxer::MediaWiki::Page (readonly)

Instance of Infoboxer's page.

Pretty useful on its own:

puts Reality::Entity('Argentina').wikipage.intro
# Argentina (ˌɑrdʒənˈtiːnə; aɾxenˈtina), officially the Argentine Republic (República Argentina), is a federal republic....

Refer to Infoboxer's documentation for details.

Returns:

  • (Infoboxer::MediaWiki::Page)


43
44
45
# File 'lib/reality/entity.rb', line 43

def wikipage
  @wikipage
end

Class Method Details

.load(name) ⇒ Entity?

Loads Entity from all datasources. Returns either loaded entity or nil if entity not found.

Parameters:

  • name (String)

    See #initialize for explanations about entity names.

Returns:



250
251
252
253
254
# File 'lib/reality/entity.rb', line 250

def load(name)
  Entity.new(name).load!.tap{|entity|
    return nil if !entity.loaded?
  }
end

Instance Method Details

#describenil

Prints general object state and all properties with values

Example:

$> Reality::Entity.new('Mississippi').describe
  Output:
  -------------------------------
  <Reality::Entity(Mississippi)>
  -------------------------------
         capital: #<Reality::Entity?(Jackson)>
           coord: #<Reality::Geo::Coord(33°0′0″N,90°0′0″W)>
         country: #<Reality::Entity?(United States of America)>
      created_at: Wed, 10 Dec 1817
      located_in: #<Reality::Entity?(United States of America)>
      neighbours: #<Reality::List[Alabama?, Tennessee?, Louisiana?, Arkansas?]>
official_website: "http://www.mississippi.gov"
       tz_offset: #<Reality::TZOffset(UTC-06:00)>

Returns:

  • (nil)


147
148
149
150
# File 'lib/reality/entity.rb', line 147

def describe
  puts _describe
  nil
end

#inspectString

Returns entity brief representation. Things to note:

#<Reality::Entity?(Argentina)>
                 ^    ^
                 |  Entity name
            Sign of not
            loaded entity

#<Reality::Entity(Argentina):country>
                 ^             ^
                 |           Name of "additional type" (to be documented...)
           No question mark:
           entity is loaded

Returns:

  • (String)


118
119
120
121
122
123
124
# File 'lib/reality/entity.rb', line 118

def inspect
  if @wikipedia_type && @wikipedia_type.symbol
    "#<#{self.class}#{loaded? ? '' : '?'}(#{name}):#{@wikipedia_type.symbol}>"
  else
    "#<#{self.class}#{loaded? ? '' : '?'}(#{name})>"
  end
end

#load!self

Loads entity data from all external sources.

Note that this method is called implicitly on #method_missing, #describe or #to_h.

Note also that if you need several entities to be loaded, its much more effective to have them grouped into List and batch-loaded via List#load!.

Returns:

  • (self)


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/reality/entity.rb', line 172

def load!
  if @wikidata_id
    @wikidata = Wikidata::Entity.one_by_id(@wikidata_id)
    if @wikidata && @wikidata.en_wikipage
      @wikipage = Infoboxer.wikipedia.get(@wikidata.en_wikipage)
    end
  else
    @wikipage = Infoboxer.wikipedia.get(name)
    @wikidata = if @wikipage
      Wikidata::Entity.one_by_wikititle(@wikipage.title)
    else
      Wikidata::Entity.one_by_label(name)
    end
  end
  after_load
  self
end

#loaded?Boolean

Returns true if entity is loaded already.

Returns:

  • (Boolean)


200
201
202
# File 'lib/reality/entity.rb', line 200

def loaded?
  !!(@wikipage || @wikidata)
end

#nameString

Entity name string. For not loaded entity returns the name by which it was created. For loaded, it's correct name of Wikipedia page:

e = Reality::Entity.new('Einstein')
# => #<Reality::Entity?(Einstein)>
e.name
# => "Einstein"
e.load!
# => #<Reality::Entity(Albert Einstein)>
e.name
# => "Albert Einstein"

Returns:

  • (String)


97
98
99
# File 'lib/reality/entity.rb', line 97

def name
  @wikipage ? @wikipage.title : @name
end

#to_hHash

Converts Entity to hash, preserving only core types (so, you can store this hash in YAML or JSON, for example). Some notes on conversion:

  • Entity name goes to :name key;
  • Rational values became floating point;
  • Measure and Geo::Coord became hashes;
  • other entities became: when loaded - hashes, when not loaded - just strings of entity name

Example:

argentina = Reality::Entity('Argentina')
# => #<Reality::Entity(Argentina):country>
argentina.head_of_government.load!
# => #<Reality::Entity(Mauricio Macri)>
agentina.to_h
# {:name=>"Argentina",
# :long_name=>"Argentine Republic",
# :area=>{:amount=>2780400.0, :unit=>"km²"},
# :gdp_ppp=>{:amount=>964279000000.0, :unit=>"$"},
# :population=>{:amount=>43417000.0, :unit=>"person"},
# :head_of_government=>
#   {:name=>"Mauricio Macri", 
#   :birthday=>"1959-02-08",
#   ....},
# :country=>"Argentina",
# :continent=>"South America",
# :head_of_state=>"Mauricio Macri",
# :capital=>"Buenos Aires",
# :currency=>"peso",
# :neighbours=>["Uruguay", "Brazil", "Chile", "Paraguay", "Bolivia"],
# :tld=>".ar",
# :adm_divisions=>["Buenos Aires", "Buenos Aires Province", ....],
# :iso2_code=>"AR",
# :iso3_code=>"ARG",
# :part_of=>["Latin America"],
# :tz_offset=>"-03:00",
# :organizations=>["United Nations","Union of South American Nations","Mercosur",...],
# :calling_code=>"+54",
# :created_at=>"1816-01-01",
# :highest_point=>"Aconcagua",
# :coord=>{:lat=>-34.0, :lng=>-64.0},
# :official_website=>"http://www.argentina.gob.ar/",
# :gdp_nominal=>{:amount=>537659972702.0, :unit=>"$"}}
# 

Returns:

  • (Hash)


305
306
307
308
309
# File 'lib/reality/entity.rb', line 305

def to_h
  load! unless loaded?
  {name: name}.merge \
    values.map{|k, v| [k.to_sym, Coercion.to_simple_type(v)]}.to_h
end

#to_jsonString

Converts entity to JSON (same as entity.to_h.to_json)

Returns:

  • (String)

See Also:



315
316
317
# File 'lib/reality/entity.rb', line 315

def to_json
  to_h.to_json
end

#to_sObject



152
153
154
# File 'lib/reality/entity.rb', line 152

def to_s
  name
end