cineworld_uk 2.1.6 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -3
  3. data/README.md +56 -14
  4. data/Rakefile +57 -1
  5. data/cineworld_uk.gemspec +1 -2
  6. data/lib/cineworld_uk/cinema.rb +113 -182
  7. data/lib/cineworld_uk/internal/api_response.rb +74 -0
  8. data/lib/cineworld_uk/internal/parser/api/cinema_address.rb +81 -0
  9. data/lib/cineworld_uk/internal/parser/api/film.rb +46 -0
  10. data/lib/cineworld_uk/internal/parser/api/film_lookup.rb +38 -0
  11. data/lib/cineworld_uk/internal/parser/api/performance.rb +46 -0
  12. data/lib/cineworld_uk/internal/parser/api/performances_by_day.rb +50 -0
  13. data/lib/cineworld_uk/internal/title_sanitizer.rb +56 -52
  14. data/lib/cineworld_uk/performance.rb +78 -0
  15. data/lib/cineworld_uk/version.rb +2 -2
  16. data/lib/cineworld_uk.rb +11 -8
  17. data/test/fixtures/api/cinema-detail-10.json +1 -0
  18. data/test/fixtures/api/cinema-detail-21.json +1 -0
  19. data/test/fixtures/api/cinema-detail-3.json +1 -0
  20. data/test/fixtures/api/cinema-detail-96.json +1 -0
  21. data/test/fixtures/api/cinema-list.json +1 -0
  22. data/test/fixtures/api/dates-3.json +1 -0
  23. data/test/fixtures/api/film-list-comingsoon.json +1 -0
  24. data/test/fixtures/api/film-list.json +1 -0
  25. data/test/fixtures/api/performances-tomorrow-3.json +1 -0
  26. data/test/lib/cineworld_uk/cinema_test.rb +96 -197
  27. data/test/lib/cineworld_uk/internal/api_response_test.rb +85 -0
  28. data/test/lib/cineworld_uk/internal/parser/api/cinema_address_test.rb +93 -0
  29. data/test/lib/cineworld_uk/internal/parser/api/film_lookup_test.rb +30 -0
  30. data/test/lib/cineworld_uk/internal/parser/api/film_test.rb +169 -0
  31. data/test/lib/cineworld_uk/internal/parser/api/performance_test.rb +62 -0
  32. data/test/lib/cineworld_uk/internal/title_sanitizer_test.rb +1 -1
  33. data/test/lib/cineworld_uk/{screening_test.rb → performance_test.rb} +36 -48
  34. data/test/support/fixture_reader.rb +44 -0
  35. metadata +48 -59
  36. data/lib/cineworld_uk/film.rb +0 -65
  37. data/lib/cineworld_uk/internal/film_with_screenings_parser.rb +0 -69
  38. data/lib/cineworld_uk/internal/screening_parser.rb +0 -132
  39. data/lib/cineworld_uk/internal/website.rb +0 -35
  40. data/lib/cineworld_uk/internal/whatson_parser.rb +0 -36
  41. data/lib/cineworld_uk/screening.rb +0 -87
  42. data/test/fixture_updater.rb +0 -64
  43. data/test/fixtures/cinemas.html +0 -513
  44. data/test/fixtures/information/brighton.html +0 -1268
  45. data/test/fixtures/information/bristol.html +0 -1265
  46. data/test/fixtures/whatson/brighton/film_first.html +0 -207
  47. data/test/fixtures/whatson/brighton/film_last.html +0 -62
  48. data/test/fixtures/whatson/brighton/film_second.html +0 -347
  49. data/test/fixtures/whatson/brighton.html +0 -7508
  50. data/test/fixtures/whatson/glasgow-imax-at-gsc/film_first.html +0 -182
  51. data/test/fixtures/whatson/the-o2-greenwich/film_first.html +0 -167
  52. data/test/lib/cineworld_uk/film_test.rb +0 -142
  53. data/test/lib/cineworld_uk/internal/film_with_screenings_parser_test.rb +0 -101
  54. data/test/lib/cineworld_uk/internal/website_test.rb +0 -57
  55. data/test/lib/cineworld_uk/internal/whatson_parser_test.rb +0 -58
@@ -1,65 +0,0 @@
1
- module CineworldUk
2
- # The object representing a film on the Cineworld UK website
3
- class Film
4
- include Comparable
5
-
6
- # @return [String] the name of the film
7
- attr_reader :name
8
- # @return [String] the normalized slug derived from the film name
9
- attr_reader :slug
10
-
11
- # @param [String] name the film name
12
- # @return [CineworldUk::Film]
13
- def initialize(name)
14
- @name = name
15
- @slug = name.downcase.gsub(/[^0-9a-z ]/, '').gsub(/\s+/, '-')
16
- end
17
-
18
- # All currently listed films showing at a cinema
19
- # @param [Integer] cinema_id id of the cinema on the website
20
- # @return [Array<CineworldUk::Film>]
21
- def self.at(cinema_id)
22
- whatson_parser(cinema_id).films_with_screenings.map do |html|
23
- new(screenings_parser(html).film_name)
24
- end.uniq
25
- end
26
-
27
- # Allows sort on objects
28
- # @param [CineworldUk::Film] other another film object
29
- # @return [Integer] -1, 0 or 1
30
- def <=>(other)
31
- slug <=> other.slug
32
- end
33
-
34
- # Check an object is the same as another object.
35
- # @param [CineworldUk::Film] other another film
36
- # @return [Boolean] True if both objects are the same exact object, or if
37
- # they are of the same type and share an equal slug
38
- # @note Guided by http://woss.name/2011/01/20/equality-comparison-and-ordering-in-ruby/
39
- def eql?(other)
40
- self.class == other.class && self == other
41
- end
42
-
43
- # Generates hash of slug in order to allow two records of the same type and
44
- # id to work with something like:
45
- #
46
- # [Film.new('ABC'), Film.new('DEF')] & [Film.new('DEF'), Film.new('GHI')]
47
- # #=> [ Film.new('DEF') ]
48
- #
49
- # @return [Integer] hash of slug
50
- # @note Guided by http://woss.name/2011/01/20/equality-comparison-and-ordering-in-ruby/
51
- def hash
52
- slug.hash
53
- end
54
-
55
- private
56
-
57
- def self.screenings_parser(html)
58
- CineworldUk::Internal::FilmWithScreeningsParser.new(html)
59
- end
60
-
61
- def self.whatson_parser(id)
62
- CineworldUk::Internal::WhatsonParser.new(id)
63
- end
64
- end
65
- end
@@ -1,69 +0,0 @@
1
- module CineworldUk
2
- # Internal utility classes: Do not use
3
- # @api private
4
- module Internal
5
- # Parses a chunk of HTML to derive movie showing data
6
- class FilmWithScreeningsParser
7
- # css selector for film name link
8
- FILM_NAME_CSS = 'h3.h1'
9
- # css selector for performances
10
- PERFORMANCES_CSS = '.schedule .performances > li'
11
-
12
- # @param [String] film_html a chunk of html
13
- def initialize(film_html)
14
- @film_html = film_html.to_s
15
- end
16
-
17
- # The film name
18
- # @return [String]
19
- def film_name
20
- title_sanitizer(film_name_text.children[0].to_s)
21
- end
22
-
23
- # attributes of all the screenings
24
- # @return [Array<Hash>]
25
- def to_a
26
- return [] unless performances_doc
27
-
28
- performances_doc.map do |node|
29
- next unless screening_parser_hash(node)
30
- screening_parser_hash(node).merge(film_hash)
31
- end.compact
32
- end
33
-
34
- private
35
-
36
- def doc
37
- @doc ||= Nokogiri::HTML(@film_html)
38
- end
39
-
40
- def film_hash
41
- @film_hash ||= { film_name: film_name }
42
- end
43
-
44
- def film_link
45
- @film_link ||= film_name_doc.css('a[href*=whatson]')
46
- end
47
-
48
- def film_name_text
49
- film_link.empty? ? film_name_doc : film_link
50
- end
51
-
52
- def film_name_doc
53
- @film_name_doc ||= doc.css(FILM_NAME_CSS)
54
- end
55
-
56
- def performances_doc
57
- @performances_doc ||= doc.css(PERFORMANCES_CSS)
58
- end
59
-
60
- def screening_parser_hash(node)
61
- ScreeningParser.new(node).to_hash
62
- end
63
-
64
- def title_sanitizer(title)
65
- TitleSanitizer.new(title).sanitized
66
- end
67
- end
68
- end
69
- end
@@ -1,132 +0,0 @@
1
- module CineworldUk
2
- # Internal utility classes: Do not use
3
- # @api private
4
- module Internal
5
- # parse a single performance
6
- class ScreeningParser
7
- # regex for date in url
8
- DATE_REGEX = /date\=(\d{4})(\d{2})(\d{2})/
9
- # regex for time in url
10
- TIME_REGEX = /time\=(\d{2})\:(\d{2})/
11
-
12
- # css selector for dimension
13
- DIMENSION_CSS = '.icon-service-2d, .icon-service-3d'
14
- # css selector for baby screening
15
- BABY_CSS = '.icon-service-cb'
16
- # css selector for d-box screening
17
- DBOX_CSS = '.icon-service-dx'
18
- # css selector for hfr screening
19
- HFR_CSS = '.icon-service-hfr'
20
- # css selector for imax screening
21
- IMAX_CSS = '.icon-service-ix'
22
- # css selector for kids screening
23
- KIDS_CSS = '.icon-service-m4j'
24
-
25
- # @param [String] html a chunk of html representing one screening
26
- def initialize(html)
27
- @html = html.to_s
28
- end
29
-
30
- # url to book this screening
31
- # @return [String]
32
- def booking_url
33
- return unless bookable?
34
- 'http://www.cineworld.co.uk' + doc.css('a').attribute('href')
35
- end
36
-
37
- # the dimension of the screening
38
- # @return [String]
39
- def dimension
40
- return unless bookable?
41
- doc.css(DIMENSION_CSS).text.downcase
42
- end
43
-
44
- # utc time of the screening
45
- # @return [Time]
46
- def time
47
- return unless bookable?
48
- timezone.local_to_utc(Time.utc(*date_array + time_array))
49
- end
50
-
51
- # anything special about the screening
52
- # @return [Array<String>]
53
- # @example
54
- # Cineworld::Internal::ScreeningParser.new(html).tags
55
- # => ["imax"]
56
- def variant
57
- return unless bookable?
58
- [baby, dbox, hfr, imax, kids].compact
59
- end
60
-
61
- # a attributes of a single screening
62
- # @return [Hash]
63
- # @example
64
- # Cineworld::Internal::ScreeningParser.new(html).to_hash
65
- # => {
66
- # booking_url: 'http://...',
67
- # dimension: '2d',
68
- # time: <Time>,
69
- # variant: ['imax']
70
- # }
71
- def to_hash
72
- return unless bookable?
73
- {
74
- booking_url: booking_url,
75
- dimension: dimension,
76
- time: time,
77
- variant: variant
78
- }
79
- end
80
-
81
- private
82
-
83
- def baby
84
- 'baby' if doc.css(BABY_CSS).length > 0
85
- end
86
-
87
- def bookable?
88
- @bookable ||= doc.css('a.performance').size > 0
89
- end
90
-
91
- def date_array
92
- @date_array ||= performance_link_html.match(DATE_REGEX) do |match|
93
- [match[1], match[2], match[3]]
94
- end
95
- end
96
-
97
- def dbox
98
- 'dbox' if doc.css(DBOX_CSS).length > 0
99
- end
100
-
101
- def doc
102
- @doc ||= Nokogiri::HTML(@html)
103
- end
104
-
105
- def hfr
106
- 'hfr' if doc.css(HFR_CSS).length > 0
107
- end
108
-
109
- def imax
110
- 'imax' if doc.css(IMAX_CSS).length > 0
111
- end
112
-
113
- def kids
114
- 'kids' if doc.css(KIDS_CSS).length > 0
115
- end
116
-
117
- def performance_link_html
118
- @performance_link_html ||= doc.css('a.performance').to_s
119
- end
120
-
121
- def time_array
122
- @time_array ||= performance_link_html.match(TIME_REGEX) do |match|
123
- [match[1], match[2]]
124
- end
125
- end
126
-
127
- def timezone
128
- @timezone ||= TZInfo::Timezone.get('Europe/London')
129
- end
130
- end
131
- end
132
- end
@@ -1,35 +0,0 @@
1
- # encoding: UTF-8
2
- require 'open-uri'
3
-
4
- module CineworldUk
5
- # Internal utility classes: Do not use
6
- # @api private
7
- module Internal
8
- # fetches pages from the cineworld.co.uk website
9
- class Website
10
- # get the cinema information page for passed id
11
- # @return [String]
12
- def cinema_information(id)
13
- get("cinemas/#{id}/information")
14
- end
15
-
16
- # get the cinemas page
17
- # @return [String]
18
- def cinemas
19
- get('cinemas')
20
- end
21
-
22
- # get the cinema page containing all upcoming films and screenings
23
- # @return [String]
24
- def whatson(id)
25
- get("whatson?cinema=#{id}")
26
- end
27
-
28
- private
29
-
30
- def get(path)
31
- open("http://www.cineworld.co.uk/#{path}").read
32
- end
33
- end
34
- end
35
- end
@@ -1,36 +0,0 @@
1
- module CineworldUk
2
- # Internal utility classes: Do not use
3
- # @api private
4
- module Internal
5
- # Parses a chunk of HTML to derive movie showing data
6
- class WhatsonParser
7
- # css selector for film html chunks
8
- FILM_CSS = '#filter-reload > .span9 > .film'
9
-
10
- # @param [Integer] cinema_id cineworld cinema id
11
- def initialize(cinema_id)
12
- @cinema_id = cinema_id
13
- end
14
-
15
- # break up the whats on page into individual chunks for each film
16
- # @return [Array<String>] html chunks for a film and it's screenings
17
- def films_with_screenings
18
- films_html
19
- end
20
-
21
- private
22
-
23
- def films_html
24
- whatson_doc.css(FILM_CSS).map { |n| n.to_s.gsub(/^\s+/, '') }
25
- end
26
-
27
- def whatson
28
- @whatson ||= CineworldUk::Internal::Website.new.whatson(@cinema_id)
29
- end
30
-
31
- def whatson_doc
32
- @whatson_doc ||= Nokogiri::HTML(whatson)
33
- end
34
- end
35
- end
36
- end
@@ -1,87 +0,0 @@
1
- module CineworldUk
2
- # The object representing a single screening on the Cineworld UK website
3
- class Screening
4
- # @return [String] the booking URL on the cinema website
5
- attr_reader :booking_url
6
- # @return [String] 2d or 3d
7
- attr_reader :dimension
8
- # @return [String] the cinema name
9
- attr_reader :cinema_name
10
- # @return [String] the film name
11
- attr_reader :film_name
12
-
13
- # @param [Hash] options options hash
14
- # @option options [String] :booking_url (nil) booking url for the screening
15
- # @option options [String] :cinema_name name of the cinema
16
- # @option options [String] :cinema_id website id of the cinema
17
- # @option options [String] :dimension ('2d') dimension of the screening
18
- # @option options [String] :film_name name of the film
19
- # @option options [Time] :time utc time of the screening
20
- # @option options [Array<String>] :variant ([]) type of screening
21
- def initialize(options)
22
- @booking_url = options.fetch(:booking_url, nil)
23
- @cinema_name = options.fetch(:cinema_name)
24
- @cinema_id = options.fetch(:cinema_id)
25
- @dimension = options.fetch(:dimension, '2d')
26
- @film_name = options.fetch(:film_name)
27
- @time = options.fetch(:time)
28
- @variant = options.fetch(:variant, [])
29
- end
30
-
31
- # All currently listed films showing at a cinema
32
- # @param [Integer] cinema_id id of the cinema on the website
33
- # @return [Array<CineworldUk::Screening>]
34
- def self.at(cinema_id)
35
- whatson_parser(cinema_id).films_with_screenings.flat_map do |html|
36
- create_for_single_film(html, cinema_id)
37
- end
38
- end
39
-
40
- # The date of the screening
41
- # @return [Date]
42
- def showing_on
43
- showing_at.to_date
44
- end
45
-
46
- # The UTC time of the screening
47
- # @return [Time]
48
- def showing_at
49
- @when ||= begin
50
- if @time.utc?
51
- @time
52
- else
53
- TZInfo::Timezone.get('Europe/London').local_to_utc(@time)
54
- end
55
- end
56
- end
57
-
58
- # The kinds of screening
59
- # @return <Array[String]>
60
- def variant
61
- @variant.map(&:downcase).sort
62
- end
63
-
64
- private
65
-
66
- def self.cinema_hash(cinema_id)
67
- {
68
- cinema_id: cinema_id,
69
- cinema_name: CineworldUk::Cinema.find(cinema_id).name
70
- }
71
- end
72
-
73
- def self.create_for_single_film(html, cinema_id)
74
- screenings_parser(html).to_a.map do |attributes|
75
- new cinema_hash(cinema_id).merge(attributes)
76
- end
77
- end
78
-
79
- def self.screenings_parser(html)
80
- CineworldUk::Internal::FilmWithScreeningsParser.new(html)
81
- end
82
-
83
- def self.whatson_parser(id)
84
- CineworldUk::Internal::WhatsonParser.new(id)
85
- end
86
- end
87
- end
@@ -1,64 +0,0 @@
1
- require File.expand_path('../../lib/cineworld_uk.rb', __FILE__)
2
-
3
- def fixture(name)
4
- File.expand_path("../fixtures/#{name}.html", __FILE__)
5
- end
6
-
7
- File.open(fixture('cinemas'), 'w') do |file|
8
- puts '* Cinemas'
9
- file.write CineworldUk::Internal::Website.new.cinemas
10
- end
11
-
12
- # BRIGHTON
13
-
14
- File.open(fixture('information/brighton'), 'w') do |file|
15
- puts '* Brighton Information'
16
- file.write CineworldUk::Internal::Website.new.cinema_information(3)
17
- end
18
-
19
- File.open(fixture('whatson/brighton'), 'w') do |file|
20
- puts '* Brighton Whats On'
21
- file.write CineworldUk::Internal::Website.new.whatson(3)
22
- end
23
-
24
- parser = CineworldUk::Internal::WhatsonParser.new(3)
25
-
26
- File.open(fixture('whatson/brighton/film_first'), 'w') do |file|
27
- puts '* Brighton Main Film'
28
- file.write parser.films_with_screenings[0]
29
- end
30
-
31
- File.open(fixture('whatson/brighton/film_second'), 'w') do |file|
32
- puts '* Brighton Second Film'
33
- file.write parser.films_with_screenings[1]
34
- end
35
-
36
- File.open(fixture('whatson/brighton/film_last'), 'w') do |file|
37
- puts '* Brighton Last Film'
38
- file.write parser.films_with_screenings[-1]
39
- end
40
-
41
- # BRISTOL
42
-
43
- File.open(fixture('information/bristol'), 'w') do |file|
44
- puts '* Bristol Information'
45
- file.write CineworldUk::Internal::Website.new.cinema_information(4)
46
- end
47
-
48
- # O2
49
-
50
- parser = CineworldUk::Internal::WhatsonParser.new(79)
51
-
52
- File.open(fixture('whatson/the-o2-greenwich/film_first'), 'w') do |file|
53
- puts '* The O2 Greenwich Main Film'
54
- file.write parser.films_with_screenings[0]
55
- end
56
-
57
- # GLASGOW IMAX
58
-
59
- parser = CineworldUk::Internal::WhatsonParser.new(88)
60
-
61
- File.open(fixture('whatson/glasgow-imax-at-gsc/film_first'), 'w') do |file|
62
- puts '* Glasgow IMAX Main Film'
63
- file.write parser.films_with_screenings[0]
64
- end