Class: WhatIs::ThisIs

Inherits:
Object
  • Object
show all
Defined in:
lib/whatis/thisis.rb,
lib/whatis/thisis/link.rb,
lib/whatis/thisis/ambigous.rb,
lib/whatis/thisis/notfound.rb

Overview

Represents one resolved entity, provides introspection and access to individual properties. You should never create instances of this class directly, but rather obtain it from #this and #these.

See also:

  • Ambigous Representing disambiguation page, allows fetching variants.

  • NotFound Representing not found entity, allows searching for possible options.

Examples:

paris = WhatIs.this('Paris')
# => #<ThisIs Paris [img] {48.856700,2.350800}>
paris.describe
# => Paris
#        title: "Paris"
#  description: "capital city of France"
#  coordinates: #<Geo::Coord 48.856700,2.350800>
#      extract: "Paris (French pronunciation: ​[paʁi] ( listen)) is the capital and most populous city of France, with an administrative-limits area of 105 square kilometres (41 square miles) and a 2015 population of 2,229,621."
#        image: "https://upload.wikimedia.org/wikipedia/commons/0/08/Seine_and_Eiffel_Tower_from_Tour_Saint_Jacques_2013-08.JPG"
#
paris.coordinates
# => #<Geo::Coord 48.856700,2.350800>
paris2 = paris.what(languages: :ru, categories: true) # fetch more details
# => #<ThisIs Paris/Париж, 12 categories [img] {48.856700,2.350800}>
paris2.describe
# => Paris
#        title: "Paris"
#  description: "capital city of France"
#  coordinates: #<Geo::Coord 48.856700,2.350800>
#   categories: ["3rd-century BC establishments", "Capitals in Europe", "Catholic pilgrimage sites", "Cities in France", "Cities in Île-de-France", "Companions of the Liberation", "Departments of Île-de-France", "European culture", "French culture", "Paris", "Populated places established in the 3rd century BC", "Prefectures in France"]
#    languages: {"ru"=>#<ThisIs::Link ru:Париж>}
#      extract: "Paris (French pronunciation: ​[paʁi] ( listen)) is the capital and most populous city of France, with an administrative-limits area of 105 square kilometres (41 square miles) and a 2015 population of 2,229,621."
#        image: "https://upload.wikimedia.org/wikipedia/commons/0/08/Seine_and_Eiffel_Tower_from_Tour_Saint_Jacques_2013-08.JPG"
paris2.languages['ru'].resolve(categories: true)
# => #<ThisIs Париж, 10 categories [img] {48.833333,2.333333}>

Defined Under Namespace

Classes: Ambigous, Link, NotFound

Constant Summary collapse

EXTRACTORS =
{
  title: ->(page) { page.title },
  description: ->(page) { page.source.dig('terms', 'description', 0) },
  coordinates: ->(page) {
    coord = page.source['coordinates']&.first or return nil
    Geo::Coord.from_h(coord)
  },
  categories: ->(page) {
    Array(page.source['categories'])
      .reject { |c| c.key?('hidden') }
      .map { |c| c['title'].split(':', 2).last }
  },
  languages: ->(page) {
    Array(page.source['langlinks'])
      .map { |l| [l['lang'], l['*']] }
      .map { |code, title| [code, Link.new(title, language: code)] }.to_h
      .to_h
  },
  extract: ->(page) {
    # remove HTML tags
    # NB: Wikipedia "extracts" submodule has "plaintext=true" option, but it produces wrong 1-sentece
    # extracts (broken by first ".", which can be somewhere in transcription of the main entity).
    # HTML extracts, on the other hand, return proper sentences
    #
    # Link: https://en.wikipedia.org/w/api.php?action=help&modules=query%2Bextracts
    page.source['extract']&.gsub(/<[^>]+>/, '')&.strip
  },
  image: ->(page) { page.source.dig('original', 'source') }
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(owner, page) ⇒ ThisIs



88
89
90
91
92
# File 'lib/whatis/thisis.rb', line 88

def initialize(owner, page)
  @owner = owner
  @page = page
  @data = EXTRACTORS.map { |sym, proc| [sym, proc.call(page)] }.to_h
end

Instance Attribute Details

#pageInfoboxer::MediaWiki::Page (readonly)



85
86
87
# File 'lib/whatis/thisis.rb', line 85

def page
  @page
end

Class Method Details

.create(owner, title, page) ⇒ Object



72
73
74
75
76
77
78
79
80
81
# File 'lib/whatis/thisis.rb', line 72

def self.create(owner, title, page)
  case
  when page.nil?
    NotFound.new(owner, title)
  when Array(page.source['categories']).any? { |c| owner.ambigous_categories.include?(c['title']) }
    Ambigous.new(owner, page)
  else
    new(owner, page)
  end
end

Instance Method Details

#categoriesArray<String>

List of page’s categories, present only if page was fetched with ‘categories: true` option.



119
# File 'lib/whatis/thisis.rb', line 119

EXTRACTORS.each_key { |title| define_method(title) { @data[title] } }

#coordinatesGeo::Coord

Geographical coordinates, associated with the page, if known, wrapped in [Geo::Coord](github.com/zverok/geo_coord) type.



119
# File 'lib/whatis/thisis.rb', line 119

EXTRACTORS.each_key { |title| define_method(title) { @data[title] } }

#describeDescription



137
138
139
140
141
142
143
144
# File 'lib/whatis/thisis.rb', line 137

def describe(*)
  maxlength = @data.keys.map(&:length).max
  Description.new(
    "#{self}\n" +
      clean_data
        .map { |k, v| "  #{k.to_s.rjust(maxlength)}: #{v.inspect}" }.join("\n")
  )
end

#descriptionString

Short entity description phrase from Wikidata. Not always present.



119
# File 'lib/whatis/thisis.rb', line 119

EXTRACTORS.each_key { |title| define_method(title) { @data[title] } }

#extractString

First sentence of Wikipedia page



119
# File 'lib/whatis/thisis.rb', line 119

EXTRACTORS.each_key { |title| define_method(title) { @data[title] } }

#imageGeo::Coord

URL of page’s main image, if known.



119
# File 'lib/whatis/thisis.rb', line 119

EXTRACTORS.each_key { |title| define_method(title) { @data[title] } }

#inspectString



124
125
126
127
128
129
130
131
132
133
134
# File 'lib/whatis/thisis.rb', line 124

def inspect # rubocop:disable Metrics/AbcSize
  [
    'ThisIs ',
    title,
    languages.iff { |l| l.count == 1 }&.yield_self { |l| l.values.first.title.prepend('/') },
    languages.iff { |l| l.count > 1 }&.yield_self { |l| " +#{l.count} translations" },
    categories.iff(&:any?)&.yield_self { |c| ", #{c.count} categories" },
    image&.yield_self { ' [img]' },
    coordinates&.to_s&.surround(' {', '}')
  ].compact.join.surround('#<', '>')
end

#languagesHash{String => ThisIs::Link}

Hash of other language version of page. Present only if the page wath fetched with ‘:languages` option. Keys are language codes, values are Link objects, allowing to fetch corresponding entities with WhatIs::ThisIs::Link#resolve.



119
# File 'lib/whatis/thisis.rb', line 119

EXTRACTORS.each_key { |title| define_method(title) { @data[title] } }

#titleString Also known as: to_s

Title of Wikipedia page



119
# File 'lib/whatis/thisis.rb', line 119

EXTRACTORS.each_key { |title| define_method(title) { @data[title] } }

#to_hHash



147
148
149
150
151
152
153
154
# File 'lib/whatis/thisis.rb', line 147

def to_h
  {type: 'ThisIs'} # To be at the beginning of a hash
    .merge(@data)
    .merge(
      coordinates: coordinates&.to_s,
      languages: languages.transform_values(&:to_s)
    ).reject { |_, v| v.nil? || v.respond_to?(:empty?) && v.empty? }
end

#to_json(opts) ⇒ String



157
158
159
# File 'lib/whatis/thisis.rb', line 157

def to_json(opts)
  to_h.to_json(opts)
end

#what(**options) ⇒ ThisIs

Refetch page with more data, see WhatIs#this for options explanation. Returns new object.

Options Hash (**options):

  • :languages (true, String, Symbol)
  • :categories (true, false)


167
168
169
# File 'lib/whatis/thisis.rb', line 167

def what(**options)
  @owner.this(title, **options)
end