eyes_images 4.0.0.alpha → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of eyes_images might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/lib/applitools/images/eyes.rb +23 -27
- data/lib/applitools/images/eyes_images_screenshot.rb +96 -0
- data/lib/applitools/images/target.rb +50 -134
- data/lib/applitools/version.rb +2 -3
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 71125b4f052c21e79a5b50b6e553c079c55ee792
|
4
|
+
data.tar.gz: 3fc0aa90e059f26fd13f82f8cd01f4399bc93665
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d89e69a8b1a86ecd33fc51e35dddc8a8cb70d95b7100ad821e4c804e954148ba461f0aa88feb9913e07c4520f27c47f9d69b300df5fabb7367050660ec8f20fd
|
7
|
+
data.tar.gz: f1925352ff32e967a17d8c8d0fd2be3b0e3db40c95bd6fe84c7e774c4a3c356ebf44cf95c51813735f79a037c4296a9cb642c88136dc45ea36d1d4e9bbff03a1
|
@@ -42,8 +42,7 @@ module Applitools::Images
|
|
42
42
|
def open(options = {})
|
43
43
|
Applitools::ArgumentGuard.hash options, 'open(options)', [:app_name, :test_name]
|
44
44
|
options[:viewport_size] = Applitools::RectangleSize.from_any_argument options[:viewport_size]
|
45
|
-
|
46
|
-
universal_open(options)
|
45
|
+
open_base options
|
47
46
|
end
|
48
47
|
|
49
48
|
# Opens eyes using passed options, yields the block and then closes eyes session.
|
@@ -94,9 +93,6 @@ module Applitools::Images
|
|
94
93
|
|
95
94
|
def check_it(name, target, match_window_data)
|
96
95
|
Applitools::ArgumentGuard.not_nil(name, 'name')
|
97
|
-
|
98
|
-
return universal_check(name, target)
|
99
|
-
|
100
96
|
region_provider = get_region_provider(target)
|
101
97
|
|
102
98
|
match_window_data.tag = name
|
@@ -168,8 +164,8 @@ module Applitools::Images
|
|
168
164
|
# eyes.check_image(image: my_image, tag: 'My Test', ignore_mismatch: true)
|
169
165
|
def check_image(options)
|
170
166
|
options = { tag: '', ignore_mismatch: false }.merge options
|
171
|
-
|
172
|
-
target = Applitools::Images::Target.any(
|
167
|
+
image = get_image_from_options(options)
|
168
|
+
target = Applitools::Images::Target.any(image).ignore_mismatch(options[:ignore_mismatch])
|
173
169
|
check(options[:tag], target)
|
174
170
|
end
|
175
171
|
|
@@ -189,10 +185,10 @@ module Applitools::Images
|
|
189
185
|
# @example Image is a +String+
|
190
186
|
# eyes.check_region(image_bytes: string_represents_image, tag: 'My Test', region: my_region)
|
191
187
|
def check_region(options)
|
192
|
-
options = { tag:
|
188
|
+
options = { tag: nil, ignore_mismatch: false }.merge options
|
193
189
|
Applitools::ArgumentGuard.not_nil options[:region], 'options[:region] can\'t be nil!'
|
194
|
-
|
195
|
-
target = Applitools::Images::Target.any(
|
190
|
+
image = get_image_from_options options
|
191
|
+
target = Applitools::Images::Target.any(image).ignore_mismatch(options[:ignore_mismatch])
|
196
192
|
target.region(options[:region])
|
197
193
|
logger.info "check_region(image, #{options[:region]}, #{options[:tag]}, #{options[:ignore_mismatch]})"
|
198
194
|
check(options[:tag], target)
|
@@ -236,22 +232,22 @@ module Applitools::Images
|
|
236
232
|
alias get_viewport_size vp_size
|
237
233
|
alias set_viewport_size vp_size=
|
238
234
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
235
|
+
def get_image_from_options(options)
|
236
|
+
image = if options[:image].nil? || !options[:image].is_a?(Applitools::Screenshot)
|
237
|
+
if options[:image].is_a? ChunkyPNG::Image
|
238
|
+
Applitools::Screenshot.from_image options[:image]
|
239
|
+
elsif !options[:image_path].nil? && !options[:image_path].empty?
|
240
|
+
Applitools::Screenshot.from_datastream ChunkyPNG::Datastream.from_file(options[:image_path]).to_s
|
241
|
+
elsif !options[:image_bytes].nil? && !options[:image_bytes].empty?
|
242
|
+
Applitools::Screenshot.from_datastream options[:image_bytes]
|
243
|
+
end
|
244
|
+
else
|
245
|
+
options[:image]
|
246
|
+
end
|
247
|
+
|
248
|
+
Applitools::ArgumentGuard.not_nil image, 'options[:image] can\'t be nil!'
|
249
|
+
|
250
|
+
image
|
251
|
+
end
|
256
252
|
end
|
257
253
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Applitools::Images
|
4
|
+
# @!visibility private
|
5
|
+
class EyesImagesScreenshot < ::Applitools::EyesScreenshot
|
6
|
+
SCREENSHOT_AS_IS = Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is].freeze
|
7
|
+
CONTEXT_RELATIVE = Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative].freeze
|
8
|
+
|
9
|
+
def initialize(image, options = {})
|
10
|
+
super image
|
11
|
+
return if (location = options[:location]).nil?
|
12
|
+
Applitools::ArgumentGuard.is_a? location, 'options[:location]', Applitools::Location
|
13
|
+
@bounds = Applitools::Region.new location.x, location.y, image.width, image.height
|
14
|
+
end
|
15
|
+
|
16
|
+
def convert_location(location, from, to)
|
17
|
+
Applitools::ArgumentGuard.not_nil location, 'location'
|
18
|
+
Applitools::ArgumentGuard.not_nil from, 'from'
|
19
|
+
Applitools::ArgumentGuard.not_nil to, 'to'
|
20
|
+
|
21
|
+
Applitools::ArgumentGuard.is_a? location, 'location', Applitools::Location
|
22
|
+
|
23
|
+
result = Applitools::Location.new location.x, location.y
|
24
|
+
return result if from == to
|
25
|
+
|
26
|
+
case from
|
27
|
+
when SCREENSHOT_AS_IS
|
28
|
+
raise "Coordinate type conversation error: #{from} -> #{to}" unless to == CONTEXT_RELATIVE
|
29
|
+
result.offset bounds
|
30
|
+
return result
|
31
|
+
when CONTEXT_RELATIVE
|
32
|
+
raise "Coordinate type conversation error: #{from} -> #{to}" unless to == SCREENSHOT_AS_IS
|
33
|
+
result.offset(Applitools::Location.new(-bounds.x, -bounds.y))
|
34
|
+
return result
|
35
|
+
else
|
36
|
+
raise "Coordinate type conversation error: #{from} -> #{to}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def intersected_region(region, from, to = CONTEXT_RELATIVE)
|
41
|
+
Applitools::ArgumentGuard.not_nil region, 'region'
|
42
|
+
Applitools::ArgumentGuard.not_nil from, 'coordinates Type (from)'
|
43
|
+
|
44
|
+
return Applitools::Region.new(0, 0, 0, 0) if region.empty?
|
45
|
+
|
46
|
+
intersected_region = convert_region_location region, from, to
|
47
|
+
intersected_region.intersect bounds
|
48
|
+
return intersected_region if intersected_region.empty?
|
49
|
+
|
50
|
+
intersected_region.location = convert_location intersected_region.location, to, from
|
51
|
+
intersected_region
|
52
|
+
end
|
53
|
+
|
54
|
+
def location_in_screenshot(location, coordinates_type)
|
55
|
+
Applitools::ArgumentGuard.not_nil location, 'location'
|
56
|
+
Applitools::ArgumentGuard.not_nil coordinates_type, 'coordinates_type'
|
57
|
+
location = convert_location(location, coordinates_type, CONTEXT_RELATIVE)
|
58
|
+
|
59
|
+
unless bounds.contains? location.left, location.top
|
60
|
+
raise Applitools::OutOfBoundsException.new "Location #{location} is not available in screenshot!"
|
61
|
+
end
|
62
|
+
|
63
|
+
convert_location location, CONTEXT_RELATIVE, SCREENSHOT_AS_IS
|
64
|
+
end
|
65
|
+
|
66
|
+
def sub_screenshot(region, coordinates_type, throw_if_clipped = false, force_nil_if_clipped = false)
|
67
|
+
Applitools::ArgumentGuard.not_nil region, 'region'
|
68
|
+
Applitools::ArgumentGuard.not_nil coordinates_type, 'coordinates_type'
|
69
|
+
|
70
|
+
sub_screen_region = intersected_region region, coordinates_type, SCREENSHOT_AS_IS
|
71
|
+
|
72
|
+
if sub_screen_region.empty? || (throw_if_clipped && !region.size_equals?(sub_screen_region))
|
73
|
+
return nil if force_nil_if_clipped
|
74
|
+
Applitools::OutOfBoundsException.new "Region #{sub_screen_region} (#{coordinates_type}) is out of " \
|
75
|
+
" screenshot bounds #{bounds}"
|
76
|
+
end
|
77
|
+
|
78
|
+
sub_screenshot_image = Applitools::Screenshot.from_any_image(
|
79
|
+
image.crop(
|
80
|
+
sub_screen_region.left, sub_screen_region.top, sub_screen_region.width, sub_screen_region.height
|
81
|
+
).to_datastream.to_blob
|
82
|
+
)
|
83
|
+
|
84
|
+
relative_sub_screenshot_region = convert_region_location(sub_screen_region, SCREENSHOT_AS_IS, CONTEXT_RELATIVE)
|
85
|
+
|
86
|
+
Applitools::Images::EyesImagesScreenshot.new sub_screenshot_image,
|
87
|
+
location: relative_sub_screenshot_region.location
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def bounds
|
93
|
+
@bounds ||= Applitools::Region.new(0, 0, image.width, image.height)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -6,20 +6,19 @@ module Applitools::Images
|
|
6
6
|
class << self
|
7
7
|
def path(path)
|
8
8
|
raise Applitools::EyesIllegalArgument unless File.exist?(path)
|
9
|
-
|
10
|
-
new(path)
|
9
|
+
new Applitools::Screenshot.from_image(ChunkyPNG::Image.from_file(path))
|
11
10
|
end
|
12
11
|
|
13
12
|
def blob(blob_image)
|
14
13
|
Applitools::ArgumentGuard.not_nil blob_image, 'blob_image'
|
15
14
|
Applitools::ArgumentGuard.is_a? blob_image, 'blob_image', String
|
16
|
-
new(blob_image)
|
15
|
+
new Applitools::Screenshot.from_datastream(blob_image)
|
17
16
|
end
|
18
17
|
|
19
18
|
def image(image)
|
20
19
|
Applitools::ArgumentGuard.not_nil image, 'image'
|
21
|
-
|
22
|
-
new(image)
|
20
|
+
Applitools::ArgumentGuard.is_a? image, 'image', ChunkyPNG::Image
|
21
|
+
new Applitools::Screenshot.from_image(image)
|
23
22
|
end
|
24
23
|
|
25
24
|
def screenshot(screenshot)
|
@@ -29,36 +28,28 @@ module Applitools::Images
|
|
29
28
|
end
|
30
29
|
|
31
30
|
def any(screenshot)
|
32
|
-
|
31
|
+
case screenshot
|
32
|
+
when Applitools::Screenshot
|
33
|
+
screenshot(screenshot)
|
34
|
+
when ChunkyPNG::Image
|
35
|
+
image(screenshot)
|
36
|
+
when String
|
37
|
+
begin
|
38
|
+
blob(screenshot)
|
39
|
+
rescue ChunkyPNG::SignatureMismatch
|
40
|
+
path(screenshot)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
raise Applitools::EyesIllegalArgument.new "Passed screenshot is not image type (#{screenshot.class})"
|
44
|
+
end
|
33
45
|
end
|
34
46
|
end
|
35
47
|
|
36
48
|
attr_accessor :image, :options, :ignored_regions, :region_to_check, :floating_regions, :accessibility_regions
|
37
49
|
|
38
|
-
def
|
39
|
-
if image_arg.is_a?(Applitools::Screenshot)
|
40
|
-
Base64.strict_encode64(image_arg.to_blob).force_encoding('UTF-8')
|
41
|
-
elsif image_arg.class.name === 'ChunkyPNG::Image'
|
42
|
-
Base64.strict_encode64(image_arg.to_blob).force_encoding('UTF-8')
|
43
|
-
elsif image_arg.is_a?(Hash) && !image_arg[:image_path].nil?
|
44
|
-
image_arg[:image_path]
|
45
|
-
elsif image_arg.is_a?(Hash) && !image_arg[:image].nil?
|
46
|
-
Base64.strict_encode64(image_arg[:image]).force_encoding('UTF-8')
|
47
|
-
elsif image_arg.is_a?(Hash)
|
48
|
-
raise Applitools::EyesIllegalArgument.new "Image is unrecognized, try to use image_path: path_or_url or image: buffer"
|
49
|
-
elsif image_arg.is_a?(String) && File.exist?(image_arg) # Path
|
50
|
-
image_arg
|
51
|
-
elsif image_arg.is_a?(String) # URL ? Buffer
|
52
|
-
raise Applitools::EyesIllegalArgument.new "Passed image is not explicit, try to use image_path: path_or_url or image: buffer"
|
53
|
-
else
|
54
|
-
raise Applitools::EyesIllegalArgument.new "Passed image is unrecognized"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def initialize(image_arg)
|
59
|
-
image = convert_image_arg(image_arg)
|
50
|
+
def initialize(image)
|
60
51
|
Applitools::ArgumentGuard.not_nil(image, 'image')
|
61
|
-
Applitools::ArgumentGuard.is_a? image, 'image',
|
52
|
+
Applitools::ArgumentGuard.is_a? image, 'image', Applitools::Screenshot
|
62
53
|
self.image = image
|
63
54
|
self.ignored_regions = []
|
64
55
|
self.floating_regions = []
|
@@ -69,67 +60,47 @@ module Applitools::Images
|
|
69
60
|
end
|
70
61
|
|
71
62
|
def ignore(*args)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
FloatingBounds.new(*last4).to_hash
|
82
|
-
else
|
83
|
-
{}
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def region_from_args(args)
|
88
|
-
options = Applitools::Utils.extract_options!(args)
|
89
|
-
padding = options && options[:padding]
|
90
|
-
requested_padding = get_requested_padding(padding, args)
|
91
|
-
value = convert_to_universal(args)
|
92
|
-
value = { type: args[0], selector: args[1] } if value.nil?
|
93
|
-
value = value[:selector] if value.is_a?(Hash) && (value[:type].to_s === 'id')
|
94
|
-
return nil if value === {selector: nil, type: nil}
|
95
|
-
region = { region: value }
|
96
|
-
region.merge!(padding: requested_padding) if requested_padding != {}
|
97
|
-
region.merge!(regionId: options[:region_id]) if options[:region_id]
|
98
|
-
region
|
99
|
-
end
|
100
|
-
|
101
|
-
def get_requested_padding(padding, args)
|
102
|
-
return padding.to_hash if padding && padding.is_a?(Applitools::PaddingBounds)
|
103
|
-
return padding if padding && (padding.is_a?(Hash) || padding.is_a?(Numeric))
|
104
|
-
if args.last.is_a? Applitools::PaddingBounds
|
105
|
-
args.pop
|
106
|
-
# elsif args.last.is_a?(Applitools::FloatingBounds)
|
107
|
-
# args.pop.to_hash
|
63
|
+
requested_padding = if args.last.is_a? Applitools::PaddingBounds
|
64
|
+
args.pop
|
65
|
+
else
|
66
|
+
Applitools::PaddingBounds::PIXEL_PADDING
|
67
|
+
end
|
68
|
+
region = args.shift
|
69
|
+
if region
|
70
|
+
Applitools::ArgumentGuard.is_a? region, 'region', Applitools::Region
|
71
|
+
ignored_regions << region.padding(requested_padding)
|
108
72
|
else
|
109
|
-
|
73
|
+
self.ignored_regions = []
|
110
74
|
end
|
75
|
+
self
|
111
76
|
end
|
112
77
|
|
113
78
|
def floating(*args)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
value =
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
79
|
+
requested_padding = if args.last.is_a? Applitools::PaddingBounds
|
80
|
+
args.pop
|
81
|
+
else
|
82
|
+
Applitools::PaddingBounds::PIXEL_PADDING
|
83
|
+
end
|
84
|
+
|
85
|
+
value = case args.first
|
86
|
+
when Applitools::FloatingRegion
|
87
|
+
proc { args.first.padding(requested_padding) }
|
88
|
+
when Applitools::Region
|
89
|
+
proc do
|
90
|
+
region = args.shift
|
91
|
+
Applitools::FloatingRegion.any(region, *args).padding(requested_padding)
|
92
|
+
end
|
93
|
+
else
|
94
|
+
self.floating_regions = []
|
95
|
+
end
|
96
|
+
floating_regions << value
|
126
97
|
self
|
127
98
|
end
|
128
99
|
|
129
100
|
def region(region = nil)
|
130
101
|
if region
|
131
102
|
Applitools::ArgumentGuard.is_a? region, 'region', Applitools::Region
|
132
|
-
self.region_to_check = region
|
103
|
+
self.region_to_check = region
|
133
104
|
else
|
134
105
|
self.region_to_check = nil
|
135
106
|
end
|
@@ -148,60 +119,5 @@ module Applitools::Images
|
|
148
119
|
Applitools::AccessibilityRegion.new(region, accessibility_region_type)
|
149
120
|
end
|
150
121
|
end
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
private # dupl
|
155
|
-
|
156
|
-
def is_element?(el)
|
157
|
-
el.is_a?(::Selenium::WebDriver::Element) || (el.is_a?(Applitools::Selenium::Element) && el.respond_to?(:ref))
|
158
|
-
end
|
159
|
-
|
160
|
-
def is_region?(region)
|
161
|
-
region.is_a?(Applitools::FloatingRegion) || region.is_a?(Applitools::Region) # || region.is_a?(Applitools::Selenium::Element)
|
162
|
-
end
|
163
|
-
|
164
|
-
def is_finder?(finders)
|
165
|
-
return false unless finders.is_a?(Array)
|
166
|
-
return false unless finders[1]
|
167
|
-
return true if [:uiautomator, :predicate, :accessibility_id].include?(finders[0].to_sym)
|
168
|
-
Applitools::Selenium::Driver::FINDERS.has_key?(finders[0].to_sym)
|
169
|
-
end
|
170
|
-
|
171
|
-
def convert_to_universal(args)
|
172
|
-
if is_element?(args.first)
|
173
|
-
ref = args.first.ref
|
174
|
-
ref = args.first.ref[1] if ref.is_a?(Array) && ref[0] === :element
|
175
|
-
return { elementId: ref }
|
176
|
-
end
|
177
|
-
return args.first.to_hash if is_region?(args.first)
|
178
|
-
if is_finder?(args)
|
179
|
-
if Applitools::Selenium::Driver::FINDERS.has_key?(args[0])
|
180
|
-
selector = args[1]
|
181
|
-
selector = "##{args[1]}" if args[0] === :id && !args[1].start_with?('#') && instance_of?(Applitools::Selenium::Target)
|
182
|
-
return {type: Applitools::Selenium::Driver::FINDERS[args[0]], selector: selector}
|
183
|
-
end
|
184
|
-
case args[0]
|
185
|
-
when :uiautomator # ANDROID_UI_AUTOMATOR: '-android uiautomator'
|
186
|
-
return {type: '-android uiautomator', selector: args[1]}
|
187
|
-
when :predicate # IOS_PREDICATE: '-ios predicate string',
|
188
|
-
return {type: '-ios predicate string', selector: args[1]}
|
189
|
-
when :accessibility_id
|
190
|
-
return {type: 'accessibility id', selector: args[1]}
|
191
|
-
end
|
192
|
-
end
|
193
|
-
if args.first.is_a?(String)
|
194
|
-
return proc { |driver| driver.find_element(name_or_id: args.first) }
|
195
|
-
end
|
196
|
-
if args.first.is_a?(Hash) && args.first.has_key?('selector')
|
197
|
-
if args.first.has_key?('shadow')
|
198
|
-
return {selector: args.first['selector'], shadow: args.first['shadow']}
|
199
|
-
else
|
200
|
-
return {selector: args.first['selector']}
|
201
|
-
end
|
202
|
-
end
|
203
|
-
nil
|
204
|
-
end
|
205
|
-
|
206
122
|
end
|
207
123
|
end
|
data/lib/applitools/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eyes_images
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Applitools Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: eyes_core
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 4.
|
19
|
+
version: 4.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 4.
|
26
|
+
version: 4.0.0
|
27
27
|
description: Provides Images SDK for Applitools tests.
|
28
28
|
email:
|
29
29
|
- team@applitools.com
|
@@ -32,6 +32,7 @@ extensions: []
|
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
34
|
- lib/applitools/images/eyes.rb
|
35
|
+
- lib/applitools/images/eyes_images_screenshot.rb
|
35
36
|
- lib/applitools/images/target.rb
|
36
37
|
- lib/applitools/version.rb
|
37
38
|
- lib/eyes_images.rb
|
@@ -51,11 +52,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
52
|
version: '0'
|
52
53
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
54
|
requirements:
|
54
|
-
- - "
|
55
|
+
- - ">="
|
55
56
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
57
|
+
version: '0'
|
57
58
|
requirements: []
|
58
|
-
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 2.6.14.3
|
59
61
|
signing_key:
|
60
62
|
specification_version: 4
|
61
63
|
summary: Applitools Ruby Images SDK
|