module PicturehouseUk # @api private module Internal # @api private module Parser # Parses screenings page into an array of hashes for an individual cinema class Screenings < Struct.new(:cinema_id) # css for a day of films & screenings LISTINGS = '#this-week .listings > li, #further-ahead .listings > li' # parse the cinema page into an array of screenings attributes # @return [Array] def to_a date = nil doc.css(LISTINGS).each_with_object([]) do |node, result| if node.attribute('title') != nil date = Date.parse(node.attribute('title').value) else result << FilmWithShowtimes.new(node, date).to_a end end.flatten end private def doc @doc ||= Nokogiri::HTML(page) end def page @page ||= PicturehouseUk::Internal::Website.new.cinema(cinema_id) end end end class FilmWithShowtimes < Struct.new(:node, :date) # film name css NAME = '.top-mg-sm a' # variants css VARIANTS = '.film-times .col-xs-10' # The film name # @return [String] def name TitleSanitizer.new(raw_name).sanitized end # Showings hashes # @return [Array] def to_a Array(node.css(VARIANTS)).flat_map do |variant| Variant.new(variant, date).to_a.map do |hash| { film_name: name, dimension: dimension }.merge(hash) end end end private def dimension raw_name.match(/3d/i) ? '3d' : '2d' end def raw_name @raw_name ||= node.css(NAME).children.first.to_s end end class Variant < Struct.new(:node, :date) SHOWTIMES = 'a' VARIENT = '.film-type-desc' def to_a node.css(SHOWTIMES).map do |node| { variant: variant }.merge(Showtime.new(node, date).to_hash) end end private def variant @variant ||= nil end end # parse an individual screening node class Showtime < Struct.new(:node, :date) # the attributes of a single screening # @return [Hash] # @example # PicturehouseUk::Internal::ScreeningParser.new(html).to_hash # => { # booking_url: 'http://...', # time: