cineworld_uk 4.3.2-aarch64-linux-gnu → 4.5.0-aarch64-linux-gnu
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/Gemfile +1 -0
- data/README.md +19 -2
- data/cineworld_uk.gemspec +1 -1
- data/lib/cineworld_uk/cinema.rb +34 -0
- data/lib/cineworld_uk/internal/api_response.rb +4 -0
- data/lib/cineworld_uk/internal/parser/api/film.rb +7 -3
- data/lib/cineworld_uk/internal/title_sanitizer.rb +2 -1
- data/lib/cineworld_uk/performance.rb +1 -0
- data/lib/cineworld_uk/version.rb +2 -2
- data/lib/cineworld_uk.rb +5 -8
- data/test/fixtures/api/sites.json +3 -0
- data/test/lib/cineworld_uk/cinema_test.rb +19 -0
- data/test/lib/cineworld_uk/internal/api_response_test.rb +9 -0
- data/test/lib/cineworld_uk/internal/guest_token_test.rb +10 -0
- data/test/lib/cineworld_uk/internal/title_sanitizer_test.rb +7 -3
- data/test/lib/cineworld_uk/performance_test.rb +10 -0
- data/test/live/integration_test.rb +10 -0
- data/test/support/api_shapes.rb +5 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f78fc774f425b7c4837b7172dad94f59336ea13679abb5d1db59dbb735293179
|
|
4
|
+
data.tar.gz: 94458a9722a15c2c6310edc80c9a89f1bfa892e07739a17467210c16eaa2f9a6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 41ebf0bba635709a424f45bc9d8d0bbfbe3023fed26433b5708e0d6a61f1f886a6dc05c496bfe6d8a016d1f345a3d55a6697125c3bcdbd854661e63bb20667b8
|
|
7
|
+
data.tar.gz: 542ed75ca5ab04cc47cfffceb22bf5e35b2739432f1e0be58d4e8570faa37c975e3eb5024003c9b538ce26c6dd1d837475822caf27f5340763f99f08e3fbdde5
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [4.5.0] - 2026-11-03
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Uses cinebase 5.9: performances take the raw `title:`, so audience labels become variants, and series prefixes such as `Met Opera:` become the performance's `event`.
|
|
9
|
+
- National Theatre Live screenings are named `National Theatre Live: `, not `National Theatre: `, before cinebase moves the series to `event`.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- `Met Opera - Cosi Fan Tutte (Mozart)` is now `Cosi Fan Tutte`: a Met Opera title loses a trailing bracketed composer.
|
|
13
|
+
|
|
14
|
+
## 4.4.0 - 2026-10-31
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- `Cinema#latitude` and `Cinema#longitude` as Floats in decimal degrees, from the Vista sites response. They are `nil` when a site has no location or sits at 0, 0.
|
|
18
|
+
- `CineworldUk.ensure_token!` fetches a guest token only when there is none or it expires within an hour, and `CineworldUk.token_expires_at` reads its expiry. Both come from cinebase's `Vista::TokenHolder`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- A token the API rejects is cleared from `CineworldUk.token`, so the next `ensure_token!` fetches a fresh one.
|
|
22
|
+
- Requires cinebase 5.6.
|
|
23
|
+
|
|
5
24
|
## 4.3.2 - 2026-10-22
|
|
6
25
|
|
|
7
26
|
### Changed
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -36,6 +36,16 @@ CineworldUk.acquire_token!
|
|
|
36
36
|
CineworldUk::Cinema.all
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
`acquire_token!` always fetches a new token. `ensure_token!` fetches one only
|
|
40
|
+
when there is no token, or the token expires within an hour, and otherwise
|
|
41
|
+
keeps the current one. Call it before each batch of requests:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
CineworldUk.ensure_token!
|
|
45
|
+
CineworldUk.token_expires_at
|
|
46
|
+
#=> 2026-10-31 03:00:00 UTC
|
|
47
|
+
```
|
|
48
|
+
|
|
39
49
|
This shells out to **`curl-impersonate`**, not ordinary system `curl`, using its
|
|
40
50
|
Chrome 150 TLS/HTTP profile. No Python, Chrome, JavaScript execution or browser
|
|
41
51
|
cookies are needed. Platform-specific gem packages include the pinned
|
|
@@ -89,8 +99,9 @@ The gem sends `Authorization: Bearer ...` and `Connect-Region-Code: GB` to
|
|
|
89
99
|
automatically.
|
|
90
100
|
|
|
91
101
|
Missing tokens and HTTP 401 responses raise `CineworldUk::AuthenticationError`.
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
A token the API rejects is cleared from `CineworldUk.token`, so call
|
|
103
|
+
`CineworldUk.ensure_token!`, or set `CineworldUk.token` with a fresh token,
|
|
104
|
+
before retrying. Tokens are never persisted by the gem. Other HTTP
|
|
94
105
|
failures raise an error rather than returning an empty schedule. Redirects are
|
|
95
106
|
not followed, so credentials are not forwarded to another host.
|
|
96
107
|
|
|
@@ -134,6 +145,12 @@ cinema.full_name
|
|
|
134
145
|
cinema.id
|
|
135
146
|
#=> 14
|
|
136
147
|
|
|
148
|
+
cinema.latitude
|
|
149
|
+
#=> 50.8125991821289
|
|
150
|
+
|
|
151
|
+
cinema.longitude
|
|
152
|
+
#=> -0.104699999094009
|
|
153
|
+
|
|
137
154
|
cinema.postal_code
|
|
138
155
|
#=> 'BN2 5UF'
|
|
139
156
|
```
|
data/cineworld_uk.gemspec
CHANGED
|
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
spec.add_development_dependency 'simplecov', '< 1'
|
|
26
26
|
spec.add_development_dependency 'webmock'
|
|
27
27
|
|
|
28
|
-
spec.add_runtime_dependency 'cinebase', '~> 5.
|
|
28
|
+
spec.add_runtime_dependency 'cinebase', '~> 5.9'
|
|
29
29
|
spec.add_runtime_dependency 'nokogiri', '>= 1.11'
|
|
30
30
|
end
|
data/lib/cineworld_uk/cinema.rb
CHANGED
|
@@ -101,6 +101,26 @@ module CineworldUk
|
|
|
101
101
|
# cinema.locality
|
|
102
102
|
# #=> 'Brighton'
|
|
103
103
|
|
|
104
|
+
# Latitude of the cinema
|
|
105
|
+
# @return [Float, nil] decimal degrees, or nil when unknown
|
|
106
|
+
# @example
|
|
107
|
+
# cinema = CineworldUk::Cinema.new(14)
|
|
108
|
+
# cinema.latitude
|
|
109
|
+
# #=> 50.8125991821289
|
|
110
|
+
def latitude
|
|
111
|
+
coordinates&.first
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Longitude of the cinema
|
|
115
|
+
# @return [Float, nil] decimal degrees, or nil when unknown
|
|
116
|
+
# @example
|
|
117
|
+
# cinema = CineworldUk::Cinema.new(14)
|
|
118
|
+
# cinema.longitude
|
|
119
|
+
# #=> -0.104699999094009
|
|
120
|
+
def longitude
|
|
121
|
+
coordinates&.last
|
|
122
|
+
end
|
|
123
|
+
|
|
104
124
|
# The name of the cinema
|
|
105
125
|
# @return [String]
|
|
106
126
|
# @example
|
|
@@ -164,5 +184,19 @@ module CineworldUk
|
|
|
164
184
|
JSON.parse(api.cinema_list)['body']['cinemas']
|
|
165
185
|
end
|
|
166
186
|
private_class_method :cinema_list_json
|
|
187
|
+
|
|
188
|
+
private
|
|
189
|
+
|
|
190
|
+
def cinema_hash
|
|
191
|
+
formatted_id = @id.to_s.rjust(3, '0')
|
|
192
|
+
self.class.send(:cinema_list_json).find { |cinema| cinema['id'] == formatted_id } || {}
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# 0, 0 marks a site whose position was never set
|
|
196
|
+
def coordinates
|
|
197
|
+
location = cinema_hash['location'] || {}
|
|
198
|
+
pair = [location['latitude'], location['longitude']]
|
|
199
|
+
pair.map(&:to_f) if pair.all?(Numeric) && pair.any?(&:nonzero?)
|
|
200
|
+
end
|
|
167
201
|
end
|
|
168
202
|
end
|
|
@@ -25,6 +25,7 @@ module CineworldUk
|
|
|
25
25
|
{
|
|
26
26
|
"id" => site.fetch("id"),
|
|
27
27
|
"displayName" => site.fetch("name").fetch("text"),
|
|
28
|
+
"location" => site["location"],
|
|
28
29
|
"addressInfo" => {
|
|
29
30
|
"address1" => address.dig("line1", "text"),
|
|
30
31
|
"city" => address.dig("line2", "text"),
|
|
@@ -87,6 +88,9 @@ module CineworldUk
|
|
|
87
88
|
|
|
88
89
|
def fetch(path, query = {})
|
|
89
90
|
client.get(path, query)
|
|
91
|
+
rescue Cinebase::Vista::AuthenticationError
|
|
92
|
+
CineworldUk.reject_token!(@client_token)
|
|
93
|
+
raise
|
|
90
94
|
end
|
|
91
95
|
|
|
92
96
|
# One client keeps one connection open, so reuse it until the token changes.
|
|
@@ -24,21 +24,25 @@ module CineworldUk
|
|
|
24
24
|
# @param [Integer] year edition when the title gives none
|
|
25
25
|
# @return [Cinebase::Festival, nil]
|
|
26
26
|
def festival(year)
|
|
27
|
-
Cinebase::Festival.from_title(
|
|
27
|
+
Cinebase::Festival.from_title(title, year: year)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
# @return [Integer, nil] the year at the end of the title
|
|
31
31
|
def film_year
|
|
32
|
-
Cinebase::TitleSanitizer.film_year(
|
|
32
|
+
Cinebase::TitleSanitizer.film_year(title)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
# Sanitized film name
|
|
36
36
|
# @return [String]
|
|
37
37
|
def name
|
|
38
|
-
title = @data['name'] || ''
|
|
39
38
|
TitleSanitizer.new(title).sanitized
|
|
40
39
|
end
|
|
41
40
|
|
|
41
|
+
# @return [String] the title as listed
|
|
42
|
+
def title
|
|
43
|
+
@data['name'] || ''
|
|
44
|
+
end
|
|
45
|
+
|
|
42
46
|
# List of strings representing different kinds of performance, such
|
|
43
47
|
# as autism, kids, imax, members or q&a
|
|
44
48
|
# @return [Array<String>] or an empty array
|
|
@@ -34,7 +34,8 @@ module CineworldUk
|
|
|
34
34
|
'SciScreen: ', # SciScreen
|
|
35
35
|
/\s(-\s)*(With)*\sLive Q And A/i, # Live Q&A
|
|
36
36
|
/(\s+\-\s+)?MOVIES FOR JUNIORS/i, # movies for juniors
|
|
37
|
-
%r{\s20\d{2}[\/-]20\d{2} Season\b}
|
|
37
|
+
%r{\s20\d{2}[\/-]20\d{2} Season\b},
|
|
38
|
+
/\A(?i:Met Opera)\b.*\K\s*\(\p{Lu}[\p{L}-]+\)\z/ # Met Opera composer
|
|
38
39
|
] + COMMON_REMOVE
|
|
39
40
|
end
|
|
40
41
|
|
data/lib/cineworld_uk/version.rb
CHANGED
data/lib/cineworld_uk.rb
CHANGED
|
@@ -20,13 +20,10 @@ require_relative './cineworld_uk/performance'
|
|
|
20
20
|
module CineworldUk
|
|
21
21
|
AuthenticationError = Cinebase::Vista::AuthenticationError
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def acquire_token!(curl: nil)
|
|
29
|
-
self.token = Internal::GuestToken.new(curl: curl).fetch
|
|
30
|
-
end
|
|
23
|
+
extend Cinebase::Vista::TokenHolder
|
|
24
|
+
|
|
25
|
+
# @api private
|
|
26
|
+
def self.guest_token_class
|
|
27
|
+
Internal::GuestToken
|
|
31
28
|
end
|
|
32
29
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
{
|
|
4
4
|
"id": "014",
|
|
5
5
|
"name": { "text": "Brighton" },
|
|
6
|
+
"location": { "latitude": 50.8125991821289, "longitude": -0.104699999094009 },
|
|
6
7
|
"contactDetails": {
|
|
7
8
|
"addressV2": {
|
|
8
9
|
"line1": { "text": "1 Example Marina" },
|
|
@@ -15,6 +16,7 @@
|
|
|
15
16
|
{
|
|
16
17
|
"id": "088",
|
|
17
18
|
"name": { "text": "Glasgow Silverburn" },
|
|
19
|
+
"location": { "latitude": 0, "longitude": 0 },
|
|
18
20
|
"contactDetails": {
|
|
19
21
|
"addressV2": {
|
|
20
22
|
"line1": { "text": "2 Example Centre" },
|
|
@@ -27,6 +29,7 @@
|
|
|
27
29
|
{
|
|
28
30
|
"id": "103",
|
|
29
31
|
"name": { "text": "Leicester Square" },
|
|
32
|
+
"location": null,
|
|
30
33
|
"contactDetails": {
|
|
31
34
|
"addressV2": {
|
|
32
35
|
"line1": { "text": "3 Example Square" },
|
|
@@ -61,6 +61,25 @@ class CineworldUk::CinemaTest < Minitest::Test
|
|
|
61
61
|
assert_equal 'Example: Riverside', CineworldUk::Cinema.new(999).name
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
def test_latitude_and_longitude
|
|
65
|
+
cinema = CineworldUk::Cinema.new(14)
|
|
66
|
+
|
|
67
|
+
assert_in_delta 50.8126, cinema.latitude, 0.0001
|
|
68
|
+
assert_in_delta(-0.1047, cinema.longitude, 0.0001)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_latitude_and_longitude_are_nil_without_a_location
|
|
72
|
+
[103, 999].each do |id|
|
|
73
|
+
assert_nil CineworldUk::Cinema.new(id).latitude
|
|
74
|
+
assert_nil CineworldUk::Cinema.new(id).longitude
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_latitude_and_longitude_are_nil_at_zero_zero
|
|
79
|
+
assert_nil CineworldUk::Cinema.new(88).latitude
|
|
80
|
+
assert_nil CineworldUk::Cinema.new(88).longitude
|
|
81
|
+
end
|
|
82
|
+
|
|
64
83
|
def test_locality
|
|
65
84
|
assert_equal 'Brighton', CineworldUk::Cinema.new(14).locality
|
|
66
85
|
assert_equal 'London', CineworldUk::Cinema.new(103).locality
|
|
@@ -68,6 +68,15 @@ class CineworldUk::Internal::ApiResponseTest < Minitest::Test
|
|
|
68
68
|
refute_includes error.message, "expired-secret"
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
def test_rejected_token_is_cleared
|
|
72
|
+
CineworldUk.token = "rejected-token"
|
|
73
|
+
stub_request(:get, "#{BASE_URL}sites").to_return(status: 401)
|
|
74
|
+
|
|
75
|
+
assert_raises(CineworldUk::AuthenticationError) { CineworldUk::Cinema.all }
|
|
76
|
+
|
|
77
|
+
assert_nil CineworldUk.token
|
|
78
|
+
end
|
|
79
|
+
|
|
71
80
|
def test_uses_replacement_token
|
|
72
81
|
CineworldUk.token = "replacement"
|
|
73
82
|
stub_request(:get, "#{BASE_URL}sites")
|
|
@@ -27,6 +27,16 @@ class CineworldUk::Internal::GuestTokenTest < Minitest::Test
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def test_ensure_token_fetches_only_without_a_current_token
|
|
31
|
+
CineworldUk.token = nil
|
|
32
|
+
html, token = token_page(Time.now.to_i + 7200)
|
|
33
|
+
serve_token_page(html)
|
|
34
|
+
|
|
35
|
+
assert_equal token, CineworldUk.ensure_token!(curl: @curl)
|
|
36
|
+
serve_token_page("", exit_code: 7)
|
|
37
|
+
assert_equal token, CineworldUk.ensure_token!(curl: @curl)
|
|
38
|
+
end
|
|
39
|
+
|
|
30
40
|
def test_rejects_expired_tokens_including_boundary_and_keeps_current_token
|
|
31
41
|
now = Time.at(1_800_000_000)
|
|
32
42
|
Time.stub(:now, now) do
|
|
@@ -42,17 +42,21 @@ class CineworldUk::Internal::TitleSanitizerTest < Minitest::Test
|
|
|
42
42
|
assert_sanitized 'Met Opera: Le Nozze Di Figaro', 'MET Opera - Le Nozze Di Figaro'
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def test_met_opera_drops_composer
|
|
46
|
+
assert_sanitized 'Met Opera: Cosi Fan Tutte', 'Met Opera - Cosi Fan Tutte (Mozart)'
|
|
47
|
+
end
|
|
48
|
+
|
|
45
49
|
def test_nt_live_encore
|
|
46
|
-
assert_sanitized 'National Theatre: Frankenstein (starring Benedict Cumberbatch)',
|
|
50
|
+
assert_sanitized 'National Theatre Live: Frankenstein (starring Benedict Cumberbatch)',
|
|
47
51
|
'NT Live Encore: Frankenstein (starring Benedict Cumberbatch)'
|
|
48
52
|
end
|
|
49
53
|
|
|
50
54
|
def test_nt_live
|
|
51
|
-
assert_sanitized 'National Theatre: Treasure Island', 'NT Live: Treasure Island'
|
|
55
|
+
assert_sanitized 'National Theatre Live: Treasure Island', 'NT Live: Treasure Island'
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
def test_nt_live_with_encore_suffix
|
|
55
|
-
assert_sanitized 'National Theatre: A Streetcar Named Desire (Young Vic)',
|
|
59
|
+
assert_sanitized 'National Theatre Live: A Streetcar Named Desire (Young Vic)',
|
|
56
60
|
'NT Live: A Streetcar Named Desire (Young Vic) - Encore'
|
|
57
61
|
end
|
|
58
62
|
|
|
@@ -70,6 +70,16 @@ class CineworldUk::PerformanceTest < Minitest::Test
|
|
|
70
70
|
assert_equal Cinebase::Festival.new(name: 'Cine-Excess', year: 2026), performance.festival
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
def test_at_names_event_from_title
|
|
74
|
+
stub_showtimes(DATE, showtimes_json.sub('The Example Film', 'Met Opera - Cosi Fan Tutte (Mozart)'))
|
|
75
|
+
performance = CineworldUk::Performance.at(14, from: DATE, to: DATE).first
|
|
76
|
+
|
|
77
|
+
assert_equal 'Met Opera - Cosi Fan Tutte (Mozart)', performance.title
|
|
78
|
+
assert_equal 'Cosi Fan Tutte', performance.film_name
|
|
79
|
+
assert_equal Cinebase::Event.new(name: 'Met Opera'), performance.event
|
|
80
|
+
assert_equal %w(arts audio_described), performance.variant
|
|
81
|
+
end
|
|
82
|
+
|
|
73
83
|
def test_at_parses_format_and_film_year
|
|
74
84
|
performance = performances_on_date[5]
|
|
75
85
|
|
|
@@ -8,6 +8,16 @@ class LiveCinemaTest < Minitest::Test
|
|
|
8
8
|
assert_operator cinemas.size, :>, 18
|
|
9
9
|
assert_equal 'Brighton', cinemas.detect { |cinema| cinema.id == 14 }.name
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
def test_cinemas_have_uk_coordinates
|
|
13
|
+
located = CineworldUk::Cinema.all.select(&:latitude)
|
|
14
|
+
|
|
15
|
+
refute_empty located
|
|
16
|
+
located.each do |cinema|
|
|
17
|
+
assert_includes 49.0..61.0, cinema.latitude, "#{cinema.id} #{cinema.name}"
|
|
18
|
+
assert_includes(-9.0..2.0, cinema.longitude, "#{cinema.id} #{cinema.name}")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
11
21
|
end
|
|
12
22
|
|
|
13
23
|
class LivePerformanceTest < Minitest::Test
|
data/test/support/api_shapes.rb
CHANGED
|
@@ -16,6 +16,11 @@ module ApiShapes
|
|
|
16
16
|
line = address.fetch(key)
|
|
17
17
|
assert_kind_of String, line.fetch('text'), "site #{site['id']} #{key}" unless line.nil?
|
|
18
18
|
end
|
|
19
|
+
location = site['location'] || {}
|
|
20
|
+
%w(latitude longitude).each do |key|
|
|
21
|
+
value = location[key]
|
|
22
|
+
assert_kind_of Numeric, value, "site #{site['id']} #{key}" unless value.nil?
|
|
23
|
+
end
|
|
19
24
|
end
|
|
20
25
|
end
|
|
21
26
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cineworld_uk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.5.0
|
|
5
5
|
platform: aarch64-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Croll
|
|
@@ -113,14 +113,14 @@ dependencies:
|
|
|
113
113
|
requirements:
|
|
114
114
|
- - "~>"
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: '5.
|
|
116
|
+
version: '5.9'
|
|
117
117
|
type: :runtime
|
|
118
118
|
prerelease: false
|
|
119
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
120
|
requirements:
|
|
121
121
|
- - "~>"
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: '5.
|
|
123
|
+
version: '5.9'
|
|
124
124
|
- !ruby/object:Gem::Dependency
|
|
125
125
|
name: nokogiri
|
|
126
126
|
requirement: !ruby/object:Gem::Requirement
|