lib/reality/list.rb in reality-0.0.3 vs lib/reality/list.rb in reality-0.0.4

- old
+ new

@@ -1,32 +1,89 @@ module Reality + # List is subclass of Array, which allows effective entities storing + # and loading. + # + # You can create list from entities or just their names: + # + # ```ruby + # Reality::List.new('Argentina', 'Ukraine') + # # => #<Reality::List[Argentina?, Ukraine?]> + # ``` + # + # ...or from existing entities: + # + # ```ruby + # Reality::List.new(Reality::Entity.new('Argentina'), Reality::Entity.new('Ukraine')) + # # => #<Reality::List[Argentina?, Ukraine?]> + # ``` + # + # List is useful for compact inspect (see above), and for effective + # batch loading (see {#load!}). + # + # Also, List is smart enough to remain List on multiple enumerable + # methods like `#select`, `#reject`, `#map` and so on: + # + # ```ruby + # Reality::List.new('Argentina', 'Bolivia', 'Chile').sample(2) + # # => #<Reality::List[Chile?, Argentina?]> + # + # Reality::List.new('Argentina', 'Bolivia', 'Chile').load!.map(&:capital) + # # => #<Reality::List[Buenos Aires?, La Paz?, Santiago?]> + # ``` + # class List < Array using Refinements - + + # Creates List from a set of entity names or entity objects. + # Also aliased as `Reality::List()` method. + # def initialize(*names) super names.map(&method(:coerce)) end + # Loads all entities in batch. Optimized to make as few requests + # as possible. Typically, when you want to load several entities + # + # @return [self] def load! - partition(&:wikidata_id).tap{|wd, wp| + compact.partition(&:wikidata_id).tap{|wd, wp| load_by_wikipedia(wp) load_by_wikidata(wd) } + # try to fallback to labels: + compact.reject(&:loaded?).tap{|entities| + load_by_wikidata_labels(entities) + } + self end [:select, :reject, :sort, :sort_by, :compact, :-, :map, :first, :last, :sample, :shuffle].each do |sym| define_method(sym){|*args, &block| ensure_type super(*args, &block) } end + # @return [String] def inspect - "#<#{self.class.name}[#{map(&:to_s?).join(', ')}]>" + "#<#{self.class.name}[#{map{|e| e ? e.to_s? : e.inspect}.join(', ')}]>" end + # Prints compact description of the list. Implicitly loads all list + # if not loaded. + # + # ```ruby + # Reality::List.new('Argentina', 'Bolivia', 'Chile').describe + # # ------------------------- + # # #<Reality::List(3 items)> + # # ------------------------- + # # keys: adm_divisions (3), area (3), calling_code (3), capital (3), continent (3), coord (3), country (3), created_at (3), currency (3), gdp_nominal (3), gdp_ppp (3), head_of_government (2), head_of_state (3), highest_point (3), iso2_code (3), iso3_code (3), long_name (3), neighbours (3), official_website (1), organizations (3), part_of (3), population (3), tld (3), tz_offset (3) + # # types: country (3) + # ``` + # + # @return [nil] def describe load! unless all?(&:loaded?) meta = { types: map(&:wikipedia_type).compact.map(&:symbol). @@ -48,11 +105,11 @@ def load_by_wikipedia(entities) return if entities.empty? pages = Infoboxer.wp.get_h(*entities.map(&:name)) datum = Wikidata::Entity. - fetch_list(*pages.values.compact.map(&:title)) + by_wikititle(*pages.values.compact.map(&:title)) entities.each do |entity| page = pages[entity.name] data = page && datum[page.title] entity.setup!(wikipage: page, wikidata: data) @@ -61,29 +118,42 @@ def load_by_wikidata(entities) return if entities.empty? datum = Wikidata::Entity. - fetch_list_by_id(*entities.map(&:wikidata_id)) + by_id(*entities.map(&:wikidata_id)) pages = Infoboxer.wp. get_h(*datum.values.compact.map(&:en_wikipage).compact) entities.each do |entity| data = datum[entity.wikidata_id] page = data && pages[data.en_wikipage] entity.setup!(wikipage: page, wikidata: data) end end + def load_by_wikidata_labels(entities) + return if entities.empty? + + datum = Wikidata::Entity. + by_label(*entities.map(&:name)) + entities.each do |entity| + data = datum[entity.name] + entity.setup!(wikidata: data) + end + end + def ensure_type(arr) - if arr.kind_of?(Array) && arr.all?{|e| e.is_a?(Entity)} + if arr.kind_of?(Array) && arr.all?{|e| e.nil? || e.is_a?(Entity)} List[*arr] else arr end end def coerce(val) case val + when nil + val when String Entity.new(val) when Entity val else