cineworld_uk 1.0.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +64 -0
  4. data/README.md +2 -1
  5. data/cineworld_uk.gemspec +3 -3
  6. data/lib/cineworld_uk/cinema.rb +60 -69
  7. data/lib/cineworld_uk/film.rb +25 -7
  8. data/lib/cineworld_uk/internal/film_with_screenings_parser.rb +29 -71
  9. data/lib/cineworld_uk/internal/name_parser.rb +20 -18
  10. data/lib/cineworld_uk/internal/screening_parser.rb +132 -0
  11. data/lib/cineworld_uk/internal/titleize.rb +19 -19
  12. data/lib/cineworld_uk/internal/website.rb +33 -0
  13. data/lib/cineworld_uk/internal/whatson_parser.rb +44 -0
  14. data/lib/cineworld_uk/screening.rb +65 -20
  15. data/lib/cineworld_uk/version.rb +2 -2
  16. data/lib/cineworld_uk.rb +4 -0
  17. data/test/fixture_updater.rb +64 -0
  18. data/test/fixtures/cinemas.html +134 -41
  19. data/test/fixtures/{cinemas/bury-st-edmunds.html → information/brighton.html} +488 -437
  20. data/test/fixtures/{cinemas → information}/bristol.html +463 -410
  21. data/test/fixtures/whatson/brighton/film_first.html +775 -0
  22. data/test/fixtures/whatson/brighton/film_last.html +52 -0
  23. data/test/fixtures/whatson/brighton/film_second.html +645 -0
  24. data/test/fixtures/whatson/brighton.html +3564 -2690
  25. data/test/fixtures/whatson/glasgow-imax-at-gsc/film_first.html +140 -0
  26. data/test/fixtures/whatson/the-o2-greenwich/film_first.html +1242 -0
  27. data/test/lib/cineworld_uk/cinema_test.rb +104 -301
  28. data/test/lib/cineworld_uk/film_test.rb +49 -2
  29. data/test/lib/cineworld_uk/internal/film_with_screenings_parser_test.rb +83 -81
  30. data/test/lib/cineworld_uk/internal/titleize_test.rb +12 -5
  31. data/test/lib/cineworld_uk/internal/website_test.rb +57 -0
  32. data/test/lib/cineworld_uk/internal/whatson_parser_test.rb +58 -0
  33. data/test/lib/cineworld_uk/screening_test.rb +155 -23
  34. data/test/lib/cineworld_uk/version_test.rb +1 -1
  35. data/test/test_helper.rb +3 -1
  36. metadata +30 -33
  37. data/test/fixtures/cinemas/brighton.html +0 -8
  38. data/test/fixtures/cinemas/chelsea.html +0 -1030
  39. data/test/fixtures/cinemas/glasgow-imax-at-gsc.html +0 -916
  40. data/test/fixtures/cinemas/the-o2-grenwich.html +0 -1191
  41. data/test/fixtures/whatson/brighton/gravity.html +0 -2129
  42. data/test/fixtures/whatson/glasgow-imax-at-gsc/the-hunger-games-catching-fire.html +0 -498
  43. data/test/fixtures/whatson/glasgow-imax-at-gsc-cinema.html +0 -3160
  44. data/test/fixtures/whatson/the-o2-greenwich/gravity.html +0 -784
  45. data/test/fixtures/whatson/the-o2-greenwich/the-hobbit-desolation-of-smaug.html +0 -764
  46. data/test/fixtures/whatson/the-o2-greenwich.html +0 -6854
  47. data/test/fixtures/whatson/wandsworth.html +0 -13729
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c228d909dc018b2ffa88f58841c53df17355f4c
4
- data.tar.gz: 65837db94438ac24f9e8460f1765495835a482fc
3
+ metadata.gz: edcee9dcbbce90d73acbbb0ccc5650811bb7f931
4
+ data.tar.gz: 8454e532aa948af962692ce9d1add716b79dd405
5
5
  SHA512:
6
- metadata.gz: 02646d623f4f7d13a8f3927283be7d17a9dbe0e8f8e2e3c3d1b31d40075858e28b6fb7b2aae321b72b3c1a25ab608f3821369bb2f608ebde31b75d1baa798130
7
- data.tar.gz: 6cabf2784246c4d1816537221abd885ba19bbbca46335a6d5b1830e7da23e99914ae057e46c13d4182184fa0c6330fc07da06a3ed9f45578f231e898cac0a7d6
6
+ metadata.gz: 55369938b4df8ad874982a708dccb985b48f1514d2a6210e24371bcdf66f575dde627456cb4567fda757d37759bb9b0d7d6cccb8e2ed1865e2f70d7134ebefcf
7
+ data.tar.gz: 9d79dc209c5091269612dc732388d5160876defdaeef29ec7820656e5c1c3f32203144194dd5cfbc44b85ef5a1c041456a2a7974ff132941e79e9a894f6a3fd7
data/.travis.yml CHANGED
@@ -2,4 +2,4 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
- - 2.1.0
5
+ - 2.1.2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,67 @@
1
+ ## 2.0.0 _25th July 2014_
2
+
3
+ Bugfix
4
+
5
+ - Cineworld changed their markup
6
+
7
+ Features
8
+
9
+ - Less logic in the Cinema class. Moved to `Film` and `Screening`.
10
+ - Introduce `Internal::Website` class for all website comms
11
+ - Rewrite Parsers and tests to be less exact but less fragile
12
+ - Screening now uses the `FilmWithScreeningsParser`
13
+ - Build `WhatsonParser` to break into 'films with screenings'
14
+ - `FilmWithScreenings` then uses `ScreeningParser` class to get individual screening info
15
+ - `ruby test/fixture_updator.rb` produces new fixtures from the live website
16
+ - it will break a few tests when run and committed but most should be ok
17
+ - documentation
18
+
19
+ Under the hood
20
+
21
+ - Remove dependancy on HTTParty
22
+ - Travis gets Ruby 2.1.2
23
+ - General Rubocop improvements
24
+
25
+ ## 1.0.6 _28th Feb 2014_
26
+
27
+ Bugfix
28
+
29
+ - UTF encoding in Titleize internal class for ruby 1.9.3
30
+
31
+ ## 1.0.5 _28th Feb 2014_
32
+
33
+ Bugfix
34
+
35
+ - Vestigal require of titleize gem
36
+
37
+ ## 1.0.4 _27th Feb 2014_
38
+
39
+ Under the hood
40
+
41
+ - Standardizing film names using modified titlecase from `titlecase` gem
42
+ - Film name parsing now moved to seperate class
43
+ - rake console task added
44
+ - MRI 2.1.0 support on Travis CI
45
+
46
+ ## 1.0.3, _16th Jan 2014_
47
+
48
+ Additional methods
49
+
50
+ - cinema#full_name including cinema brand
51
+ - tidy up cinema naming to use colons
52
+
53
+ ## 1.0.2, _3rd Jan 2014_
54
+
55
+ Under the hood
56
+
57
+ - deal with HFR screenings, bloody hobbitses
58
+
59
+ ## 1.0.1, _3rd Jan 2014_
60
+
61
+ External interface
62
+
63
+ - screening#variant for spelling win, #varient maintained for compatability
64
+
1
65
  ## 1.0.0, _6th Dec 2013_
2
66
 
3
67
  First ready-for-public release
data/README.md CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  A simple gem to parse the [Cineworld UK website](http://cineworld.co.uk) and spit out useful formatted info.
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/cineword_uk.png)](http://badge.fury.io/rb/cineworld_uk)
5
+ [![Gem Version](https://badge.fury.io/rb/cineworld_uk.svg)](http://badge.fury.io/rb/cineworld_uk)
6
6
  [![Code Climate](https://codeclimate.com/github/andycroll/cineworld_uk.png)](https://codeclimate.com/github/andycroll/cineworld_uk)
7
7
  [![Build Status](https://travis-ci.org/andycroll/cineworld_uk.png?branch=master)](https://travis-ci.org/andycroll/cineworld_uk)
8
+ [![Inline docs](http://inch-ci.org/github/andycroll/cineworld_uk.png)](http://inch-ci.org/github/andycroll/cineworld_uk)
8
9
 
9
10
  ## Installation
10
11
 
data/cineworld_uk.gemspec CHANGED
@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'minitest-reporters'
23
+ spec.add_development_dependency 'rake'
23
24
  spec.add_development_dependency 'webmock'
24
25
 
25
- spec.add_runtime_dependency 'httparty'
26
26
  spec.add_runtime_dependency 'nokogiri'
27
27
  spec.add_runtime_dependency 'tzinfo'
28
28
  spec.add_runtime_dependency 'tzinfo-data'
@@ -1,11 +1,9 @@
1
1
  module CineworldUk
2
-
3
2
  # The object representing a cinema on the Cineworld UK website
4
3
  class Cinema
5
-
6
4
  # @return [String] the brand of the cinema
7
5
  attr_reader :brand
8
- # @return [Integer] the numeric id of the cinema on the Odeon website
6
+ # @return [Integer] the numeric id of the cinema on the Cineworld website
9
7
  attr_reader :id
10
8
  # @return [String] the name of the cinema
11
9
  attr_reader :name
@@ -20,8 +18,8 @@ module CineworldUk
20
18
  def initialize(id, name)
21
19
  @brand = 'Cineworld'
22
20
  @id = id.to_i
23
- @name = name.gsub('London - ','').gsub(' - ', ': ')
24
- @slug = @name.downcase.gsub(/[^0-9a-z ]/,'').gsub(/\s+/, '-')
21
+ @name = name.gsub('London - ', '').gsub(' - ', ': ')
22
+ @slug = @name.downcase.gsub(/[^0-9a-z ]/, '').gsub(/\s+/, '-')
25
23
  @url = "http://www.cineworld.co.uk/cinemas/#{@id}/information"
26
24
  end
27
25
 
@@ -29,32 +27,39 @@ module CineworldUk
29
27
  # @return [Array<CineworldUk::Cinema>]
30
28
  # @example
31
29
  # CineworldUk::Cinema.all
32
- # #=> [<CineworldUk::Cinema brand="Cineworld" name="Brighton" slug="brighton" id=3 url="...">, <CineworldUk::Cinema brand="Cineworld" name="The O2, Greenwich" slug="the-o2-greenwich" url="...">, ...]
30
+ # #=> [<CineworldUk::Cinema>, <CineworldUk::Cinema>, ...]
33
31
  def self.all
34
- parsed_cinemas.css('#cinemaId option[value]').map do |option|
32
+ cinemas_doc.css('#cinemaId option[value]').map do |option|
35
33
  new option['value'], option.text
36
34
  end[1..-1]
37
35
  end
38
36
 
39
37
  # Find a single cinema
40
- # @param [Integer, String] id the cinema id of the format 3/'3' as used on the cineworld.co.uk website
38
+ # @param [Integer, String] id the cinema id as used on the website
41
39
  # @return [CineworldUk::Cinema, nil]
42
40
  # @example
43
41
  # CineworldUk::Cinema.find('3')
44
- # #=> <CineworldUk::Cinema brand="Cineworld" name="Brighton" slug="brighton" id=3 url="...">
42
+ # #=> <CineworldUk::Cinema brand="Cineworld"
43
+ # name="Brighton"
44
+ # slug="brighton"
45
+ # id=3
46
+ # url="...">
45
47
  def self.find(id)
46
- id = id.to_i
47
- return nil unless id > 0
48
-
49
- all.select { |cinema| cinema.id == id }[0]
48
+ all.select { |cinema| cinema.id == id.to_i }[0]
50
49
  end
51
50
 
52
51
  # Address of the cinema
53
52
  # @return [Hash] of different address parts
54
53
  # @example
55
- # cinema = CineworldUk::Cinema.find('Dukes_At_Komedia')
54
+ # cinema = CineworldUk::Cinema.find(3)
56
55
  # cinema.adr
57
- # #=> { street_address: '44-47 Gardner Street', extended_address: 'North Laine', locality: 'Brighton', postal_code: 'BN1 1UN', country_name: 'United Kingdom' }
56
+ # #=> {
57
+ # street_address: '44-47 Gardner Street',
58
+ # extended_address: 'North Laine',
59
+ # locality: 'Brighton',
60
+ # postal_code: 'BN1 1UN',
61
+ # country_name: 'United Kingdom'
62
+ # }
58
63
  # @note Uses the standard method naming as at http://microformats.org/wiki/adr
59
64
  def adr
60
65
  {
@@ -80,20 +85,17 @@ module CineworldUk
80
85
  # #=> nil
81
86
  # @note Uses the standard method naming as at http://microformats.org/wiki/adr
82
87
  def extended_address
83
- remaining_address * ', ' unless remaining_address.empty?
88
+ remaining_address * ', ' unless remaining_address.empty?
84
89
  end
85
90
 
86
91
  # Films with showings scheduled at this cinema
87
- # @return [Array<OdeonUk::Film>]
92
+ # @return [Array<CineworldUk::Film>]
88
93
  # @example
89
- # cinema = OdeonUk::Cinema.find('71')
94
+ # cinema = CineworldUk::Cinema.find('71')
90
95
  # cinema.films
91
- # #=> [<OdeonUk::Film name="Iron Man 3">, <OdeonUk::Film name="Star Trek Into Darkness">]
96
+ # #=> [<CineworldUk::Film>, <CineworldUk::Film>, ...]
92
97
  def films
93
- film_nodes.map do |node|
94
- parser = CineworldUk::Internal::FilmWithScreeningsParser.new node.to_s
95
- parser.film_name.length > 0 ? CineworldUk::Film.new(parser.film_name) : nil
96
- end.compact.uniq
98
+ Film.at(id)
97
99
  end
98
100
 
99
101
  # The name of the cinema including the brand
@@ -114,7 +116,11 @@ module CineworldUk
114
116
  # #=> 'Brighton'
115
117
  # @note Uses the standard method naming as at http://microformats.org/wiki/adr
116
118
  def locality
117
- adr_has_region? && !adr_in_london? ? final_address_array[-2] : final_address_array[-1]
119
+ if adr_has_region? && !adr_in_london?
120
+ adr_array[-2]
121
+ else
122
+ adr_array[-1]
123
+ end
118
124
  end
119
125
 
120
126
  # Post code of the cinema
@@ -125,7 +131,7 @@ module CineworldUk
125
131
  # #=> 'BN2 5UF'
126
132
  # @note Uses the standard method naming as at http://microformats.org/wiki/adr
127
133
  def postal_code
128
- final_line_array[-2..-1]*' '
134
+ last_adr_line_array[-2..-1] * ' '
129
135
  end
130
136
 
131
137
  # The region (county) of the cinema if provided
@@ -136,7 +142,7 @@ module CineworldUk
136
142
  # #=> 'East Sussex'
137
143
  # @note Uses the standard method naming as at http://microformats.org/wiki/adr
138
144
  def region
139
- final_line_non_postal_code if adr_has_region? && !adr_in_london?
145
+ last_adr_line_non_postal_code if adr_has_region? && !adr_in_london?
140
146
  end
141
147
 
142
148
  # All planned screenings
@@ -144,16 +150,9 @@ module CineworldUk
144
150
  # @example
145
151
  # cinema = CineworldUk::Cinema.find(3)
146
152
  # cinema.screenings
147
- # # => [<CineworldUk::Screening film_name="Iron Man 3" cinema_name="Brighton" when="..." variant="...">, <CineworldUk::Screening ...>]
153
+ # # => [<CineworldUk::Screening>, <CineworldUk::Screening>, ...]
148
154
  def screenings
149
- film_nodes.map do |node|
150
- parser = CineworldUk::Internal::FilmWithScreeningsParser.new node.to_s
151
- parser.showings.map do |screening_type, times|
152
- times.map do |array|
153
- CineworldUk::Screening.new parser.film_name, self.name, array[0], array[1], screening_type
154
- end
155
- end
156
- end.flatten
155
+ Screening.at(id)
157
156
  end
158
157
 
159
158
  # The street adress of the cinema
@@ -164,65 +163,57 @@ module CineworldUk
164
163
  # #=> 'Brighton Marina'
165
164
  # @note Uses the standard method naming as at http://microformats.org/wiki/adr
166
165
  def street_address
167
- address_parts[0]
166
+ adr_parts[0]
168
167
  end
169
168
 
170
169
  private
171
170
 
172
- def self.parsed_cinemas
173
- @parsed_cinemas ||= Nokogiri::HTML(cinemas_response)
174
- end
175
-
176
- def self.cinemas_response
177
- @cinemas_response ||= HTTParty.get('http://www.cineworld.co.uk/cinemas')
178
- end
179
-
180
- def address_parts
181
- @address_parts ||= parsed_information.css('address.marker').to_s.split('<br>')[-2].split(',').map(&:strip)
171
+ def self.cinemas_doc
172
+ @cinemas_doc ||= Nokogiri::HTML(website.cinemas)
182
173
  end
183
174
 
184
- def adr_in_london?
185
- final_line_non_postal_code == 'London'
175
+ def self.website
176
+ @website ||= CineworldUk::Internal::Website.new
186
177
  end
187
178
 
188
- def adr_has_region?
189
- final_line_non_postal_code != name
179
+ def adr_array
180
+ adr_parts[0..-2] << last_adr_line_non_postal_code
190
181
  end
191
182
 
192
- def film_nodes
193
- @film_nodes ||= parsed_whatson.css('.section.light #filter-reload > .span9').to_s.split('<hr>')
183
+ def adr_content
184
+ information_doc.css('address.marker').to_s
194
185
  end
195
186
 
196
- def final_address_array
197
- address_parts[0..-2] << final_line_non_postal_code
187
+ def adr_parts
188
+ @parts ||= adr_content.split('<br>')[-2].split(',').map(&:strip)
198
189
  end
199
190
 
200
- def final_line_array
201
- address_parts[-1].split(' ')
191
+ def adr_in_london?
192
+ last_adr_line_non_postal_code == 'London'
202
193
  end
203
194
 
204
- def final_line_non_postal_code
205
- final_line_array[0..-3]*' '
195
+ def adr_has_region?
196
+ last_adr_line_non_postal_code != name
206
197
  end
207
198
 
208
- def information_response
209
- @information_response ||= HTTParty.get("http://www.cineworld.co.uk/cinemas/#{@id}/information")
199
+ def last_adr_line_array
200
+ adr_parts[-1].split(' ')
210
201
  end
211
202
 
212
- def parsed_information
213
- @parsed_information ||= Nokogiri::HTML(information_response)
203
+ def last_adr_line_non_postal_code
204
+ last_adr_line_array[0..-3] * ' '
214
205
  end
215
206
 
216
- def parsed_whatson
217
- @parsed_whatson ||= Nokogiri::HTML(whatson_response)
207
+ def information_doc
208
+ @information_doc ||= begin
209
+ Nokogiri::HTML(CineworldUk::Internal::Website.new.information(@id))
210
+ end
218
211
  end
219
212
 
220
213
  def remaining_address
221
- final_address_array.delete_if { |e| e == street_address || e == locality || e == region }
222
- end
223
-
224
- def whatson_response
225
- @whatson_response ||= HTTParty.get("http://www.cineworld.co.uk/whatson?cinema=#{@id}")
214
+ adr_array.delete_if do |e|
215
+ e == street_address || e == locality || e == region
216
+ end
226
217
  end
227
218
  end
228
219
  end
@@ -1,5 +1,4 @@
1
1
  module CineworldUk
2
-
3
2
  # The object representing a film on the Cineworld UK website
4
3
  class Film
5
4
  include Comparable
@@ -13,14 +12,23 @@ module CineworldUk
13
12
  # @return [CineworldUk::Film]
14
13
  def initialize(name)
15
14
  @name = name
16
- @slug = name.downcase.gsub(/[^0-9a-z ]/,'').gsub(/\s+/, '-')
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
17
25
  end
18
26
 
19
27
  # Allows sort on objects
20
28
  # @param [CineworldUk::Film] other another film object
21
29
  # @return [Integer] -1, 0 or 1
22
- def <=> other
23
- self.slug <=> other.slug
30
+ def <=>(other)
31
+ slug <=> other.slug
24
32
  end
25
33
 
26
34
  # Check an object is the same as another object.
@@ -28,20 +36,30 @@ module CineworldUk
28
36
  # @return [Boolean] True if both objects are the same exact object, or if
29
37
  # they are of the same type and share an equal slug
30
38
  # @note Guided by http://woss.name/2011/01/20/equality-comparison-and-ordering-in-ruby/
31
- def eql? other
39
+ def eql?(other)
32
40
  self.class == other.class && self == other
33
41
  end
34
42
 
35
43
  # Generates hash of slug in order to allow two records of the same type and
36
44
  # id to work with something like:
37
45
  #
38
- # [ Film.new('ABC'), Film.new('DEF') ] & [ Film.new('DEF'), Film.new('GHI') ]
46
+ # [Film.new('ABC'), Film.new('DEF')] & [Film.new('DEF'), Film.new('GHI')]
39
47
  # #=> [ Film.new('DEF') ]
40
48
  #
41
49
  # @return [Integer] hash of slug
42
50
  # @note Guided by http://woss.name/2011/01/20/equality-comparison-and-ordering-in-ruby/
43
51
  def hash
44
- self.slug.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)
45
63
  end
46
64
  end
47
65
  end
@@ -1,102 +1,60 @@
1
1
  module CineworldUk
2
-
3
2
  # Internal utility classes: Do not use
4
3
  # @api private
5
4
  module Internal
6
-
7
5
  # Parses a chunk of HTML to derive movie showing data
8
6
  class FilmWithScreeningsParser
7
+ # css selector for film name
8
+ FILM_NAME_CSS = 'h3.h1 a[href*=whatson]'
9
+ # css selector for performances
10
+ PERFORMANCES_CSS = '.schedule .performances > li'
9
11
 
10
12
  # @param [String] film_html a chunk of html
11
13
  def initialize(film_html)
12
- @nokogiri_html = Nokogiri::HTML(film_html)
14
+ @film_html = film_html.to_s
15
+ end
16
+
17
+ # The cinema id
18
+ # @return [String]
19
+ def cinema_id
20
+ name_doc.to_s.match(/cinema=(\d+)/)[1].to_i
13
21
  end
14
22
 
15
23
  # The film name
16
24
  # @return [String]
17
25
  def film_name
18
- NameParser.new(original_name).standardize
26
+ name_doc.children[0].to_s
19
27
  end
20
28
 
21
- # Showings
22
- # @return [Hash]
23
- # @example
24
- # {
25
- # "2D" => [Time.utc, Time.utc]
26
- # }
27
- def showings
28
- tz = TZInfo::Timezone.get('Europe/London')
29
- @nokogiri_html.css('.schedule .performances > li').inject({}) do |result, li|
30
- key = performance_variant(li)
31
-
32
- if has_bookable_link_node?(li)
33
- time_array = performance_date_array(li) + performance_time_array(li)
34
- time = tz.local_to_utc(Time.utc(*time_array))
35
- result.merge(key => (result[key] || []) << [time, booking_url(li)])
36
- else
37
- result
38
- end
39
- end
29
+ # attributes of all the screenings
30
+ # @return [Array<Hash>]
31
+ def to_a
32
+ performances_doc.map do |node|
33
+ next unless screening_parser_hash(node)
34
+ screening_parser_hash(node).merge(film_hash)
35
+ end.compact
40
36
  end
41
37
 
42
38
  private
43
39
 
44
- def booking_url(node)
45
- 'http://www.cineworld.co.uk' + performance_link(node)['href']
46
- end
47
-
48
- def dbox?(node)
49
- node.css('.tooltip-box .icon-service-dbox').count > 0
50
- end
51
-
52
- def dimension(node)
53
- node.css('.tooltip-box .icon-service-twod, .tooltip-box .icon-service-thrd').text
54
- end
55
-
56
- def has_bookable_link_node?(node)
57
- performance_link(node) != nil
58
- end
59
-
60
- def imax?(node)
61
- node.css('.tooltip-box .icon-service-imax').count > 0
62
- end
63
-
64
- def hfr?(node)
65
- node.css('.tooltip-box .icon-service-hfr').count > 0
66
- end
67
-
68
- def original_name
69
- @original_name ||= @nokogiri_html.css('.span5 h1 a,.span7 h1 a, .span7 h1').children[0].to_s
70
- end
71
-
72
- def performance_date_array(node)
73
- if has_bookable_link_node?(node)
74
- match = performance_link_text(node).match(/date\=(\d{4})(\d{2})(\d{2})/)
75
- [match[1], match[2], match[3]]
76
- end
77
- end
78
-
79
- def performance_link(node)
80
- node.css('a.performance').first
40
+ def doc
41
+ @doc ||= Nokogiri::HTML(@film_html)
81
42
  end
82
43
 
83
- def performance_link_string(node)
84
- performance_link(node).to_s
44
+ def film_hash
45
+ @film_hash ||= { cinema_id: cinema_id, film_name: film_name }
85
46
  end
86
47
 
87
- def performance_link_text(node)
88
- has_bookable_link_node?(node) ? performance_link_string(node) : nil
48
+ def name_doc
49
+ @name_doc ||= doc.css(FILM_NAME_CSS)
89
50
  end
90
51
 
91
- def performance_time_array(node)
92
- if has_bookable_link_node?(node)
93
- match = performance_link_text(node).match(/time\=(\d{2})\:(\d{2})/)
94
- [match[1], match[2]]
95
- end
52
+ def performances_doc
53
+ @performances_doc ||= doc.css(PERFORMANCES_CSS)
96
54
  end
97
55
 
98
- def performance_variant(node)
99
- dimension(node) + "#{ ' D-BOX' if dbox?(node) }#{ ' IMAX' if imax?(node) }#{ ' HFR' if hfr?(node) }"
56
+ def screening_parser_hash(node)
57
+ ScreeningParser.new(node).to_hash
100
58
  end
101
59
  end
102
60
  end
@@ -1,14 +1,13 @@
1
1
  module CineworldUk
2
-
3
2
  # Internal utility classes: Do not use
4
3
  # @api private
5
4
  module Internal
6
-
7
5
  # Parses a string to derive a standardized movie title
8
6
  class NameParser
9
-
7
+ # @return [String] the original name
10
8
  attr_reader :original_name
11
9
 
10
+ # @param [String] name original film name
12
11
  def initialize(name)
13
12
  @original_name = name
14
13
  @name = name
@@ -17,15 +16,15 @@ module CineworldUk
17
16
  # Process the name and return the final string
18
17
  # @return [String]
19
18
  def standardize
20
- strip_and_squeeze.
21
- ampersands_into_text.
22
- into_ampersand_if_second_to_last.
23
- remove_indian_languages.
24
- remove_screening_details.
25
- replace_non_film_prefix.
26
- remove_newlines.
27
- remove_dates.
28
- title_case
19
+ strip_and_squeeze
20
+ .ampersands_into_text
21
+ .into_ampersand_if_second_to_last
22
+ .remove_indian_languages
23
+ .remove_screening_details
24
+ .replace_non_film_prefix
25
+ .remove_newlines
26
+ .remove_dates
27
+ .title_case
29
28
  to_s
30
29
  end
31
30
 
@@ -48,9 +47,9 @@ module CineworldUk
48
47
  end
49
48
 
50
49
  def remove_indian_languages
51
- languages = ['Malayalam', 'Tamil']
50
+ languages = %w(Malayalam Tamil)
52
51
 
53
- _remove(/\((#{languages*'|'})\)/i)
52
+ _remove(/\((#{languages * '|'})\)/i)
54
53
  self
55
54
  end
56
55
 
@@ -61,7 +60,7 @@ module CineworldUk
61
60
  end
62
61
 
63
62
  def remove_dates
64
- _remove(/\-? \d{1,2}\/\d{1,2}\/\d{2,4}/)
63
+ _remove(%r(-? \d{1,2}/\d{1,2}/\d{2,4}))
65
64
  self
66
65
  end
67
66
 
@@ -73,15 +72,18 @@ module CineworldUk
73
72
  def replace_non_film_prefix
74
73
  _replace 'Bolshoi Ballet Live -', 'Bolshoi:'
75
74
 
76
- @name = 'National Theatre: ' + @name.gsub(/\- NT .+ encore/, '') if @name.match /\- NT .+ encore/
75
+ if @name.match(/\- NT .+ encore/)
76
+ @name = 'National Theatre: ' + @name.gsub(/\- NT .+ encore/, '')
77
+ end
78
+
77
79
  _replace 'NT Live:', 'National Theatre:'
78
80
 
79
81
  _replace 'MET Opera -', 'Met Opera:'
80
82
  _replace 'Royal Ballet Live:', 'Royal Ballet:'
81
83
 
82
84
  # fill out Royal Opera House
83
- if pure_name_match = @name.match(/Royal Opera Live\: (.+) \-.+/)
84
- @name = 'Royal Opera House: ' + pure_name_match[1]
85
+ @name.match(/Royal Opera Live\: (.+) \-.+/) do |match|
86
+ @name = 'Royal Opera House: ' + match[1]
85
87
  end
86
88
  _replace 'Royal Opera Live:', 'Royal Opera House:'
87
89