cineworld_uk 1.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 (47) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +9 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +59 -0
  8. data/Rakefile +15 -0
  9. data/cineworld_uk.gemspec +29 -0
  10. data/lib/cineworld_uk.rb +15 -0
  11. data/lib/cineworld_uk/cinema.rb +218 -0
  12. data/lib/cineworld_uk/film.rb +47 -0
  13. data/lib/cineworld_uk/internal/film_with_screenings_parser.rb +128 -0
  14. data/lib/cineworld_uk/screening.rb +33 -0
  15. data/lib/cineworld_uk/version.rb +6 -0
  16. data/test/fixtures/cinemas.html +420 -0
  17. data/test/fixtures/cinemas/brighton.html +8 -0
  18. data/test/fixtures/cinemas/bristol.html +1206 -0
  19. data/test/fixtures/cinemas/bury-st-edmunds.html +1211 -0
  20. data/test/fixtures/cinemas/chelsea.html +1030 -0
  21. data/test/fixtures/cinemas/the-o2-grenwich.html +1191 -0
  22. data/test/fixtures/whatson/brighton.html +7906 -0
  23. data/test/fixtures/whatson/brighton/autism-friendly-cloudy-2.html +79 -0
  24. data/test/fixtures/whatson/brighton/geethanjali-malayalam.html +71 -0
  25. data/test/fixtures/whatson/brighton/gravity.html +2129 -0
  26. data/test/fixtures/whatson/brighton/take-2-thursday-about-time.html +89 -0
  27. data/test/fixtures/whatson/glasgow-imax-at-gsc-cinema.html +3160 -0
  28. data/test/fixtures/whatson/glasgow-imax-at-gsc/the-hunger-games-catching-fire.html +498 -0
  29. data/test/fixtures/whatson/the-o2-greenwich.html +6854 -0
  30. data/test/fixtures/whatson/the-o2-greenwich/gravity.html +784 -0
  31. data/test/fixtures/whatson/wandsworth.html +13729 -0
  32. data/test/fixtures/whatson/wandsworth/arrambam-tamil.html +126 -0
  33. data/test/fixtures/whatson/wandsworth/bolshoi-ballet-live-lost-illusions.html +80 -0
  34. data/test/fixtures/whatson/wandsworth/frankenstein-nt-50th.html +82 -0
  35. data/test/fixtures/whatson/wandsworth/met-opera-falstaff.html +74 -0
  36. data/test/fixtures/whatson/wandsworth/nt-live-war-horse.html +80 -0
  37. data/test/fixtures/whatson/wandsworth/royal-ballet-live-the-sleeping-beauty.html +79 -0
  38. data/test/fixtures/whatson/wandsworth/royal-opera-live-parsifal-weird-date.html +79 -0
  39. data/test/fixtures/whatson/wandsworth/rsc-live-richard-ii-encore.html +80 -0
  40. data/test/fixtures/whatson/wandsworth/west-end-theatre-series-private-lives.html +80 -0
  41. data/test/lib/cineworld_uk/cinema_test.rb +466 -0
  42. data/test/lib/cineworld_uk/film_test.rb +95 -0
  43. data/test/lib/cineworld_uk/internal/film_with_screenings_parser_test.rb +200 -0
  44. data/test/lib/cineworld_uk/screening_test.rb +31 -0
  45. data/test/lib/cineworld_uk/version_test.rb +9 -0
  46. data/test/test_helper.rb +6 -0
  47. metadata +219 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Yjc5NWQ4NDdkYzUwN2NmMzRkMzBhZGZhNjM4NWRiNDQ1ZmQ0N2JmZQ==
5
+ data.tar.gz: !binary |-
6
+ ZjkxNGU0ODcwNTQyYTcxOWQxZjQ1OGE4MGUxYTc2YTQ2NzNjYzc1NQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MDQyNDYwMTcxYWNiZGU2ZjEzYzZkMzU1YjJkYjQzZDEzNmYyZmIxNjE0ZTFj
10
+ MGRhMzRmZjVkNDY4ZTVlODczMjQ3MWE0NjczZGZlZTgzOWFjOGE4M2FiZjEz
11
+ Y2YzOWNlMzJhMDY5NmM4YzZlMzlkYmZjNmJjNTUzMWI5MGY5Y2U=
12
+ data.tar.gz: !binary |-
13
+ YTU3ZjQ1YjM2N2RkZTI3YTRkYzlhY2UxMDYwOWE1Njg3MjBkNWEyYjU0ZjRj
14
+ ZGY0MWMxZDViOTUyY2NkN2NiYTBhNTVlYWM5MjE1YjcxYjkyOTlhMTQ2OWM3
15
+ NzljMzkyZDVjMDUyZmQ5MmUyZDNiN2MzODc3NDI5ODFhN2YwY2M=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ ## 1.0.0, _6th Dec 2013_
2
+
3
+ First ready-for-public release
4
+
5
+ - Added changelog
6
+ - added booking url to screenings
7
+ - screenings created with UTC Time objects not strings
8
+ - added cinema addresses
9
+ - Get films and screenings out of a cinema
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cineworld_uk.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andy Croll
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # CineworldUk
2
+
3
+ A simple gem to parse the [Cineworld UK website](http://cineworld.co.uk) and spit out useful formatted info.
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/cineword_uk.png)](http://badge.fury.io/rb/cineworld_uk)
6
+ [![Code Climate](https://codeclimate.com/github/andycroll/cineworld_uk.png)](https://codeclimate.com/github/andycroll/cineworld_uk)
7
+ [![Build Status](https://travis-ci.org/andycroll/cineworld_uk.png?branch=master)](https://travis-ci.org/andycroll/cineworld_uk)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'cineworld_uk'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install cineworld_uk
22
+
23
+ ## Usage
24
+
25
+ ### Cinema
26
+
27
+ ``` ruby
28
+ CineworldUK::Cinema.all
29
+ #=> [<CineworldUK::Cinema brand="Cineworld" name="Duke's At Komedia" slug="dukes-at-komedia" chain_id="Dukes_At_Komedia" url="...">, #=> <CineworldUK::Cinema brand="Cineworld" name="Duke o York's" slug="duke-of-yorks" chain_id="Brighton" url="...">, ...]
30
+
31
+ CineworldUK::Cinema.find('3')
32
+ #=> <CineworldUK::Cinema brand="Cineworld" name="Brighton" slug="duke-of-yorks" address="..." chain_id="Brighton" url="...">
33
+
34
+ cinema.brand
35
+ #=> 'Cineworld'
36
+
37
+ cinema.id
38
+ #=> '3'
39
+
40
+ cinema.films
41
+ #=> [<CineworldUK::Film name="Iron Man 3">, <CineworldUK::Film name="Star Trek: Into Darkness">]
42
+
43
+ cinema.screenings
44
+ #=> [<CineworldUK::Screening film="About Time" when="2013-09-09 11:00 UTC" varient="3d">, <CineworldUK::Screening film="Iron Man 3" when="2013-09-09 13:50 UTC" varient="kids">, <CineworldUK::Screening ..>, <CineworldUK::Screening ...>]
45
+
46
+ cinema.screenings_of 'Iron Man 3'
47
+ #=> [<CineworldUK::Screening film="Iron Man 3" when="2013-09-09 11:00 UTC" varient="3d">, <CineworldUK::Screening film="Iron Man 3" when="2013-09-09 13:50 UTC" varient="kids">]
48
+
49
+ cinema.screenings_of <CineworldUK::Film name="Iron Man 3">
50
+ #=> [<CineworldUK::Screening film="Iron Man 3" when="2013-09-09 11:00 UTC" varient="3d">, <CineworldUK::Screening film="Iron Man 3" when="2013-09-09 13:50 UTC" varient="kids">]
51
+ ```
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
58
+ 4. Push to the branch (`git push origin my-new-feature`)
59
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'lib/cineworld_uk'
8
+ t.test_files = FileList[
9
+ 'test/lib/cineworld_uk/*_test.rb',
10
+ 'test/lib/cineworld_uk/internal/*_test.rb'
11
+ ]
12
+ t.verbose = true
13
+ end
14
+
15
+ task :default => :test
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cineworld_uk/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cineworld_uk"
8
+ spec.version = CineworldUk::VERSION
9
+ spec.authors = ["Andy Croll"]
10
+ spec.email = ["andy@goodscary.com"]
11
+ spec.description = %q{Cineworld cinema data}
12
+ spec.summary = %q{Parses cinema and showing data from the cineworld.co.uk website}
13
+ spec.homepage = "https://github.com/andycroll/cineworld_uk"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency 'webmock'
24
+
25
+ spec.add_runtime_dependency 'httparty'
26
+ spec.add_runtime_dependency 'nokogiri'
27
+ spec.add_runtime_dependency 'tzinfo'
28
+ spec.add_runtime_dependency 'tzinfo-data'
29
+ end
@@ -0,0 +1,15 @@
1
+ require 'httparty'
2
+ require 'nokogiri'
3
+ require 'tzinfo'
4
+ require 'tzinfo/data'
5
+
6
+ require_relative './cineworld_uk/version'
7
+
8
+ require_relative './cineworld_uk/internal/film_with_screenings_parser'
9
+
10
+ require_relative './cineworld_uk/cinema'
11
+ require_relative './cineworld_uk/film'
12
+ require_relative './cineworld_uk/screening'
13
+
14
+ module CineworldUk
15
+ end
@@ -0,0 +1,218 @@
1
+ module CineworldUk
2
+
3
+ # The object representing a cinema on the Cineworld UK website
4
+ class Cinema
5
+
6
+ # @return [String] the brand of the cinema
7
+ attr_reader :brand
8
+ # @return [Integer] the numeric id of the cinema on the Odeon website
9
+ attr_reader :id
10
+ # @return [String] the name of the cinema
11
+ attr_reader :name
12
+ # @return [String] the slug of the cinema
13
+ attr_reader :slug
14
+ # @return [String] the url of the cinema on the Cineworld website
15
+ attr_reader :url
16
+
17
+ # @param [Integer, String] id cinema id
18
+ # @param [String] name cinema name
19
+ # @return [CineworldUk::Cinema]
20
+ def initialize(id, name)
21
+ @brand = 'Cineworld'
22
+ @id = id.to_i
23
+ @name = name.gsub('London - ','')
24
+ @slug = @name.downcase.gsub(/[^0-9a-z ]/,'').gsub(/\s+/, '-')
25
+ @url = "http://www.cineworld.co.uk/cinemas/#{@id}/information"
26
+ end
27
+
28
+ # Return basic cinema information for all cinemas
29
+ # @return [Array<CineworldUk::Cinema>]
30
+ # @example
31
+ # 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="...">, ...]
33
+ def self.all
34
+ parsed_cinemas.css('#cinemaId option[value]').map do |option|
35
+ new option['value'], option.text
36
+ end[1..-1]
37
+ end
38
+
39
+ # 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
41
+ # @return [CineworldUk::Cinema, nil]
42
+ # @example
43
+ # CineworldUk::Cinema.find('3')
44
+ # #=> <CineworldUk::Cinema brand="Cineworld" name="Brighton" slug="brighton" id=3 url="...">
45
+ def self.find(id)
46
+ id = id.to_i
47
+ return nil unless id > 0
48
+
49
+ all.select { |cinema| cinema.id == id }[0]
50
+ end
51
+
52
+ # Address of the cinema
53
+ # @return [Hash] of different address parts
54
+ # @example
55
+ # cinema = CineworldUk::Cinema.find('Dukes_At_Komedia')
56
+ # cinema.adr
57
+ # #=> { street_address: '44-47 Gardner Street', extended_address: 'North Laine', locality: 'Brighton', postal_code: 'BN1 1UN', country_name: 'United Kingdom' }
58
+ # @note Uses the standard method naming as at http://microformats.org/wiki/adr
59
+ def adr
60
+ {
61
+ street_address: street_address,
62
+ extended_address: extended_address,
63
+ locality: locality,
64
+ region: region,
65
+ postal_code: postal_code,
66
+ country: 'United Kingdom'
67
+ }
68
+ end
69
+ alias_method :address, :adr
70
+
71
+ # The second address line of the cinema
72
+ # @return [String, nil]
73
+ # @example
74
+ # cinema = CineworldUk::Cinema.find(10)
75
+ # cinema.extended_address
76
+ # #=> 'Chelsea'
77
+ #
78
+ # cinema = CineworldUk::Cinema.find(3)
79
+ # cinema.extended_address
80
+ # #=> nil
81
+ # @note Uses the standard method naming as at http://microformats.org/wiki/adr
82
+ def extended_address
83
+ remaining_address * ', ' unless remaining_address.empty?
84
+ end
85
+
86
+ # Films with showings scheduled at this cinema
87
+ # @return [Array<OdeonUk::Film>]
88
+ # @example
89
+ # cinema = OdeonUk::Cinema.find('71')
90
+ # cinema.films
91
+ # #=> [<OdeonUk::Film name="Iron Man 3">, <OdeonUk::Film name="Star Trek Into Darkness">]
92
+ 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
97
+ end
98
+
99
+ # The locality (town) of the cinema
100
+ # @return [String]
101
+ # @example
102
+ # cinema = CineworldUk::Cinema.find(3)
103
+ # cinema.locality
104
+ # #=> 'Brighton'
105
+ # @note Uses the standard method naming as at http://microformats.org/wiki/adr
106
+ def locality
107
+ adr_has_region? && !adr_in_london? ? final_address_array[-2] : final_address_array[-1]
108
+ end
109
+
110
+ # Post code of the cinema
111
+ # @return [String]
112
+ # @example
113
+ # cinema = CineworldUk::Cinema.find(3)
114
+ # cinema.postal_code
115
+ # #=> 'BN2 5UF'
116
+ # @note Uses the standard method naming as at http://microformats.org/wiki/adr
117
+ def postal_code
118
+ final_line_array[-2..-1]*' '
119
+ end
120
+
121
+ # The region (county) of the cinema if provided
122
+ # @return [String, nil]
123
+ # @example
124
+ # cinema = CineworldUk::Cinema.find(3)
125
+ # cinema.region
126
+ # #=> 'East Sussex'
127
+ # @note Uses the standard method naming as at http://microformats.org/wiki/adr
128
+ def region
129
+ final_line_non_postal_code if adr_has_region? && !adr_in_london?
130
+ end
131
+
132
+ # All planned screenings
133
+ # @return [Array<CineworldUk::Screening>]
134
+ # @example
135
+ # cinema = CineworldUk::Cinema.find(3)
136
+ # cinema.screenings
137
+ # # => [<CineworldUk::Screening film_name="Iron Man 3" cinema_name="Brighton" when="..." varient="...">, <CineworldUk::Screening ...>]
138
+ def screenings
139
+ film_nodes.map do |node|
140
+ parser = CineworldUk::Internal::FilmWithScreeningsParser.new node.to_s
141
+ parser.showings.map do |screening_type, times|
142
+ times.map do |array|
143
+ CineworldUk::Screening.new parser.film_name, self.name, array[0], array[1], screening_type
144
+ end
145
+ end
146
+ end.flatten
147
+ end
148
+
149
+ # The street adress of the cinema
150
+ # @return a String
151
+ # @example
152
+ # cinema = CineworldUk::Cinema.find(3)
153
+ # cinema.street_address
154
+ # #=> 'Brighton Marina'
155
+ # @note Uses the standard method naming as at http://microformats.org/wiki/adr
156
+ def street_address
157
+ address_parts[0]
158
+ end
159
+
160
+ private
161
+
162
+ def self.parsed_cinemas
163
+ @parsed_cinemas ||= Nokogiri::HTML(cinemas_response)
164
+ end
165
+
166
+ def self.cinemas_response
167
+ @cinemas_response ||= HTTParty.get('http://www.cineworld.co.uk/cinemas')
168
+ end
169
+
170
+ def address_parts
171
+ @address_parts ||= parsed_information.css('address.marker').to_s.split('<br>')[-2].split(',').map(&:strip)
172
+ end
173
+
174
+ def adr_in_london?
175
+ final_line_non_postal_code == 'London'
176
+ end
177
+
178
+ def adr_has_region?
179
+ final_line_non_postal_code != name
180
+ end
181
+
182
+ def film_nodes
183
+ @film_nodes ||= parsed_whatson.css('.section.light #filter-reload > .span9').to_s.split('<hr>')
184
+ end
185
+
186
+ def final_address_array
187
+ address_parts[0..-2] << final_line_non_postal_code
188
+ end
189
+
190
+ def final_line_array
191
+ address_parts[-1].split(' ')
192
+ end
193
+
194
+ def final_line_non_postal_code
195
+ final_line_array[0..-3]*' '
196
+ end
197
+
198
+ def information_response
199
+ @information_response ||= HTTParty.get("http://www.cineworld.co.uk/cinemas/#{@id}/information")
200
+ end
201
+
202
+ def parsed_information
203
+ @parsed_information ||= Nokogiri::HTML(information_response)
204
+ end
205
+
206
+ def parsed_whatson
207
+ @parsed_whatson ||= Nokogiri::HTML(whatson_response)
208
+ end
209
+
210
+ def remaining_address
211
+ final_address_array.delete_if { |e| e == street_address || e == locality || e == region }
212
+ end
213
+
214
+ def whatson_response
215
+ @whatson_response ||= HTTParty.get("http://www.cineworld.co.uk/whatson?cinema=#{@id}")
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,47 @@
1
+ module CineworldUk
2
+
3
+ # The object representing a film on the Cineworld UK website
4
+ class Film
5
+ include Comparable
6
+
7
+ # @return [String] the name of the film
8
+ attr_reader :name
9
+ # @return [String] the normalized slug derived from the film name
10
+ attr_reader :slug
11
+
12
+ # @param [String] name the film name
13
+ # @return [CineworldUk::Film]
14
+ def initialize(name)
15
+ @name = name
16
+ @slug = name.downcase.gsub(/[^0-9a-z ]/,'').gsub(/\s+/, '-')
17
+ end
18
+
19
+ # Allows sort on objects
20
+ # @param [CineworldUk::Film] other another film object
21
+ # @return [Integer] -1, 0 or 1
22
+ def <=> other
23
+ self.slug <=> other.slug
24
+ end
25
+
26
+ # Check an object is the same as another object.
27
+ # @param [CineworldUk::Film] other another film
28
+ # @return [Boolean] True if both objects are the same exact object, or if
29
+ # they are of the same type and share an equal slug
30
+ # @note Guided by http://woss.name/2011/01/20/equality-comparison-and-ordering-in-ruby/
31
+ def eql? other
32
+ self.class == other.class && self == other
33
+ end
34
+
35
+ # Generates hash of slug in order to allow two records of the same type and
36
+ # id to work with something like:
37
+ #
38
+ # [ Film.new('ABC'), Film.new('DEF') ] & [ Film.new('DEF'), Film.new('GHI') ]
39
+ # #=> [ Film.new('DEF') ]
40
+ #
41
+ # @return [Integer] hash of slug
42
+ # @note Guided by http://woss.name/2011/01/20/equality-comparison-and-ordering-in-ruby/
43
+ def hash
44
+ self.slug.hash
45
+ end
46
+ end
47
+ end